CvUnitAI.cpp 868 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320
  1. // unitAI.cpp
  2. #include "CvGameCoreDLL.h"
  3. #include "CvUnitAI.h"
  4. #include "CvMap.h"
  5. #include "CvArea.h"
  6. #include "CvPlot.h"
  7. #include "CvGlobals.h"
  8. #include "CvGameAI.h"
  9. #include "CvTeamAI.h"
  10. #include "CvPlayerAI.h"
  11. #include "CvGameCoreUtils.h"
  12. #include "CvRandom.h"
  13. #include "CyUnit.h"
  14. #include "CyArgsList.h"
  15. #include "CvDLLPythonIFaceBase.h"
  16. #include "CvInfos.h"
  17. #include "FProfiler.h"
  18. #include "FAStarNode.h"
  19. // interface uses
  20. #include "CvDLLInterfaceIFaceBase.h"
  21. #include "CvDLLFAStarIFaceBase.h"
  22. /************************************************************************************************/
  23. /* BETTER_BTS_AI_MOD 10/02/09 jdog5000 */
  24. /* */
  25. /* AI logging */
  26. /************************************************************************************************/
  27. #include "BetterBTSAI.h"
  28. /************************************************************************************************/
  29. /* BETTER_BTS_AI_MOD END */
  30. /************************************************************************************************/
  31. #define FOUND_RANGE (7)
  32. // Public Functions...
  33. CvUnitAI::CvUnitAI()
  34. {
  35. AI_reset();
  36. }
  37. CvUnitAI::~CvUnitAI()
  38. {
  39. AI_uninit();
  40. }
  41. void CvUnitAI::AI_init(UnitAITypes eUnitAI)
  42. {
  43. AI_reset(eUnitAI);
  44. //--------------------------------
  45. // Init other game data
  46. AI_setBirthmark(GC.getGameINLINE().getSorenRandNum(10000, "AI Unit Birthmark"));
  47. AI_setBirthmark2(GC.getGameINLINE().getSorenRandNum(10000, "AI Unit Birthmark"));
  48. AI_setBirthmark3(GC.getGameINLINE().getSorenRandNum(10000, "AI Unit Birthmark"));
  49. FAssertMsg(AI_getUnitAIType() != NO_UNITAI, "AI_getUnitAIType() is not expected to be equal with NO_UNITAI");
  50. area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), 1);
  51. GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), 1);
  52. }
  53. void CvUnitAI::AI_uninit()
  54. {
  55. }
  56. void CvUnitAI::AI_reset(UnitAITypes eUnitAI)
  57. {
  58. AI_uninit();
  59. m_iBirthmark = 0;
  60. /*************************************************************************************************/
  61. /** BETTER AI (New Functions Definition) Sephi **/
  62. /*************************************************************************************************/
  63. m_iGroupflag=GROUPFLAG_NONE;
  64. m_bSuicideSummon=false;
  65. m_bPermanentSummon=false;
  66. m_bAllowedPermDefense=true;
  67. /*************************************************************************************************/
  68. /** END **/
  69. /*************************************************************************************************/
  70. if (eUnitAI != NO_UNITAI)
  71. {
  72. if (!GC.getUnitInfo(getUnitType()).getUnitAIType(eUnitAI))
  73. {
  74. eUnitAI = (UnitAITypes)GC.getUnitInfo(getUnitType()).getDefaultUnitAIType();
  75. }
  76. }
  77. m_eUnitAIType = eUnitAI;
  78. m_iAutomatedAbortTurn = -1;
  79. }
  80. // AI_update returns true when we should abort the loop and wait until next slice
  81. bool CvUnitAI::AI_update()
  82. {
  83. PROFILE_FUNC();
  84. CvUnit* pTransportUnit;
  85. //FAssertMsg(canMove(), "canMove is expected to be true"); // lfgr 03/2021: Also allow calling this when unit can only cast
  86. FAssertMsg(isGroupHead(), "isGroupHead is expected to be true"); // XXX is this a good idea???
  87. // allow python to handle it for certain barbarians
  88. if (isBarbarian())
  89. {
  90. CyUnit* pyUnit = new CyUnit(this);
  91. CyArgsList argsList;
  92. argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit)); // pass in unit class
  93. long lResult=0;
  94. gDLL->getPythonIFace()->callFunction(PYGameModule, "AI_unitUpdate", argsList.makeFunctionArgs(), &lResult);
  95. delete pyUnit; // python fxn must not hold on to this pointer
  96. if (lResult == 1)
  97. {
  98. return false;
  99. }
  100. }
  101. //FfH: End Modify
  102. // Various FFH AI functions - lots of HARDCODE
  103. // TODO: make this section better
  104. if (!GET_PLAYER(getOwnerINLINE()).isHuman())
  105. {
  106. // Tholal AI - Shades
  107. if (getUnitClassType() == GC.getInfoTypeForString("UNITCLASS_SHADE"))
  108. {
  109. AI_ShadeMove();
  110. }
  111. // Bring out the comfy chair!
  112. if (GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_RELIGION2))
  113. {
  114. if (isInquisitor())
  115. {
  116. AI_InquisitionMove();
  117. }
  118. }
  119. // Vampire stuff. Eating local pop, assignment of AI_FEASTING
  120. if (isVampire() && getGroup()->getNumUnits() == 1)
  121. {
  122. AI_feastingmove();
  123. }
  124. // End Tholal AI
  125. /** BETTER AI Sephi (Time for the Mages to Caste Haste, etc.) **/
  126. /*
  127. CLLNode<IDInfo>* pEntityNode = getGroup()->headUnitNode();
  128. CvUnit* pLoopUnit;
  129. while (pEntityNode != NULL)
  130. {
  131. pLoopUnit = ::getUnit(pEntityNode->m_data);
  132. pEntityNode = getGroup()->nextUnitNode(pEntityNode);
  133. if (pLoopUnit->isMovementCaster())
  134. {
  135. pLoopUnit->AI_MovementCast();
  136. }
  137. }
  138. */
  139. }
  140. /*************************************************************************************************/
  141. /** END **/
  142. /*************************************************************************************************/
  143. if (getDomainType() == DOMAIN_LAND)
  144. {
  145. if (plot()->isWater() && !canMoveAllTerrain())
  146. {
  147. getGroup()->pushMission(MISSION_SKIP);
  148. return false;
  149. }
  150. else
  151. {
  152. pTransportUnit = getTransportUnit();
  153. if (pTransportUnit != NULL)
  154. {
  155. if (pTransportUnit->getGroup()->hasMoved() || (pTransportUnit->getGroup()->headMissionQueueNode() != NULL))
  156. {
  157. getGroup()->pushMission(MISSION_SKIP);
  158. return false;
  159. }
  160. }
  161. }
  162. }
  163. if (AI_afterAttack())
  164. {
  165. return false;
  166. }
  167. //FfH: Added by Kael 10/26/2008
  168. if (!isBarbarian())
  169. {
  170. if (getLevel() < (isAnimal() ? 6 : 3))
  171. {
  172. bool bDoesBuild = false;
  173. for (int iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
  174. {
  175. BuildingTypes eBuilding = (BuildingTypes)GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iI);
  176. if (NO_BUILDING != eBuilding)
  177. {
  178. if ((m_pUnitInfo->getForceBuildings(eBuilding)) || (m_pUnitInfo->getBuildings(eBuilding)))// LFGR_TODO: This can be cached
  179. {
  180. /*
  181. if (canConstruct(plot(),eBuilding))
  182. {
  183. construct(eBuilding);
  184. return false;
  185. }
  186. */
  187. bDoesBuild = true;
  188. }
  189. }
  190. }
  191. if (bDoesBuild)
  192. {
  193. if (AI_construct())
  194. {
  195. return false;
  196. }
  197. }
  198. }
  199. }
  200. /*************************************************************************************************/
  201. /** BUGFIX (also AI Units can become Enraged) Sephi **/
  202. /** **/
  203. /** **/
  204. /*************************************************************************************************/
  205. /** FFH code
  206. if (isHuman())
  207. {
  208. if (getGroup()->getHeadUnit()->isAIControl())
  209. {
  210. if (AI_anyAttack(3, 20))
  211. {
  212. return true;
  213. }
  214. AI_barbAttackMove();
  215. }
  216. }
  217. **/
  218. if(isAIControl())
  219. {
  220. /*
  221. if (getGroup()->getNumUnits()>1)
  222. {
  223. joinGroup(NULL);
  224. return true;
  225. }
  226. */
  227. // Fix from Snarko - Merged by Tholal on 6/15/10
  228. if (getGroup()->getNumUnits()>1)
  229. {
  230. CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
  231. CvUnit* pLoopUnit;
  232. while (pUnitNode != NULL)
  233. {
  234. pLoopUnit = ::getUnit(pUnitNode->m_data);
  235. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  236. if (!pLoopUnit->isAIControl())
  237. {
  238. joinGroup(NULL);
  239. return true;
  240. }
  241. }
  242. }
  243. // End Tholal Merge
  244. //remove AI control from Defensive only Units
  245. if(isOnlyDefensive()) // lfgr fix 03/2021: else if -> if, due to Snarko's fix above
  246. {
  247. changeAIControl(-1);
  248. getGroup()->pushMission(MISSION_SKIP);
  249. return false;
  250. }
  251. else if(isAIControl())
  252. {
  253. if (canMove() && canAttack()) // lfgr 11/2022: Fix for defensive-only units
  254. {
  255. if (AI_anyAttack(getMoves(), 0))
  256. {
  257. return false;
  258. }
  259. if (AI_anyAttack(3, 0))
  260. {
  261. return false;
  262. }
  263. if (AI_anyAttack(10, 0))
  264. {
  265. return false;
  266. }
  267. if (AI_anyAttack(30, 0))
  268. {
  269. return false;
  270. }
  271. }
  272. getGroup()->pushMission(MISSION_SKIP);
  273. return false;
  274. }
  275. }
  276. /*************************************************************************************************/
  277. /** END **/
  278. /*************************************************************************************************/
  279. //FfH: End Add
  280. if (getGroup()->isAutomated())
  281. {
  282. switch (getGroup()->getAutomateType())
  283. {
  284. case AUTOMATE_BUILD:
  285. if (AI_getUnitAIType() == UNITAI_WORKER)
  286. {
  287. AI_workerMove();
  288. }
  289. else if (AI_getUnitAIType() == UNITAI_WORKER_SEA)
  290. {
  291. AI_workerSeaMove();
  292. }
  293. else
  294. {
  295. FAssert(false);
  296. }
  297. break;
  298. case AUTOMATE_NETWORK:
  299. AI_networkAutomated();
  300. // XXX else wake up???
  301. break;
  302. case AUTOMATE_CITY:
  303. AI_cityAutomated();
  304. // XXX else wake up???
  305. break;
  306. case AUTOMATE_EXPLORE:
  307. switch (getDomainType())
  308. {
  309. case DOMAIN_SEA:
  310. AI_exploreSeaMove();
  311. break;
  312. case DOMAIN_AIR:
  313. // if we are cargo (on a carrier), hold if the carrier is not done moving yet
  314. pTransportUnit = getTransportUnit();
  315. if (pTransportUnit != NULL)
  316. {
  317. if (pTransportUnit->isAutomated() && pTransportUnit->canMove() && pTransportUnit->getGroup()->getActivityType() != ACTIVITY_HOLD)
  318. {
  319. getGroup()->pushMission(MISSION_SKIP);
  320. break;
  321. }
  322. }
  323. /************************************************************************************************/
  324. /* BETTER_BTS_AI_MOD 01/12/09 jdog5000 */
  325. /* */
  326. /* Player Interface */
  327. /************************************************************************************************/
  328. // Have air units explore like AI units do
  329. AI_exploreAir();
  330. /************************************************************************************************/
  331. /* BETTER_BTS_AI_MOD END */
  332. /************************************************************************************************/
  333. break;
  334. case DOMAIN_LAND:
  335. AI_exploreMove();
  336. break;
  337. default:
  338. FAssert(false);
  339. break;
  340. }
  341. // if we have air cargo (we are a carrier), and we done moving, explore with the aircraft as well
  342. if (hasCargo() && domainCargo() == DOMAIN_AIR && (!canMove() || getGroup()->getActivityType() == ACTIVITY_HOLD))
  343. {
  344. std::vector<CvUnit*> aCargoUnits;
  345. getCargoUnits(aCargoUnits);
  346. for (uint i = 0; i < aCargoUnits.size() && isAutomated(); ++i)
  347. {
  348. CvUnit* pCargoUnit = aCargoUnits[i];
  349. if (pCargoUnit->getDomainType() == DOMAIN_AIR)
  350. {
  351. if (pCargoUnit->canMove())
  352. {
  353. pCargoUnit->getGroup()->setAutomateType(AUTOMATE_EXPLORE);
  354. pCargoUnit->getGroup()->setActivityType(ACTIVITY_AWAKE);
  355. }
  356. }
  357. }
  358. }
  359. break;
  360. case AUTOMATE_RELIGION:
  361. if (AI_getUnitAIType() == UNITAI_MISSIONARY)
  362. {
  363. AI_missionaryMove();
  364. }
  365. break;
  366. // Start Sephi Code - Automatic Terraforming
  367. case AUTOMATE_TERRAFORMING:
  368. if( AI_getUnitAIType() != UNITAI_TERRAFORMER )
  369. {
  370. AI_setUnitAIType(UNITAI_TERRAFORMER); // lfgr comment: This kicks us out of our group and resets our AutomateType!
  371. getGroup()->setAutomateType( AUTOMATE_TERRAFORMING ); // lfgr fix 03/2021
  372. }
  373. AI_terraformerMove();
  374. break;
  375. // End Sephi Code
  376. default: // lfgr comment: isAIControl() makes isAutomated() true without actually having to have an automate type.
  377. FAssertMsg( isAIControl(), CvString::format( "Unknown automate type: %d", getGroup()->getAutomateType() ).c_str() );
  378. break;
  379. }
  380. // if no longer automated, then we want to bail
  381. //return !getGroup()->isAutomated();
  382. }
  383. else
  384. {
  385. /*************************************************************************************************/
  386. /** BETTER AI (UnitAI::AI_update) Sephi **/
  387. /*************************************************************************************************/
  388. // Tholal ToDo - this section is kind of hacky. Figure out a way to remove it entirely and move the functionality to appropriate spots
  389. if (!isBarbarian())
  390. {
  391. if (getExperience() > 99)
  392. {
  393. if (AI_getUnitAIType() != UNITAI_HERO)
  394. {
  395. AI_setUnitAIType(UNITAI_HERO);
  396. AI_setGroupflag(GROUPFLAG_CONQUEST);
  397. }
  398. }
  399. // Tholal AI - temp hack for adepts that get wrong AI type
  400. if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
  401. {
  402. switch (AI_getUnitAIType())
  403. {
  404. case UNITAI_WARWIZARD:
  405. case UNITAI_MANA_UPGRADE:
  406. case UNITAI_TERRAFORMER:
  407. case UNITAI_MAGE:
  408. case UNITAI_HERO:
  409. break;
  410. case UNITAI_FEASTING:
  411. if (isVampire())
  412. {
  413. break;
  414. }
  415. case UNITAI_INQUISITOR:
  416. if (isInquisitor())
  417. {
  418. break;
  419. }
  420. default:
  421. if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_MANA_UPGRADE) == 0)
  422. {
  423. AI_setUnitAIType(UNITAI_MANA_UPGRADE);
  424. AI_setGroupflag(GROUPFLAG_NONE);
  425. break;
  426. }
  427. if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_TERRAFORMER) == 0 && isTerraformer())
  428. {
  429. AI_setUnitAIType(UNITAI_TERRAFORMER);
  430. AI_setGroupflag(GROUPFLAG_NONE);
  431. break;
  432. }
  433. if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_MAGE) < GET_PLAYER(getOwnerINLINE()).getNumCities())
  434. {
  435. AI_setUnitAIType(UNITAI_MAGE);
  436. AI_setGroupflag(GROUPFLAG_PERMDEFENSE);
  437. break;
  438. }
  439. AI_setUnitAIType(UNITAI_WARWIZARD);
  440. AI_setGroupflag(GROUPFLAG_CONQUEST);
  441. break;
  442. }
  443. }
  444. // Tholal AI - catch for units who have casted already this turn and now can't move
  445. // lfgr 04/2021: Allow certain AI functions to be called when we can still cast, but not move anymore
  446. if (!AI_readyToMoveOrCast())
  447. {
  448. return false;
  449. }
  450. switch (AI_getGroupflag())
  451. {
  452. case GROUPFLAG_HNGROUP:
  453. AI_HiddenNationalityMove();
  454. return false;
  455. break;
  456. case GROUPFLAG_SUICIDE_SUMMON:
  457. AI_summonAttackMove();
  458. return false;
  459. break;
  460. case GROUPFLAG_SVARTALFAR_KIDNAP:
  461. AI_SvartalfarKidnapMove();
  462. return false;
  463. break;
  464. case GROUPFLAG_CONQUEST:
  465. AI_ConquestMove();
  466. return false;
  467. break;
  468. case GROUPFLAG_PERMDEFENSE:
  469. AI_cityDefenseMove();
  470. return false;
  471. break;
  472. case GROUPFLAG_PATROL:
  473. AI_PatrolMove();
  474. return false;
  475. break;
  476. case GROUPFLAG_HERO:
  477. AI_heromove();
  478. return false;
  479. break;
  480. default:
  481. break;
  482. }
  483. if (isSuicideSummon())
  484. {
  485. AI_summonAttackMove();
  486. setSuicideSummon(false);
  487. return false;
  488. }
  489. }
  490. /*************************************************************************************************/
  491. /** END **/
  492. /*************************************************************************************************/
  493. // Tholal AI - make sure we dont try to move if we can't (ie, due to spell/ability usage earlier in this function)
  494. // lfgr 04/2021: Allow certain AI functions to be called when we can still cast, but not move anymore
  495. if (AI_readyToMoveOrCast())
  496. {
  497. switch (AI_getUnitAIType())
  498. {
  499. case UNITAI_UNKNOWN:
  500. getGroup()->pushMission(MISSION_SKIP);
  501. break;
  502. case UNITAI_ANIMAL:
  503. AI_animalMove();
  504. break;
  505. case UNITAI_SETTLE:
  506. AI_settleMove();
  507. break;
  508. case UNITAI_WORKER:
  509. AI_workerMove();
  510. break;
  511. case UNITAI_ATTACK:
  512. //Added by Kael 09/19/2007
  513. if (getDuration() > 0)
  514. {
  515. AI_summonAttackMove();
  516. break;
  517. }
  518. //FfH: End Add
  519. if (isBarbarian())
  520. {
  521. AI_barbAttackMove();
  522. }
  523. else
  524. {
  525. AI_attackMove();
  526. }
  527. break;
  528. /*************************************************************************************************/
  529. /** BETTER AI (New UNITAI) Sephi **/
  530. /** **/
  531. /** **/
  532. /*************************************************************************************************/
  533. case UNITAI_HERO:
  534. if (isBarbarian())
  535. {
  536. AI_barbAttackMove();
  537. }
  538. else
  539. {
  540. AI_heromove();
  541. }
  542. break;
  543. case UNITAI_INQUISITOR:
  544. AI_InquisitionMove();
  545. break;
  546. case UNITAI_FEASTING:
  547. AI_feastingmove();
  548. break;
  549. case UNITAI_MANA_UPGRADE:
  550. AI_upgrademanaMove();
  551. break;
  552. case UNITAI_MAGE:
  553. //AI_mageMove();
  554. AI_cityDefenseMove();
  555. break;
  556. case UNITAI_WARWIZARD:
  557. AI_ConquestMove();
  558. break;
  559. case UNITAI_TERRAFORMER:
  560. AI_terraformerMove();
  561. break;
  562. case UNITAI_ATTACK_CITY:
  563. if (isBarbarian())
  564. {
  565. AI_barbAttackMove();
  566. }
  567. else
  568. {
  569. AI_attackCityMove();
  570. }
  571. break;
  572. /*************************************************************************************************/
  573. /** END **/
  574. /*************************************************************************************************/
  575. case UNITAI_COLLATERAL:
  576. AI_collateralMove();
  577. break;
  578. case UNITAI_PILLAGE:
  579. AI_pillageMove();
  580. break;
  581. case UNITAI_RESERVE:
  582. AI_reserveMove();
  583. break;
  584. case UNITAI_MEDIC:
  585. case UNITAI_COUNTER:
  586. AI_counterMove();
  587. break;
  588. case UNITAI_PARADROP:
  589. AI_paratrooperMove();
  590. break;
  591. case UNITAI_CITY_DEFENSE:
  592. AI_cityDefenseMove();
  593. break;
  594. case UNITAI_CITY_COUNTER:
  595. case UNITAI_CITY_SPECIAL:
  596. AI_cityDefenseExtraMove();
  597. break;
  598. case UNITAI_EXPLORE:
  599. AI_exploreMove();
  600. break;
  601. case UNITAI_MISSIONARY:
  602. AI_missionaryMove();
  603. break;
  604. case UNITAI_PROPHET:
  605. AI_prophetMove();
  606. break;
  607. case UNITAI_ARTIST:
  608. AI_artistMove();
  609. break;
  610. case UNITAI_SCIENTIST:
  611. AI_scientistMove();
  612. break;
  613. case UNITAI_GENERAL:
  614. AI_generalMove();
  615. break;
  616. case UNITAI_MERCHANT:
  617. AI_merchantMove();
  618. break;
  619. case UNITAI_ENGINEER:
  620. AI_engineerMove();
  621. break;
  622. case UNITAI_SPY:
  623. AI_spyMove();
  624. break;
  625. case UNITAI_ICBM:
  626. AI_ICBMMove();
  627. break;
  628. case UNITAI_WORKER_SEA:
  629. AI_workerSeaMove();
  630. break;
  631. case UNITAI_ATTACK_SEA:
  632. if (isBarbarian())
  633. {
  634. AI_barbAttackSeaMove();
  635. }
  636. else
  637. {
  638. AI_attackSeaMove();
  639. }
  640. break;
  641. case UNITAI_RESERVE_SEA:
  642. AI_reserveSeaMove();
  643. break;
  644. case UNITAI_ESCORT_SEA:
  645. AI_escortSeaMove();
  646. break;
  647. case UNITAI_EXPLORE_SEA:
  648. AI_exploreSeaMove();
  649. break;
  650. case UNITAI_ASSAULT_SEA:
  651. AI_assaultSeaMove();
  652. break;
  653. case UNITAI_SETTLER_SEA:
  654. AI_settlerSeaMove();
  655. break;
  656. case UNITAI_MISSIONARY_SEA:
  657. AI_missionarySeaMove();
  658. break;
  659. case UNITAI_SPY_SEA:
  660. AI_spySeaMove();
  661. break;
  662. case UNITAI_CARRIER_SEA:
  663. AI_carrierSeaMove();
  664. break;
  665. case UNITAI_MISSILE_CARRIER_SEA:
  666. AI_missileCarrierSeaMove();
  667. break;
  668. case UNITAI_PIRATE_SEA:
  669. AI_pirateSeaMove();
  670. break;
  671. case UNITAI_ATTACK_AIR:
  672. AI_attackAirMove();
  673. break;
  674. case UNITAI_DEFENSE_AIR:
  675. AI_defenseAirMove();
  676. break;
  677. case UNITAI_CARRIER_AIR:
  678. AI_carrierAirMove();
  679. break;
  680. case UNITAI_MISSILE_AIR:
  681. AI_missileAirMove();
  682. break;
  683. case UNITAI_ATTACK_CITY_LEMMING:
  684. AI_attackCityLemmingMove();
  685. break;
  686. case UNITAI_LAIRGUARDIAN:
  687. AI_lairGuardianMove();
  688. break;
  689. case UNITAI_SHADE:
  690. AI_ShadeMove();
  691. break;
  692. default:
  693. FAssert(false);
  694. break;
  695. }
  696. }
  697. }
  698. return false;
  699. }
  700. // Returns true if took an action or should wait to move later...
  701. // K-Mod. I've basically rewriten this function.
  702. // bFirst should be "true" if this is the first unit in the group to use this follow function.
  703. // the point is that there are some calculations and checks in here which only depend on the group, not the unit
  704. // so for efficiency, we should only check them once.
  705. bool CvUnitAI::AI_follow(bool bFirst)
  706. {
  707. FAssert(getDomainType() != DOMAIN_AIR);
  708. if (AI_followBombard())
  709. return true;
  710. if (bFirst && getGroup()->getHeadUnitAI() == UNITAI_ATTACK_CITY)
  711. {
  712. // note: AI_stackAttackCity will check which of our units can attack when comparing stacks;
  713. // and it will issue the attack order using MOVE_DIRECT ATTACK, which will execute without waiting for the entire group to have movement points.
  714. if (AI_stackAttackCity(1, 160, true)) // automatic threshold
  715. return true;
  716. }
  717. // I've changed attack-follow code so that it will only attack with a single unit, not the whole group.
  718. if (bFirst && AI_cityAttack(1, 65, true))
  719. return true;
  720. if (bFirst)
  721. {
  722. bool bMoveGroup = false; // to large groups to leave some units behind.
  723. if (getGroup()->getNumUnits() >= 16)
  724. {
  725. int iCanMove = 0;
  726. CLLNode<IDInfo>* pEntityNode = getGroup()->headUnitNode();
  727. while (pEntityNode)
  728. {
  729. CvUnit* pLoopUnit = ::getUnit(pEntityNode->m_data);
  730. pEntityNode = getGroup()->nextUnitNode(pEntityNode);
  731. iCanMove += (pLoopUnit->canMove() ? 1 : 0);
  732. }
  733. bMoveGroup = 5 * iCanMove >= 4 * getGroup()->getNumUnits() || iCanMove >= 20; // if 4/5 of our group can still move.
  734. }
  735. if (AI_anyAttack(1, isEnemy(plot()->getTeam()) ? 65 : 70, bMoveGroup ? 0 : 2, true, true))
  736. return true;
  737. }
  738. //
  739. if (isEnemy(plot()->getTeam()))
  740. {
  741. if (canPillage(plot()))
  742. {
  743. getGroup()->pushMission(MISSION_PILLAGE);
  744. return true;
  745. }
  746. }
  747. if (isFound())
  748. {
  749. if (area()->getBestFoundValue(getOwnerINLINE()) > 0)
  750. {
  751. if (AI_foundRange(FOUND_RANGE, true))
  752. {
  753. return true;
  754. }
  755. }
  756. }
  757. return false;
  758. }
  759. // K-Mod. This function has been completely rewritten to improve efficiency and intelligence.
  760. void CvUnitAI::AI_upgrade()
  761. {
  762. PROFILE_FUNC();
  763. FAssert(!isHuman());
  764. FAssert(AI_getUnitAIType() != NO_UNITAI);
  765. if (!isReadyForUpgrade())
  766. return;
  767. const CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  768. const CvCivilizationInfo& kCivInfo = GC.getCivilizationInfo(kPlayer.getCivilizationType());
  769. UnitAITypes eUnitAI = AI_getUnitAIType();
  770. CvArea* pArea = area();
  771. int iBestValue = kPlayer.AI_unitValue(getUnitType(), eUnitAI, pArea, true) * 100;
  772. UnitTypes eBestUnit = NO_UNIT;
  773. // LFGR_TODO: A new function CvUnit::canEverUpgrade(UnitTypes) could help here. Caching a list of possible upgrades for each UnitType could also make sense.
  774. // Note: the original code did two passes, presumably for speed reasons.
  775. // In the first pass, they checked only units which were flagged with the right unitAI.
  776. // Then, only if no such units were found, they checked all other units.
  777. //
  778. // I'm just jumping straight to the second (slower) pass, because most of the time no upgrades are available at all and so both passes would be used anyway.
  779. //
  780. // I've reversed the order of iteration because the stronger units are typically later in the list
  781. for (UnitClassTypes i = (UnitClassTypes)(GC.getNumUnitClassInfos()-1); i >= 0; i=(UnitClassTypes)(i-1))
  782. {
  783. UnitTypes eLoopUnit = (UnitTypes)kCivInfo.getCivilizationUnits(i);
  784. if (eLoopUnit != NO_UNIT)
  785. {
  786. int iValue = kPlayer.AI_unitValue(eLoopUnit, eUnitAI, pArea, true);
  787. // use a random factor. less than 100, so that the upgrade must be better than the current unit.
  788. iValue *= 80 + GC.getGameINLINE().getSorenRandNum(21, "AI Upgrade");
  789. // (believe it or not, AI_unitValue is faster than canUpgrade.)
  790. if (iValue > iBestValue && canUpgrade(eLoopUnit))
  791. {
  792. iBestValue = iValue;
  793. eBestUnit = eLoopUnit;
  794. }
  795. }
  796. }
  797. if (eBestUnit != NO_UNIT)
  798. {
  799. logBBAI(" %S (unit %d - %S, level %d) upgrading to %S (value: %d)", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription(), getLevel(), GC.getUnitInfo(eBestUnit).getDescription(), iBestValue);
  800. //upgrade(eBestUnit);
  801. // K-Mod. Ungroup the unit, so that we don't cause the whole group to miss their turn.
  802. CvUnit* pUpgradeUnit = upgrade(eBestUnit);
  803. doDelayedDeath();
  804. if (pUpgradeUnit != this)
  805. {
  806. CvSelectionGroup* pGroup = pUpgradeUnit->getGroup();
  807. if (pGroup->getHeadUnit() != pUpgradeUnit)
  808. {
  809. pUpgradeUnit->joinGroup(NULL);
  810. // indicate that the unit intends to rejoin the old group (although it might not actually do so...)
  811. pUpgradeUnit->getGroup()->AI_setMissionAI(MISSIONAI_GROUP, 0, pGroup->getHeadUnit());
  812. }
  813. }
  814. }
  815. }
  816. void CvUnitAI::AI_promote()
  817. {
  818. PROFILE_FUNC();
  819. // K-Mod. A quick check to see if we can rule out all promotions in one hit, before we go through them one by one.
  820. if (!isPromotionReady())
  821. return; // can't get any normal promotions. (see CvUnit::canPromote)
  822. // K-Mod end
  823. if( gPromoteLogLevel >= 1 )
  824. {
  825. logBBAI(" %S (unit %d - %S) looking for best promotion...", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription() );
  826. }
  827. int iBestValue = 0;
  828. PromotionTypes eBestPromotion = NO_PROMOTION;
  829. for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
  830. {
  831. if (canPromote((PromotionTypes)iI, -1))
  832. {
  833. int iValue = AI_promotionValue((PromotionTypes)iI);
  834. if( gPromoteLogLevel >= 1 && iValue > 0 )
  835. {
  836. logBBAI(" %S has value %d", GC.getPromotionInfo( (PromotionTypes)iI ).getDescription(), iValue );
  837. }
  838. if (iValue > iBestValue)
  839. {
  840. iBestValue = iValue;
  841. eBestPromotion = ((PromotionTypes)iI);
  842. }
  843. }
  844. }
  845. if (eBestPromotion != NO_PROMOTION)
  846. {
  847. if( gUnitLogLevel >= 3 )
  848. {
  849. logBBAI(" %S (unit %d - %S) choosing promotion %S (value: %d)", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription(), GC.getPromotionInfo(eBestPromotion).getDescription(), iBestValue);
  850. }
  851. promote(eBestPromotion, -1);
  852. AI_promote();
  853. }
  854. }
  855. int CvUnitAI::AI_groupFirstVal()
  856. {
  857. if (isBarbarian() && AI_getUnitAIType() != UNITAI_HERO)
  858. {
  859. return (AI_getBarbLeadership());
  860. }
  861. /*************************************************************************************************/
  862. /** BETTER AI (improved logic which unit becomes head of a group) Sephi **/
  863. /** **/
  864. /** **/
  865. /*************************************************************************************************/
  866. if (getDuration()>0)
  867. {
  868. return 1;
  869. }
  870. /*
  871. if (AI_getGroupflag()==GROUPFLAG_CONQUEST)
  872. {
  873. return 25;
  874. }
  875. */
  876. /*************************************************************************************************/
  877. /** END **/
  878. /*************************************************************************************************/
  879. switch (AI_getUnitAIType())
  880. {
  881. case UNITAI_UNKNOWN:
  882. case UNITAI_ANIMAL:
  883. //FAssert(false);
  884. return 1;
  885. break;
  886. case UNITAI_SETTLE:
  887. return 21;
  888. break;
  889. case UNITAI_WORKER:
  890. return 20;
  891. break;
  892. case UNITAI_ATTACK:
  893. if (collateralDamage() > 0)
  894. {
  895. return 17;
  896. }
  897. else if (withdrawalProbability() > 0)
  898. {
  899. return 15;
  900. }
  901. else if (!m_pUnitInfo->isPillage())
  902. {
  903. return 10;
  904. }
  905. else
  906. {
  907. return 13;
  908. }
  909. break;
  910. case UNITAI_ATTACK_CITY:
  911. if (bombardRate() > 0)
  912. {
  913. return 19;
  914. }
  915. else if (collateralDamage() > 0)
  916. {
  917. return 18;
  918. }
  919. else if (withdrawalProbability() > 0)
  920. {
  921. return 16;
  922. }
  923. else if (!m_pUnitInfo->isPillage())
  924. {
  925. return 10;
  926. }
  927. else
  928. {
  929. return 14;
  930. }
  931. break;
  932. case UNITAI_COLLATERAL:
  933. return 7;
  934. break;
  935. case UNITAI_PILLAGE:
  936. return 12;
  937. break;
  938. case UNITAI_RESERVE:
  939. return 6;
  940. break;
  941. case UNITAI_COUNTER:
  942. return 5;
  943. break;
  944. case UNITAI_CITY_DEFENSE:
  945. return 3;
  946. break;
  947. case UNITAI_CITY_COUNTER:
  948. return 2;
  949. break;
  950. case UNITAI_CITY_SPECIAL:
  951. /*************************************************************************************************/
  952. /** BETTER AI (New UNITAI) Sephi **/
  953. /** **/
  954. /** **/
  955. /*************************************************************************************************/
  956. case UNITAI_MAGE:
  957. case UNITAI_TERRAFORMER:
  958. case UNITAI_MANA_UPGRADE:
  959. case UNITAI_WARWIZARD:
  960. /*************************************************************************************************/
  961. /** END **/
  962. /*************************************************************************************************/
  963. return 3;
  964. break;
  965. /*************************************************************************************************/
  966. /** BETTER AI (New UNITAI) Sephi **/
  967. /** **/
  968. /** **/
  969. /*************************************************************************************************/
  970. case UNITAI_FEASTING:
  971. case UNITAI_MEDIC:
  972. case UNITAI_INQUISITOR:
  973. return 3;
  974. break;
  975. case UNITAI_HERO:
  976. return 100; //Heroes don't like to get pushed around
  977. break;
  978. /*************************************************************************************************/
  979. /** END **/
  980. /*************************************************************************************************/
  981. case UNITAI_PARADROP:
  982. return 4;
  983. break;
  984. case UNITAI_EXPLORE:
  985. return 8;
  986. break;
  987. case UNITAI_MISSIONARY:
  988. return 10;
  989. break;
  990. case UNITAI_PROPHET:
  991. case UNITAI_ARTIST:
  992. case UNITAI_SCIENTIST:
  993. case UNITAI_GENERAL:
  994. case UNITAI_MERCHANT:
  995. case UNITAI_ENGINEER:
  996. return 11;
  997. break;
  998. case UNITAI_SPY:
  999. return 9;
  1000. break;
  1001. case UNITAI_ICBM:
  1002. break;
  1003. case UNITAI_WORKER_SEA:
  1004. return 8;
  1005. break;
  1006. case UNITAI_ATTACK_SEA:
  1007. return 3;
  1008. break;
  1009. case UNITAI_RESERVE_SEA:
  1010. return 2;
  1011. break;
  1012. case UNITAI_ESCORT_SEA:
  1013. return 1;
  1014. break;
  1015. case UNITAI_EXPLORE_SEA:
  1016. return 5;
  1017. break;
  1018. case UNITAI_ASSAULT_SEA:
  1019. return 11;
  1020. break;
  1021. case UNITAI_SETTLER_SEA:
  1022. return 9;
  1023. break;
  1024. case UNITAI_MISSIONARY_SEA:
  1025. return 9;
  1026. break;
  1027. case UNITAI_SPY_SEA:
  1028. return 10;
  1029. break;
  1030. case UNITAI_CARRIER_SEA:
  1031. return 7;
  1032. break;
  1033. case UNITAI_MISSILE_CARRIER_SEA:
  1034. return 6;
  1035. break;
  1036. case UNITAI_PIRATE_SEA:
  1037. return 4;
  1038. break;
  1039. case UNITAI_ATTACK_AIR:
  1040. case UNITAI_DEFENSE_AIR:
  1041. case UNITAI_CARRIER_AIR:
  1042. case UNITAI_MISSILE_AIR:
  1043. break;
  1044. case UNITAI_ATTACK_CITY_LEMMING:
  1045. return 1;
  1046. break;
  1047. case UNITAI_LAIRGUARDIAN:
  1048. case UNITAI_SHADE:
  1049. break;
  1050. default:
  1051. FAssert(false);
  1052. break;
  1053. }
  1054. return 0;
  1055. }
  1056. int CvUnitAI::AI_groupSecondVal()
  1057. {
  1058. return ((getDomainType() == DOMAIN_AIR) ? airBaseCombatStr() : baseCombatStr());
  1059. }
  1060. // Returns attack odds out of 100 (the higher, the better...)
  1061. // Withdrawal odds included in returned value
  1062. int CvUnitAI::AI_attackOdds(const CvPlot* pPlot, bool bPotentialEnemy) const
  1063. {
  1064. PROFILE_FUNC();
  1065. CvUnit* pDefender;
  1066. int iOurStrength;
  1067. int iTheirStrength;
  1068. int iOurFirepower;
  1069. int iTheirFirepower;
  1070. int iBaseOdds;
  1071. int iStrengthFactor;
  1072. int iDamageToUs;
  1073. int iDamageToThem;
  1074. int iNeededRoundsUs;
  1075. int iNeededRoundsThem;
  1076. int iHitLimitThem;
  1077. pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, !bPotentialEnemy, bPotentialEnemy);
  1078. if (pDefender == NULL)
  1079. {
  1080. return 100;
  1081. }
  1082. iOurStrength = ((getDomainType() == DOMAIN_AIR) ? airCurrCombatStr(NULL) : currCombatStr(NULL, pDefender));
  1083. iOurFirepower = ((getDomainType() == DOMAIN_AIR) ? iOurStrength : currFirepower(NULL, pDefender));
  1084. if (iOurStrength == 0)
  1085. {
  1086. return 1;
  1087. }
  1088. iTheirStrength = pDefender->currCombatStr(pPlot, this);
  1089. iTheirFirepower = pDefender->currFirepower(pPlot, this);
  1090. FAssert((iOurStrength + iTheirStrength) > 0);
  1091. FAssert((iOurFirepower + iTheirFirepower) > 0);
  1092. iBaseOdds = (100 * iOurStrength) / (iOurStrength + iTheirStrength);
  1093. if (iBaseOdds == 0)
  1094. {
  1095. return 1;
  1096. }
  1097. iStrengthFactor = ((iOurFirepower + iTheirFirepower + 1) / 2);
  1098. iDamageToUs = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iTheirFirepower + iStrengthFactor)) / (iOurFirepower + iStrengthFactor)));
  1099. iDamageToThem = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iOurFirepower + iStrengthFactor)) / (iTheirFirepower + iStrengthFactor)));
  1100. iHitLimitThem = pDefender->maxHitPoints() - combatLimit();
  1101. iNeededRoundsUs = (std::max(0, pDefender->currHitPoints() - iHitLimitThem) + iDamageToThem - 1 ) / iDamageToThem;
  1102. iNeededRoundsThem = (std::max(0, currHitPoints()) + iDamageToUs - 1 ) / iDamageToUs;
  1103. if (getDomainType() != DOMAIN_AIR)
  1104. {
  1105. /************************************************************************************************/
  1106. /* BETTER_BTS_AI_MOD 10/30/09 Mongoose & jdog5000 */
  1107. /* */
  1108. /* Unit AI */
  1109. /************************************************************************************************/
  1110. // From Mongoose SDK
  1111. if (!pDefender->immuneToFirstStrikes()) {
  1112. iNeededRoundsUs -= ((iBaseOdds * firstStrikes()) + ((iBaseOdds * chanceFirstStrikes()) / 2)) / 100;
  1113. }
  1114. if (!immuneToFirstStrikes()) {
  1115. iNeededRoundsThem -= (((100 - iBaseOdds) * pDefender->firstStrikes()) + (((100 - iBaseOdds) * pDefender->chanceFirstStrikes()) / 2)) / 100;
  1116. }
  1117. iNeededRoundsUs = std::max(1, iNeededRoundsUs);
  1118. iNeededRoundsThem = std::max(1, iNeededRoundsThem);
  1119. /************************************************************************************************/
  1120. /* BETTER_BTS_AI_MOD END */
  1121. /************************************************************************************************/
  1122. }
  1123. int iRoundsDiff = iNeededRoundsUs - iNeededRoundsThem;
  1124. if (iRoundsDiff > 0)
  1125. {
  1126. iTheirStrength *= (1 + iRoundsDiff);
  1127. }
  1128. else
  1129. {
  1130. iOurStrength *= (1 - iRoundsDiff);
  1131. }
  1132. int iOdds = (((iOurStrength * 100) / (iOurStrength + iTheirStrength)));
  1133. iOdds += ((100 - iOdds) * withdrawalProbability()) / 100;
  1134. iOdds += GET_PLAYER(getOwnerINLINE()).AI_getAttackOddsChange();
  1135. /************************************************************************************************/
  1136. /* BETTER_BTS_AI_MOD 10/30/09 Mongoose & jdog5000 */
  1137. /* */
  1138. /* Unit AI */
  1139. /************************************************************************************************/
  1140. // From Mongoose SDK
  1141. return range(iOdds, 1, 99);
  1142. /************************************************************************************************/
  1143. /* BETTER_BTS_AI_MOD END */
  1144. /************************************************************************************************/
  1145. }
  1146. // Returns true if the unit found a build for this city...
  1147. bool CvUnitAI::AI_bestCityBuild(CvCity* pCity, CvPlot** ppBestPlot, BuildTypes* peBestBuild, CvPlot* pIgnorePlot, CvUnit* pUnit)
  1148. {
  1149. PROFILE_FUNC();
  1150. int iBestValue = 0;
  1151. BuildTypes eBestBuild = NO_BUILD;
  1152. CvPlot* pBestPlot = NULL;
  1153. for (int iPass = 0; iPass < 2; iPass++)
  1154. {
  1155. for (int iI = 0; iI < pCity->getNumCityPlots(); iI++)
  1156. {
  1157. CvPlot* pLoopPlot = plotCity(pCity->getX_INLINE(), pCity->getY_INLINE(), iI);
  1158. if (pLoopPlot != NULL)
  1159. {
  1160. if (AI_plotValid(pLoopPlot))
  1161. {
  1162. if (pLoopPlot != pIgnorePlot)
  1163. {
  1164. if ((pLoopPlot->getImprovementType() == NO_IMPROVEMENT) || !(GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION) && !(pLoopPlot->getImprovementType() == (GC.getDefineINT("RUINS_IMPROVEMENT")))))
  1165. {
  1166. int iValue = pCity->AI_getBestBuildValue(iI);
  1167. if (iValue > iBestValue)
  1168. {
  1169. BuildTypes eBuild = pCity->AI_getBestBuild(iI);
  1170. FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");
  1171. if (eBuild != NO_BUILD)
  1172. {
  1173. if (0 == iPass)
  1174. {
  1175. iBestValue = iValue;
  1176. pBestPlot = pLoopPlot;
  1177. eBestBuild = eBuild;
  1178. }
  1179. else if (canBuild(pLoopPlot, eBuild))
  1180. {
  1181. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  1182. {
  1183. int iPathTurns;
  1184. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  1185. {
  1186. // XXX take advantage of range (warning... this could lead to some units doing nothing...)
  1187. int iMaxWorkers = 1;
  1188. if (getPathLastNode()->m_iData1 == 0)
  1189. {
  1190. iPathTurns++;
  1191. }
  1192. else if (iPathTurns <= 1)
  1193. {
  1194. iMaxWorkers = AI_calculatePlotWorkersNeeded(pLoopPlot, eBuild);
  1195. }
  1196. if (pUnit != NULL)
  1197. {
  1198. if (pUnit->plot()->isCity() && iPathTurns == 1 && getPathLastNode()->m_iData1 > 0)
  1199. {
  1200. iMaxWorkers += 10;
  1201. }
  1202. }
  1203. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup()) < iMaxWorkers)
  1204. {
  1205. //XXX this could be improved greatly by
  1206. //looking at the real build time and other factors
  1207. //when deciding whether to stack.
  1208. iValue /= iPathTurns;
  1209. iBestValue = iValue;
  1210. pBestPlot = pLoopPlot;
  1211. eBestBuild = eBuild;
  1212. }
  1213. }
  1214. }
  1215. }
  1216. }
  1217. }
  1218. }
  1219. }
  1220. }
  1221. }
  1222. }
  1223. if (0 == iPass)
  1224. {
  1225. if (eBestBuild != NO_BUILD)
  1226. {
  1227. FAssert(pBestPlot != NULL);
  1228. int iPathTurns;
  1229. if ((generatePath(pBestPlot, 0, true, &iPathTurns)) && canBuild(pBestPlot, eBestBuild)
  1230. && !(pBestPlot->isVisibleEnemyUnit(this)))
  1231. {
  1232. int iMaxWorkers = 1;
  1233. if (pUnit != NULL)
  1234. {
  1235. if (pUnit->plot()->isCity())
  1236. {
  1237. iMaxWorkers += 10;
  1238. }
  1239. }
  1240. if (getPathLastNode()->m_iData1 == 0)
  1241. {
  1242. iPathTurns++;
  1243. }
  1244. else if (iPathTurns <= 1)
  1245. {
  1246. iMaxWorkers = AI_calculatePlotWorkersNeeded(pBestPlot, eBestBuild);
  1247. }
  1248. int iWorkerCount = GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pBestPlot, MISSIONAI_BUILD, getGroup());
  1249. if (iWorkerCount < iMaxWorkers)
  1250. {
  1251. //Good to go.
  1252. break;
  1253. }
  1254. }
  1255. eBestBuild = NO_BUILD;
  1256. iBestValue = 0;
  1257. }
  1258. }
  1259. }
  1260. if (NO_BUILD != eBestBuild)
  1261. {
  1262. FAssert(NULL != pBestPlot);
  1263. if (ppBestPlot != NULL)
  1264. {
  1265. *ppBestPlot = pBestPlot;
  1266. }
  1267. if (peBestBuild != NULL)
  1268. {
  1269. *peBestBuild = eBestBuild;
  1270. }
  1271. }
  1272. return (NO_BUILD != eBestBuild);
  1273. }
  1274. bool CvUnitAI::AI_isCityAIType() const
  1275. {
  1276. return isCityAIType( AI_getUnitAIType() );
  1277. }
  1278. int CvUnitAI::AI_getBirthmark() const
  1279. {
  1280. return m_iBirthmark;
  1281. }
  1282. int CvUnitAI::AI_getBirthmark2() const
  1283. {
  1284. return m_iBirthmark;
  1285. }
  1286. int CvUnitAI::AI_getBirthmark3() const
  1287. {
  1288. return m_iBirthmark;
  1289. }
  1290. int CvUnitAI::AI_getBarbLeadership() const
  1291. {
  1292. int iFollowers = 0;
  1293. return (AI_getBarbLeadership(iFollowers));
  1294. }
  1295. // ALN - This is used as a measure of how able a barbarian unit is able to pull
  1296. // others barbarians under his command
  1297. int CvUnitAI::AI_getBarbLeadership(int& iFollowers) const
  1298. {
  1299. bool bHero = AI_getUnitAIType() == UNITAI_HERO;
  1300. bool bAttack = AI_getUnitAIType() == UNITAI_ATTACK;
  1301. bool bAttackCity = AI_getUnitAIType() == UNITAI_ATTACK_CITY;
  1302. // Only certain unitAIs can command other barbs
  1303. if (!bHero && !bAttack && !bAttackCity)
  1304. {
  1305. return 0;
  1306. }
  1307. int iLeadership = AI_getBirthmark3() % 8;
  1308. // more experienced units are better leaders
  1309. iLeadership += (std::min(3, getLevel() / 2));
  1310. // heros always are better leaders, not always great ones though
  1311. iLeadership += (bHero ? 2 + (AI_getBirthmark3() % 3) : 0);
  1312. // Absolute highest level possible will be 11
  1313. iLeadership = std::min(11, iLeadership);
  1314. // sorry goblins, you won't be leading any stacks of doom
  1315. iLeadership = std::min((baseCombatStr() * 2) + 1, iLeadership);
  1316. // undead don't lead large groups
  1317. if (!bHero && !isAlive())
  1318. {
  1319. iLeadership -= 1;
  1320. iLeadership = std::min(5 + (AI_getBirthmark3() % 2), iLeadership);
  1321. }
  1322. // max follower units based on leadership
  1323. if (iLeadership >= 9)
  1324. {
  1325. iFollowers = iLeadership - 6;
  1326. }
  1327. else if (iLeadership >= 5)
  1328. {
  1329. iFollowers = 2;
  1330. }
  1331. else if (iLeadership >= 3)
  1332. {
  1333. iFollowers = 1;
  1334. }
  1335. // limit group sizes in the beginning of the game
  1336. int iCivCities = GC.getGameINLINE().getNumCivCities();
  1337. int iCivs = GC.getGameINLINE().countCivPlayersAlive();
  1338. // Bugfix: Prevent a crash when playing with require complete kills.
  1339. if (iCivs <= 0) {
  1340. iCivs = 1;
  1341. }
  1342. iFollowers = std::min((iCivCities / (iCivs + (iCivs / 2))) + 1, iFollowers);
  1343. return iLeadership;
  1344. }
  1345. // ALN - This function is always to be called in the position of a barb looking for a higher 'leadership' barbarian
  1346. // that he's looking to join, never from the leader side, but from the follower side(looking for a better leader).
  1347. bool CvUnitAI::AI_groupBarbLeader(int iMaxRange) const
  1348. {
  1349. bool bHero = AI_getUnitAIType() == UNITAI_HERO;
  1350. bool bAttack = AI_getUnitAIType() == UNITAI_ATTACK;
  1351. bool bAttackCity = AI_getUnitAIType() == UNITAI_ATTACK_CITY;
  1352. if (isCargo())
  1353. {
  1354. return false;
  1355. }
  1356. if (bHero)
  1357. {
  1358. return false;
  1359. }
  1360. CvPlot* pPlot = plot();
  1361. CvSelectionGroup* pGroup = getGroup();
  1362. int iGroupSize = pGroup->getNumUnits();
  1363. int iOurLeadership = AI_getBarbLeadership();
  1364. int iOurRace = getRace();
  1365. int iLeadership;
  1366. int iRace;
  1367. int iMaxFollowers;
  1368. int iFollowers;
  1369. int iJoiners;
  1370. int iBestValue = 0;
  1371. CvUnit* pBestUnit = NULL;
  1372. for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
  1373. {
  1374. for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
  1375. {
  1376. CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
  1377. if (pLoopPlot != NULL && pLoopPlot->getArea() == pPlot->getArea())
  1378. {
  1379. CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
  1380. while (pUnitNode != NULL)
  1381. {
  1382. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  1383. pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
  1384. CvSelectionGroup* pLoopGroup = pLoopUnit->getGroup();
  1385. iRace = pLoopUnit->getRace();
  1386. // if pLoopUnit is not a hero, require race to be the same
  1387. if (iRace == iOurRace || pLoopUnit->AI_getUnitAIType() == UNITAI_HERO)
  1388. {
  1389. if (AI_allowGroup(pLoopUnit, UNITAI_UNKNOWN))
  1390. {
  1391. iLeadership = pLoopUnit->AI_getBarbLeadership(iMaxFollowers);
  1392. iFollowers = pLoopGroup->getNumUnits() - 1;
  1393. if (iLeadership > iOurLeadership)
  1394. {
  1395. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  1396. iJoiners = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, MISSIONAI_GROUP, pLoopGroup);
  1397. if (iFollowers + iJoiners + iGroupSize <= iMaxFollowers)
  1398. {
  1399. int XDist=pLoopPlot->getX_INLINE() - plot()->getX_INLINE();
  1400. int YDist=pLoopPlot->getY_INLINE() - plot()->getY_INLINE();
  1401. if (((XDist*XDist)+(YDist*YDist))<(iMaxRange + 2)*(iMaxRange + 2)*4)
  1402. {
  1403. int iPathTurns;
  1404. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  1405. {
  1406. if (iPathTurns <= (iMaxRange <= 2 ? iMaxRange + 2 : iMaxRange + 1))
  1407. {
  1408. int iValue = iLeadership * 1000;
  1409. // leaders can pick up different race units, but reduce it's value still
  1410. // so those different race units will prefer one of their own if also in range
  1411. iValue /= (iRace == iOurRace ? 1 : 2);
  1412. iValue /= (iPathTurns + 2);
  1413. if (iValue > iBestValue)
  1414. {
  1415. iBestValue = iValue;
  1416. pBestUnit = pLoopUnit;
  1417. }
  1418. }
  1419. }
  1420. }
  1421. }
  1422. }
  1423. }
  1424. }
  1425. }
  1426. }
  1427. }
  1428. }
  1429. if (pBestUnit != NULL)
  1430. {
  1431. if (atPlot(pBestUnit->plot()))
  1432. {
  1433. pGroup->mergeIntoGroup(pBestUnit->getGroup());
  1434. return true;
  1435. }
  1436. else
  1437. {
  1438. if (getGroup()->getNumUnits() > 1)
  1439. {
  1440. pGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
  1441. return true;
  1442. }
  1443. else
  1444. {
  1445. pGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
  1446. return true;
  1447. }
  1448. }
  1449. }
  1450. return false;
  1451. }
  1452. void CvUnitAI::AI_setBirthmark(int iNewValue)
  1453. {
  1454. m_iBirthmark = iNewValue;
  1455. if (AI_getUnitAIType() == UNITAI_EXPLORE_SEA)
  1456. {
  1457. if (GC.getGame().circumnavigationAvailable())
  1458. {
  1459. m_iBirthmark -= m_iBirthmark % 4;
  1460. int iExplorerCount = GET_PLAYER(getOwnerINLINE()).AI_getNumAIUnits(UNITAI_EXPLORE_SEA);
  1461. iExplorerCount += getOwnerINLINE() % 4;
  1462. if (GC.getMap().isWrapX())
  1463. {
  1464. if ((iExplorerCount % 2) == 1)
  1465. {
  1466. m_iBirthmark += 1;
  1467. }
  1468. }
  1469. if (GC.getMap().isWrapY())
  1470. {
  1471. if (!GC.getMap().isWrapX())
  1472. {
  1473. iExplorerCount *= 2;
  1474. }
  1475. if (((iExplorerCount >> 1) % 2) == 1)
  1476. {
  1477. m_iBirthmark += 2;
  1478. }
  1479. }
  1480. }
  1481. }
  1482. }
  1483. void CvUnitAI::AI_setBirthmark2(int iNewValue)
  1484. {
  1485. m_iBirthmark = iNewValue;
  1486. }
  1487. void CvUnitAI::AI_setBirthmark3(int iNewValue)
  1488. {
  1489. m_iBirthmark = iNewValue;
  1490. }
  1491. UnitAITypes CvUnitAI::AI_getUnitAIType() const
  1492. {
  1493. return m_eUnitAIType;
  1494. }
  1495. // XXX make sure this gets called...
  1496. void CvUnitAI::AI_setUnitAIType(UnitAITypes eNewValue)
  1497. {
  1498. FAssertMsg(eNewValue != NO_UNITAI, "NewValue is not assigned a valid value");
  1499. if (AI_getUnitAIType() != eNewValue)
  1500. {
  1501. area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), -1);
  1502. GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), -1);
  1503. m_eUnitAIType = eNewValue;
  1504. area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), 1);
  1505. GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), 1);
  1506. joinGroup(NULL);
  1507. }
  1508. }
  1509. int CvUnitAI::AI_sacrificeValue(const CvPlot* pPlot) const
  1510. {
  1511. int iValue;
  1512. int iCollateralDamageValue = 0;
  1513. if (pPlot != NULL)
  1514. {
  1515. int iPossibleTargets = std::min((pPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits());
  1516. if (iPossibleTargets > 0)
  1517. {
  1518. iCollateralDamageValue = collateralDamage();
  1519. iCollateralDamageValue += std::max(0, iCollateralDamageValue - 100);
  1520. // Improved Pyre Zombie AI (Skyre) - account for their explosion factor - merged by Tholal 4/12/10
  1521. if (getUnitInfo().isExplodeInCombat())
  1522. {
  1523. iCollateralDamageValue += 150;
  1524. }
  1525. // End Improved Pyre Zombie AI
  1526. iCollateralDamageValue *= iPossibleTargets;
  1527. iCollateralDamageValue /= 5;
  1528. }
  1529. }
  1530. if (getDomainType() == DOMAIN_AIR)
  1531. {
  1532. iValue = 128 * (100 + currInterceptionProbability());
  1533. if (m_pUnitInfo->getNukeRange() != -1)
  1534. {
  1535. iValue += 25000;
  1536. }
  1537. iValue /= std::max(1, (1 + m_pUnitInfo->getProductionCost()));
  1538. iValue *= (maxHitPoints() - getDamage());
  1539. iValue /= 100;
  1540. }
  1541. else
  1542. {
  1543. /************************************************************************************************/
  1544. /* BETTER_BTS_AI_MOD 05/14/10 jdog5000 */
  1545. /* */
  1546. /* General AI */
  1547. /************************************************************************************************/
  1548. /*
  1549. // original bts code
  1550. iValue = 128 * (currEffectiveStr(pPlot, ((pPlot == NULL) ? NULL : this)));
  1551. iValue *= (100 + iCollateralDamageValue);
  1552. iValue /= (100 + cityDefenseModifier());
  1553. iValue *= (100 + withdrawalProbability());
  1554. iValue /= std::max(1, (1 + m_pUnitInfo->getProductionCost()));
  1555. iValue /= (10 + getExperience());
  1556. */
  1557. iValue = 128 * (currEffectiveStr(pPlot, ((pPlot == NULL) ? NULL : this)));
  1558. iValue *= (100 + iCollateralDamageValue);
  1559. iValue /= (100 + cityDefenseModifier());
  1560. iValue *= (100 + withdrawalProbability());
  1561. // Value experience a bit more, especially medics
  1562. iValue /= (10 + getExperience());
  1563. iValue /= (10 + getSameTileHeal() + getAdjacentTileHeal());
  1564. /************************************************************************************************/
  1565. /* BETTER_BTS_AI_MOD END */
  1566. /************************************************************************************************/
  1567. // Value units which can't kill units later, also combat limits mean higher survival odds
  1568. if (combatLimit() < 100)
  1569. {
  1570. iValue *= 150;
  1571. iValue /= 100;
  1572. iValue *= 100;
  1573. iValue /= std::max(1, combatLimit());
  1574. }
  1575. iValue /= std::max(1, (1 + m_pUnitInfo->getProductionCost()));
  1576. /************************************************************************************************/
  1577. /* BETTER_BTS_AI_MOD END */
  1578. /************************************************************************************************/
  1579. }
  1580. // summoned units make good sacrifices since they can be resummoned
  1581. if (getSummoner() != -1)
  1582. {
  1583. iValue *= 10;
  1584. }
  1585. return iValue;
  1586. }
  1587. // Protected Functions...
  1588. void CvUnitAI::AI_animalMove()
  1589. {
  1590. PROFILE_FUNC();
  1591. if( gUnitLogLevel >= 2 )
  1592. {
  1593. logBBAI(" Stack %d (led by %S (%d), size %d) starting animalMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  1594. }
  1595. //FfH: Added by Kael 10/26/2008 So that animals can build their pens...
  1596. if (!isBarbarian())
  1597. {
  1598. if (AI_construct())
  1599. {
  1600. return;
  1601. }
  1602. // ToDo: here's where we should decide whether or not to keep animals as HN - requires more HN move code
  1603. if (getDomainType() == DOMAIN_SEA)
  1604. {
  1605. if (isHiddenNationality())
  1606. {
  1607. AI_setUnitAIType(UNITAI_PIRATE_SEA);
  1608. }
  1609. else
  1610. {
  1611. AI_setUnitAIType(UNITAI_ATTACK_SEA);
  1612. }
  1613. }
  1614. else
  1615. {
  1616. AI_setUnitAIType(UNITAI_COUNTER);
  1617. }
  1618. return;
  1619. }
  1620. //FfH: End Add
  1621. if (GC.getGameINLINE().getSorenRandNum(100, "Animal Attack") < GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAnimalAttackProb())
  1622. {
  1623. if (AI_anyAttack(1, 0, 0, false))
  1624. {
  1625. return;
  1626. }
  1627. }
  1628. if (AI_heal())
  1629. {
  1630. return;
  1631. }
  1632. if (AI_patrol())
  1633. {
  1634. return;
  1635. }
  1636. getGroup()->pushMission(MISSION_SKIP);
  1637. return;
  1638. }
  1639. void CvUnitAI::AI_settleMove()
  1640. {
  1641. PROFILE_FUNC();
  1642. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  1643. if( gUnitLogLevel >= 2 )
  1644. {
  1645. logBBAI(" Stack %d (led by %S (%d), size %d) starting settleMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  1646. }
  1647. /*************************************************************************************************/
  1648. /** BETTER AI (UNITAI_SETTLE move) Sephi **/
  1649. /*************************************************************************************************/
  1650. //reset values after first city is build
  1651. if (kOwner.getNumCities() == 1 && getGroup()->getNumUnits()==1)
  1652. {
  1653. GET_PLAYER(getOwnerINLINE()).AI_updateFoundValues(false);
  1654. }
  1655. // TODO - figure out why the AI does a poor job of settling without this section
  1656. if (kOwner.getNumCities() == 0)
  1657. {
  1658. if (GC.getGameINLINE().getGameTurn()==0)
  1659. {
  1660. kOwner.AI_updateFoundValues(false);
  1661. CvPlot* pLoopPlot;
  1662. CvPlot* pBestPlot;
  1663. int iSearchRange;
  1664. int iPathTurns;
  1665. int iValue;
  1666. int iBestValue;
  1667. int iDX, iDY;
  1668. iSearchRange = 6;
  1669. int iRange = 6;
  1670. iBestValue = plot()->getFoundValue(getOwnerINLINE());
  1671. pBestPlot = plot();
  1672. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  1673. {
  1674. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  1675. {
  1676. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  1677. if (pLoopPlot != NULL)
  1678. {
  1679. if (pLoopPlot->isRevealed(getTeam(), false) || pLoopPlot->isAdjacentRevealed(getTeam()))
  1680. {
  1681. if ((AI_plotValid(pLoopPlot)) && canFound(pLoopPlot))
  1682. {
  1683. if (!pLoopPlot->isVisibleEnemyUnit(this))
  1684. {
  1685. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  1686. {
  1687. if (iPathTurns < 2)
  1688. {
  1689. iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
  1690. if (iValue > iBestValue)
  1691. {
  1692. iBestValue = iValue;
  1693. pBestPlot = pLoopPlot;
  1694. }
  1695. }
  1696. }
  1697. }
  1698. }
  1699. }
  1700. }
  1701. }
  1702. }
  1703. if (pBestPlot != NULL)
  1704. {
  1705. if(atPlot(pBestPlot))
  1706. {
  1707. CvCity* pNearestCity;
  1708. pNearestCity = GC.getMapINLINE().findCity(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), NO_PLAYER, getTeam());
  1709. if (pNearestCity != NULL)
  1710. {
  1711. if (plotDistance(plot()->getX_INLINE(), plot()->getY_INLINE(), pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE()) <= 3)
  1712. {
  1713. kOwner.AI_updateFoundValues(false);
  1714. int iNewCityPlotValue = pBestPlot->getFoundValue(getOwnerINLINE());
  1715. if (iNewCityPlotValue < iBestValue)
  1716. {
  1717. getGroup()->pushMission(MISSION_SKIP);
  1718. return;
  1719. }
  1720. }
  1721. }
  1722. getGroup()->pushMission(MISSION_FOUND);
  1723. return;
  1724. }
  1725. else
  1726. {
  1727. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  1728. return;
  1729. }
  1730. }
  1731. }
  1732. if (canFound(plot()))
  1733. {
  1734. getGroup()->pushMission(MISSION_FOUND);
  1735. return;
  1736. }
  1737. }
  1738. // Tholal AI - modified from BBAI
  1739. int iDanger = kOwner.AI_getPlotDanger(plot(), 2);
  1740. int iNeededSettleDefenders = (GC.getGameINLINE().isOption(GAMEOPTION_RAGING_BARBARIANS) ? 4 : 3);
  1741. if (GET_TEAM(getTeam()).isBarbarianAlly() && GET_TEAM(getTeam()).getAtWarCount(true) == 0)
  1742. {
  1743. iNeededSettleDefenders = 2;
  1744. }
  1745. if (GC.getGameINLINE().isOption(GAMEOPTION_NO_BARBARIANS) || GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_PEACE))
  1746. {
  1747. iNeededSettleDefenders -= 1;
  1748. }
  1749. if (iDanger > 0)
  1750. {
  1751. if( gUnitLogLevel > 3 ) logBBAI(" ... in Danger (%d) Zone at plot %d, %d", iDanger, plot()->getX(), plot()->getY());
  1752. if ((plot()->getOwnerINLINE() == getOwnerINLINE()) || (iDanger > getGroup()->getNumUnits()) || !getGroup()->canDefend())
  1753. {
  1754. //if (getGroup()->getNumUnits() < iNeededSettleDefenders)
  1755. if (plot()->getNumDefenders(getOwnerINLINE()) < iNeededSettleDefenders)
  1756. {
  1757. if( gUnitLogLevel > 3 ) logBBAI(" ... not enough defenders; seeking safety (H/N: %d/%d)", plot()->getNumDefenders(getOwnerINLINE()), iNeededSettleDefenders);
  1758. if (AI_retreatToCity())
  1759. {
  1760. return;
  1761. }
  1762. if (AI_safety())
  1763. {
  1764. return;
  1765. }
  1766. //getGroup()->pushMission(MISSION_SKIP);
  1767. }
  1768. }
  1769. }
  1770. if (plot()->isCity())
  1771. {
  1772. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  1773. {
  1774. if (getGroup()->getNumUnits() < iNeededSettleDefenders)
  1775. {
  1776. if( gUnitLogLevel > 3 ) logBBAI(" ...not enough defenders");
  1777. getGroup()->pushMission(MISSION_SKIP);
  1778. return;
  1779. }
  1780. }
  1781. }
  1782. int iAreaBestFoundValue = 0;
  1783. int iOtherBestFoundValue = 0;
  1784. if( gUnitLogLevel > 3 ) logBBAI(" ...number of city sites: %d", kOwner.AI_getNumCitySites());
  1785. if( gUnitLogLevel > 3 ) logBBAI(" ...min found value: %d", kOwner.AI_getMinFoundValue());
  1786. for (int iI = 0; iI < kOwner.AI_getNumCitySites(); iI++)
  1787. {
  1788. CvPlot* pCitySitePlot = kOwner.AI_getCitySite(iI);
  1789. if( gUnitLogLevel > 3 ) logBBAI(" ...checking site at %d, %d", pCitySitePlot->getX(), pCitySitePlot->getY());
  1790. /************************************************************************************************/
  1791. /* UNOFFICIAL_PATCH 01/10/09 jdog5000 */
  1792. /* */
  1793. /* Bugfix, settler AI */
  1794. /************************************************************************************************/
  1795. /* original bts code
  1796. if (pCitySitePlot->getArea() == getArea())
  1797. */
  1798. // Only count city sites we can get to
  1799. if ((pCitySitePlot->getArea() == getArea() || canMoveAllTerrain()) && generatePath(pCitySitePlot, MOVE_AVOID_ENEMY_WEIGHT_3, true))
  1800. /************************************************************************************************/
  1801. /* UNOFFICIAL_PATCH END */
  1802. /************************************************************************************************/
  1803. {
  1804. if (plot() == pCitySitePlot)
  1805. {
  1806. if (canFound(plot()))
  1807. {
  1808. if( gUnitLogLevel >= 2 )
  1809. {
  1810. logBBAI(" Settler founding in place since it's at a city site %d, %d", getX_INLINE(), getY_INLINE());
  1811. }
  1812. getGroup()->pushMission(MISSION_FOUND);
  1813. return;
  1814. }
  1815. }
  1816. if( gUnitLogLevel > 3 ) logBBAI(" ...found value: %d", pCitySitePlot->getFoundValue(getOwnerINLINE()));
  1817. iAreaBestFoundValue = std::max(iAreaBestFoundValue, pCitySitePlot->getFoundValue(getOwnerINLINE()));
  1818. }
  1819. else
  1820. {
  1821. iOtherBestFoundValue = std::max(iOtherBestFoundValue, pCitySitePlot->getFoundValue(getOwnerINLINE()));
  1822. }
  1823. }
  1824. if( gUnitLogLevel > 3 ) logBBAI(" ...iAreaBestFoundValue: %d", iAreaBestFoundValue);
  1825. if( gUnitLogLevel > 3 ) logBBAI(" ...iOtherBestFoundValue: %d", iOtherBestFoundValue);
  1826. if (iAreaBestFoundValue > 0 && kOwner.getNumCities() == 0)
  1827. {
  1828. if (AI_found())
  1829. {
  1830. return;
  1831. }
  1832. }
  1833. /************************************************************************************************/
  1834. /* BETTER_BTS_AI_MOD 01/16/09 jdog5000 */
  1835. /* */
  1836. /* Gold AI */
  1837. /************************************************************************************************/
  1838. // No new settling of colonies when AI is in financial trouble
  1839. /*
  1840. if( plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()) )
  1841. {
  1842. if( kOwner.AI_isFinancialTrouble() )
  1843. {
  1844. iOtherBestFoundValue = 0;
  1845. }
  1846. }
  1847. */
  1848. /************************************************************************************************/
  1849. /* BETTER_BTS_AI_MOD END */
  1850. /************************************************************************************************/
  1851. if ((iOtherBestFoundValue * 100) > (iAreaBestFoundValue * 110))
  1852. {
  1853. // Tholal TODO - Make sure we dont board a ship for a distant location unless the ship can take us there
  1854. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  1855. {
  1856. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, 0, MOVE_SAFE_TERRITORY))
  1857. {
  1858. if( gUnitLogLevel >= 2 )
  1859. {
  1860. logBBAI(" ... boarding a transport because we have better site in another area");
  1861. }
  1862. return;
  1863. }
  1864. }
  1865. }
  1866. /*
  1867. if ((iAreaBestFoundValue > 0) && plot()->isBestAdjacentFound(getOwnerINLINE()))
  1868. {
  1869. if (canFound(plot()))
  1870. {
  1871. if( gUnitLogLevel >= 2 )
  1872. {
  1873. logBBAI(" Settler founding in place due to best adjacent found");
  1874. }
  1875. getGroup()->pushMission(MISSION_FOUND);
  1876. return;
  1877. }
  1878. }
  1879. */
  1880. if (!GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_PEACE) && !GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) && !getGroup()->canDefend())
  1881. {
  1882. if (AI_retreatToCity())
  1883. {
  1884. if( gUnitLogLevel >= 2 ){logBBAI(" ... retreating to city due to lack of defense");}
  1885. return;
  1886. }
  1887. }
  1888. if (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()))
  1889. {
  1890. /************************************************************************************************/
  1891. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  1892. /* */
  1893. /* Unit AI, Efficiency */
  1894. /************************************************************************************************/
  1895. //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0)
  1896. if (kOwner.AI_getAnyPlotDanger(plot())
  1897. /************************************************************************************************/
  1898. /* BETTER_BTS_AI_MOD END */
  1899. /************************************************************************************************/
  1900. && (GC.getGameINLINE().getMaxCityElimination() > 0))
  1901. {
  1902. if (getGroup()->getNumUnits() < iNeededSettleDefenders)
  1903. {
  1904. if( gUnitLogLevel >= 3 ){logBBAI(" ... staying in place due to lack of defense");}
  1905. getGroup()->pushMission(MISSION_SKIP);
  1906. return;
  1907. }
  1908. }
  1909. }
  1910. if (iAreaBestFoundValue > 0)
  1911. {
  1912. if (AI_found())
  1913. {
  1914. return;
  1915. }
  1916. }
  1917. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  1918. {
  1919. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, 0, MOVE_NO_ENEMY_TERRITORY))
  1920. {
  1921. if( gUnitLogLevel >= 3 ){logBBAI(" ... loading onto a Settler transport");}
  1922. return;
  1923. }
  1924. // BBAI TODO: Go to a good city (like one with a transport) ...
  1925. }
  1926. // make sure combat units dont get stuck guarding settlers in cities during wartime
  1927. if (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()))
  1928. {
  1929. if (getGroup()->getNumUnits() > 2)
  1930. {
  1931. if ((GET_TEAM(getTeam()).getAtWarCount(false) > 0) && (iDanger > 0))
  1932. {
  1933. if( gUnitLogLevel >= 3 ){logBBAI(" ... breaking up Settler group");}
  1934. joinGroup(NULL, true);
  1935. return;
  1936. }
  1937. }
  1938. }
  1939. if (!plot()->isCity())
  1940. {
  1941. if (AI_retreatToCity())
  1942. {
  1943. if( gUnitLogLevel >= 3 ){logBBAI(" ... retreating to city");}
  1944. return;
  1945. }
  1946. }
  1947. /************************************************************************************************/
  1948. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  1949. /* */
  1950. /* Settler AI */
  1951. /************************************************************************************************/
  1952. if( getGroup()->isStranded() )
  1953. {
  1954. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  1955. {
  1956. if( gUnitLogLevel >= 3 ){logBBAI(" ... loading onto ship due to Stranded status");}
  1957. return;
  1958. }
  1959. }
  1960. /************************************************************************************************/
  1961. /* BETTER_BTS_AI_MOD END */
  1962. /************************************************************************************************/
  1963. if (AI_safety())
  1964. {
  1965. return;
  1966. }
  1967. getGroup()->pushMission(MISSION_SKIP);
  1968. return;
  1969. }
  1970. void CvUnitAI::AI_workerMove()
  1971. {
  1972. PROFILE_FUNC();
  1973. CvCity* pCity;
  1974. bool bCanRoute;
  1975. bool bNextCity;
  1976. bCanRoute = canBuildRoute();
  1977. bNextCity = false;
  1978. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  1979. if( gUnitLogLevel >= 2 )
  1980. {
  1981. logBBAI(" Stack %d (led by %S (%d), size %d) starting workerMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  1982. }
  1983. if (AI_construct())
  1984. {
  1985. return;
  1986. }
  1987. // Tholal AI - Catch for upgraded worker units
  1988. if (m_pUnitInfo->getWorkRate() == 0)
  1989. {
  1990. AI_setUnitAIType((UnitAITypes)m_pUnitInfo->getDefaultUnitAIType());
  1991. AI_setGroupflag(GROUPFLAG_NONE);
  1992. }
  1993. // slaves can hurry production
  1994. if (GC.getUnitInfo(getUnitType()).getBaseHurry() > 0)
  1995. {
  1996. if (AI_hurry())
  1997. {
  1998. return;
  1999. }
  2000. }
  2001. // XXX could be trouble...
  2002. // Super Forts begin *AI_worker* (removing this to allow workers to build outside borders)
  2003. if(!GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS) && plot()->getOwnerINLINE() != getOwnerINLINE())
  2004. //if (plot()->getOwnerINLINE() != getOwnerINLINE())
  2005. {
  2006. if (AI_retreatToCity())
  2007. {
  2008. return;
  2009. }
  2010. }
  2011. // Super Forts end
  2012. if (!isHuman())
  2013. {
  2014. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  2015. {
  2016. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, 2, -1, -1, 0, MOVE_SAFE_TERRITORY))
  2017. {
  2018. if( gUnitLogLevel >= 3 ){logBBAI(" ... loading onto Settler ship");}
  2019. return;
  2020. }
  2021. }
  2022. }
  2023. /*************************************************************************************************/
  2024. /** Skyre Mod **/
  2025. /** BETTER AI (Workers retreat at Danger ) merged Sephi **/
  2026. /** **/
  2027. /*************************************************************************************************/
  2028. /**Orig
  2029. if (!(getGroup()->canDefend()))
  2030. {
  2031. if (GET_PLAYER(getOwnerINLINE()).AI_isPlotThreatened(plot(), 2))
  2032. {
  2033. if (AI_retreatToCity()) // XXX maybe not do this??? could be working productively somewhere else...
  2034. {
  2035. return;
  2036. }
  2037. }
  2038. }
  2039. if (bCanRoute)
  2040. {
  2041. if (plot()->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
  2042. {
  2043. BonusTypes eNonObsoleteBonus = plot()->getNonObsoleteBonusType(getTeam());
  2044. if (NO_BONUS != eNonObsoleteBonus)
  2045. {
  2046. if (!(plot()->isConnectedToCapital()))
  2047. {
  2048. ImprovementTypes eImprovement = plot()->getImprovementType();
  2049. if (NO_IMPROVEMENT != eImprovement && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
  2050. {
  2051. if (AI_connectPlot(plot()))
  2052. {
  2053. return;
  2054. }
  2055. }
  2056. }
  2057. }
  2058. }
  2059. }
  2060. CvPlot* pBestBonusPlot = NULL;
  2061. BuildTypes eBestBonusBuild = NO_BUILD;
  2062. int iBestBonusValue = 0;
  2063. if (AI_improveBonus(25, &pBestBonusPlot, &eBestBonusBuild, &iBestBonusValue))
  2064. {
  2065. return;
  2066. }
  2067. **/
  2068. if (kOwner.AI_isPlotThreatened(plot(), 3))
  2069. {
  2070. bool bDanger = true;
  2071. if (bDanger)
  2072. {
  2073. if (AI_retreatToCity())
  2074. {
  2075. if( gUnitLogLevel >= 3 ){logBBAI(" ... retreating from danger");}
  2076. return;
  2077. }
  2078. }
  2079. }
  2080. CvPlot* pBestBonusPlot = NULL;
  2081. BuildTypes eBestBonusBuild = NO_BUILD;
  2082. int iBestBonusValue = 0;
  2083. // First try to connect resources. Only consider resources inside borders, even if super forts is enabled.
  2084. if (AI_improveBonus(25, &pBestBonusPlot, &eBestBonusBuild, &iBestBonusValue, true))
  2085. {
  2086. return;
  2087. }
  2088. if (bCanRoute)
  2089. {
  2090. if (plot()->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
  2091. {
  2092. BonusTypes eNonObsoleteBonus = plot()->getNonObsoleteBonusType(getTeam());
  2093. if (NO_BONUS != eNonObsoleteBonus)
  2094. {
  2095. if (!(plot()->isConnectedToCapital()))
  2096. {
  2097. ImprovementTypes eImprovement = plot()->getImprovementType();
  2098. //if (NO_IMPROVEMENT != eImprovement && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
  2099. if (kOwner.doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus))
  2100. {
  2101. if (AI_connectPlot(plot()))
  2102. {
  2103. if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting the plot on which we're standing");}
  2104. return;
  2105. }
  2106. }
  2107. }
  2108. }
  2109. }
  2110. }
  2111. /*
  2112. if (AI_improveBonus(25, &pBestBonusPlot, &eBestBonusBuild, &iBestBonusValue))
  2113. {
  2114. return;
  2115. }
  2116. */
  2117. /*************************************************************************************************/
  2118. /** END **/
  2119. /*************************************************************************************************/
  2120. if (bCanRoute && !isBarbarian())
  2121. {
  2122. if (AI_connectCity())
  2123. {
  2124. if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting some city");}
  2125. return;
  2126. }
  2127. }
  2128. pCity = NULL;
  2129. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  2130. {
  2131. pCity = plot()->getPlotCity();
  2132. if (pCity == NULL)
  2133. {
  2134. pCity = plot()->getWorkingCity();
  2135. }
  2136. }
  2137. // if (pCity != NULL)
  2138. // {
  2139. // bool bMoreBuilds = false;
  2140. // for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
  2141. // {
  2142. // CvPlot* pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
  2143. // if ((iI != CITY_HOME_PLOT) && (pLoopPlot != NULL))
  2144. // {
  2145. // if (pLoopPlot->getWorkingCity() == pCity)
  2146. // {
  2147. // if (pLoopPlot->isBeingWorked())
  2148. // {
  2149. // if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT)
  2150. // {
  2151. // if (pCity->AI_getBestBuildValue(iI) > 0)
  2152. // {
  2153. // ImprovementTypes eImprovement;
  2154. // eImprovement = (ImprovementTypes)GC.getBuildInfo((BuildTypes)pCity->AI_getBestBuild(iI)).getImprovement();
  2155. // if (eImprovement != NO_IMPROVEMENT)
  2156. // {
  2157. // bMoreBuilds = true;
  2158. // break;
  2159. // }
  2160. // }
  2161. // }
  2162. // }
  2163. // }
  2164. // }
  2165. // }
  2166. //
  2167. // if (bMoreBuilds)
  2168. // {
  2169. // if (AI_improveCity(pCity))
  2170. // {
  2171. // return;
  2172. // }
  2173. // }
  2174. // }
  2175. if (pCity != NULL)
  2176. {
  2177. /* original bts code (is it just me, or did they get this backwards?)
  2178. if ((pCity->AI_getWorkersNeeded() > 0) && (plot()->isCity() || (pCity->AI_getWorkersNeeded() < ((1 + pCity->AI_getWorkersHave() * 2) / 3)))) */
  2179. // K-Mod
  2180. if (pCity->AI_getWorkersNeeded() > 0 && (plot()->isCity() || pCity->AI_getWorkersHave() < (1 + pCity->AI_getWorkersNeeded() * 2) / 3))
  2181. // K-Mod end
  2182. {
  2183. if (AI_improveCity(pCity))
  2184. {
  2185. if( gUnitLogLevel >= 3 ){logBBAI(" ... improving city %S", pCity->getName().c_str());}
  2186. return;
  2187. }
  2188. }
  2189. }
  2190. if (AI_improveLocalPlot(2, pCity))
  2191. {
  2192. if( gUnitLogLevel >= 3 ){logBBAI(" ... improving local plot");}
  2193. return;
  2194. }
  2195. bool bBuildFort = false;
  2196. if (GC.getGame().getSorenRandNum(5, "AI Worker build Fort with Priority") == 1)
  2197. {
  2198. // Super Forts begin *canal* *choke*
  2199. //CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  2200. bool bCanal = kOwner.countNumCoastalCities() > 0; //((100 * area()->getNumCities()) / std::max(1, GC.getGame().getNumCities()) < 85);
  2201. bool bAirbase = false;
  2202. bAirbase = (kOwner.AI_totalUnitAIs(UNITAI_PARADROP) || kOwner.AI_totalUnitAIs(UNITAI_ATTACK_AIR) || kOwner.AI_totalUnitAIs(UNITAI_MISSILE_AIR));
  2203. // if (bCanal || bAirbase)
  2204. // {
  2205. if (AI_fortTerritory(bCanal, bAirbase))
  2206. {
  2207. if( gUnitLogLevel >= 3 ){logBBAI(" ... build fort");}
  2208. return;
  2209. }
  2210. // }
  2211. bBuildFort = bCanal && bAirbase;
  2212. }
  2213. // Super Forts end
  2214. if (bCanRoute && isBarbarian())
  2215. {
  2216. if (AI_connectCity())
  2217. {
  2218. // LFGR_TODO: Can this ever happen? Same checks above.
  2219. if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting some city");}
  2220. return;
  2221. }
  2222. }
  2223. if ((pCity == NULL) || (pCity->AI_getWorkersNeeded() == 0) || ((pCity->AI_getWorkersHave() > (pCity->AI_getWorkersNeeded() + 1))))
  2224. {
  2225. if ((pBestBonusPlot != NULL) && (iBestBonusValue >= 15))
  2226. {
  2227. if (AI_improvePlot(pBestBonusPlot, eBestBonusBuild))
  2228. {
  2229. if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting bonus with low priority that we found earlier");}
  2230. return;
  2231. }
  2232. }
  2233. // if (pCity == NULL)
  2234. // {
  2235. // pCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE()); // XXX do team???
  2236. // }
  2237. if (AI_nextCityToImprove(pCity))
  2238. {
  2239. if( gUnitLogLevel >= 3 ){logBBAI(" ... improve next city");}
  2240. return;
  2241. }
  2242. bNextCity = true;
  2243. }
  2244. if (pBestBonusPlot != NULL)
  2245. {
  2246. if (AI_improvePlot(pBestBonusPlot, eBestBonusBuild))
  2247. {
  2248. if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting bonus with very low priority that we found earlier");}
  2249. return;
  2250. }
  2251. }
  2252. // Second try to connect resources, outside borders with super forts
  2253. if( GC.getGameINLINE().isOption( GAMEOPTION_ADVANCED_TACTICS ) )
  2254. {
  2255. // Only do this if we have defenders to spare for the fort.
  2256. bool bDefendersAvailable = true; // LFGR_TODO
  2257. /*bool bDefendersAvailable = false;
  2258. CvPlayerAI& kOwner = GET_PLAYER( getOwnerINLINE() );
  2259. int iLoop;
  2260. for( CvCity* pLoopCity = kOwner.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kOwner.nextCity(&iLoop) )
  2261. {
  2262. if( pLoopCity->area()->getID() == area()->getID() )
  2263. {
  2264. int iDefenders = pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE());
  2265. iDefenders += pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_COUNTER, -1, getOwnerINLINE());
  2266. if( pLoopCity->AI_neededDefenders() < iDefenders ) {
  2267. bDefendersAvailable = true;
  2268. break;
  2269. }
  2270. }
  2271. }*/
  2272. if( bDefendersAvailable ) {
  2273. if( AI_improveBonus() ) {
  2274. if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting bonus outside borders");}
  2275. return;
  2276. }
  2277. }
  2278. else {
  2279. if( gUnitLogLevel >= 3 ){logBBAI(" ... don't try to connect bonus outside borders: no defenders available!");}
  2280. }
  2281. }
  2282. if (pCity != NULL)
  2283. {
  2284. if (AI_improveCity(pCity))
  2285. {
  2286. return;
  2287. }
  2288. }
  2289. if (!bNextCity)
  2290. {
  2291. if (AI_nextCityToImprove(pCity))
  2292. {
  2293. return;
  2294. }
  2295. }
  2296. if (bCanRoute)
  2297. {
  2298. if (AI_routeTerritory(true))
  2299. {
  2300. return;
  2301. }
  2302. if (AI_connectBonus(false))
  2303. {
  2304. return;
  2305. }
  2306. if (AI_routeCity())
  2307. {
  2308. return;
  2309. }
  2310. }
  2311. if (AI_irrigateTerritory())
  2312. {
  2313. return;
  2314. }
  2315. // Super Forts begin *canal* *choke*
  2316. if (!bBuildFort)
  2317. {
  2318. if (AI_fortTerritory(true, true /*bCanal, bAirbase*/))
  2319. {
  2320. return;
  2321. }
  2322. }
  2323. /* if (!bBuildFort)
  2324. {
  2325. bool bCanal = ((100 * area()->getNumCities()) / std::max(1, GC.getGame().getNumCities()) < 85);
  2326. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  2327. bool bAirbase = false;
  2328. bAirbase = (kPlayer.AI_totalUnitAIs(UNITAI_PARADROP) || kPlayer.AI_totalUnitAIs(UNITAI_ATTACK_AIR) || kPlayer.AI_totalUnitAIs(UNITAI_MISSILE_AIR));
  2329. if (bCanal || bAirbase)
  2330. {
  2331. if (AI_fortTerritory(bCanal, bAirbase))
  2332. {
  2333. return;
  2334. }
  2335. }
  2336. }*/
  2337. // Super Forts end
  2338. if (bCanRoute)
  2339. {
  2340. if (AI_routeTerritory())
  2341. {
  2342. return;
  2343. }
  2344. }
  2345. if (!isHuman() || (isAutomated() && GET_TEAM(getTeam()).getAtWarCount(true) == 0))
  2346. {
  2347. if (!isHuman() || (getGameTurnCreated() < GC.getGame().getGameTurn()))
  2348. {
  2349. if (AI_nextCityToImproveAirlift())
  2350. {
  2351. return;
  2352. }
  2353. }
  2354. if (!isHuman())
  2355. {
  2356. /************************************************************************************************/
  2357. /* BETTER_BTS_AI_MOD 01/14/09 jdog5000 */
  2358. /* */
  2359. /* Worker AI */
  2360. /************************************************************************************************/
  2361. /*
  2362. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY))
  2363. {
  2364. return;
  2365. }
  2366. */
  2367. // Fill up boats which already have workers
  2368. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_WORKER, -1, -1, -1, -1, MOVE_SAFE_TERRITORY))
  2369. {
  2370. return;
  2371. }
  2372. // Avoid filling a galley which has just a settler in it, reduce chances for other ships
  2373. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, 2, -1, -1, MOVE_SAFE_TERRITORY))
  2374. {
  2375. return;
  2376. }
  2377. /************************************************************************************************/
  2378. /* BETTER_BTS_AI_MOD END */
  2379. /************************************************************************************************/
  2380. }
  2381. }
  2382. if (AI_improveLocalPlot(3, NULL))
  2383. {
  2384. return;
  2385. }
  2386. /*************************************************************************************************/
  2387. /** BETTER AI (stop AI from deleting workers) Sephi **/
  2388. /** **/
  2389. /** **/
  2390. /*************************************************************************************************/
  2391. /**
  2392. if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_WORKER))
  2393. {
  2394. if (GC.getGameINLINE().getElapsedGameTurns() > 10)
  2395. {
  2396. if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_WORKER) > GET_PLAYER(getOwnerINLINE()).getNumCities())
  2397. {
  2398. if (GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
  2399. {
  2400. scrap();
  2401. return;
  2402. }
  2403. }
  2404. }
  2405. }
  2406. /*************************************************************************************************/
  2407. /** END **/
  2408. /*************************************************************************************************/
  2409. if (AI_retreatToCity(false, true))
  2410. {
  2411. if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting bonus outside of borders with a super fort");}
  2412. return;
  2413. }
  2414. if (AI_retreatToCity())
  2415. {
  2416. return;
  2417. }
  2418. /************************************************************************************************/
  2419. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  2420. /* */
  2421. /* Worker AI */
  2422. /************************************************************************************************/
  2423. if( getGroup()->isStranded() )
  2424. {
  2425. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  2426. {
  2427. return;
  2428. }
  2429. }
  2430. /************************************************************************************************/
  2431. /* BETTER_BTS_AI_MOD END */
  2432. /************************************************************************************************/
  2433. if (AI_safety())
  2434. {
  2435. return;
  2436. }
  2437. getGroup()->pushMission(MISSION_SKIP);
  2438. return;
  2439. }
  2440. void CvUnitAI::AI_barbAttackMove()
  2441. {
  2442. PROFILE_FUNC();
  2443. if( gUnitLogLevel >= 2 )
  2444. {
  2445. logBBAI(" Stack %d (led by %S (%d), size %d) starting barbAttackMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  2446. }
  2447. // catch for wrong AI - units spawned through lair events maybe?
  2448. if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL"))
  2449. {
  2450. AI_setUnitAIType(UNITAI_PIRATE_SEA);
  2451. getGroup()->pushMission(MISSION_SKIP);
  2452. return;
  2453. }
  2454. if (isAnimal())
  2455. {
  2456. AI_setUnitAIType(UNITAI_ANIMAL);
  2457. getGroup()->pushMission(MISSION_SKIP);
  2458. return;
  2459. }
  2460. // ALN Notes: This is an experiment in mixing up barb behaivor, some will attack earlier, some later in terms of civ developement
  2461. // the more 'cautious' they are, the later they will step up their attacks against civilized lands
  2462. // basically it's all about not having them all hang back then attack at the same time all of a sudden, barbs aren't that coordinated
  2463. // but still give some breathing room early on
  2464. bool bRagingBarbs = GC.getGameINLINE().isOption(GAMEOPTION_RAGING_BARBARIANS);
  2465. bool bBarbWorld = GC.getGameINLINE().isOption(GAMEOPTION_BARBARIAN_WORLD);
  2466. bool bHero = AI_getUnitAIType() == UNITAI_HERO;
  2467. bool bAttack = AI_getUnitAIType() == UNITAI_ATTACK;
  2468. bool bAttackCity = AI_getUnitAIType() == UNITAI_ATTACK_CITY;
  2469. int iPillage = AI_getBirthmark2() % 10;
  2470. if (!isAlive())
  2471. {
  2472. iPillage = 0;
  2473. }
  2474. // pay attention to where we are
  2475. bool bFriendlyTerritory = false;
  2476. bool bEnemyTerritory = false;
  2477. if (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE())
  2478. {
  2479. if (!isEnemy(plot()->getTeam()))
  2480. {
  2481. bFriendlyTerritory = true;
  2482. }
  2483. else
  2484. {
  2485. bEnemyTerritory = true;
  2486. }
  2487. }
  2488. int iMaxFollowers;
  2489. int iLeadership = AI_getBarbLeadership(iMaxFollowers);
  2490. int iHeroAttMod = (bHero ? 10 + (AI_getBirthmark() % 15) : 0);
  2491. // This is a measure of how likely a given barb is likely to stay away from civs or else seek one out to attack or plunder
  2492. int iCaution = 2;
  2493. iCaution += AI_getBirthmark() % 7;
  2494. if (bHero)
  2495. {
  2496. // Barbarian Heros hang back till they level up typically
  2497. iCaution += 6 - getLevel();
  2498. }
  2499. // larger stacks more likely to attack civs
  2500. iCaution -= (getGroup()->getNumUnits() - 1);
  2501. // more aggressive (attack cities earlier) when raging barbarians is on
  2502. if (bRagingBarbs)
  2503. {
  2504. iCaution -= 2;
  2505. }
  2506. else if (bBarbWorld)
  2507. {
  2508. iCaution -= 1;
  2509. }
  2510. if (!isAlive())
  2511. {
  2512. iCaution = 0;
  2513. }
  2514. iCaution = std::max(0, iCaution);
  2515. // how likely they are to attack against poor odds
  2516. int iRecklessness = iHeroAttMod + (iPillage) - (int)pow((float)(GC.getGameINLINE().getSorenRandNum(100, "AI Barb")), 0.5f);
  2517. if (!isAlive())
  2518. {
  2519. iRecklessness -= 10;
  2520. }
  2521. // Aggression steps based on units caution level and number of civilized cities per player
  2522. bool bAggressive = (GC.getGameINLINE().getNumCivCities() > (GC.getGameINLINE().countCivPlayersAlive() * iCaution / 2));
  2523. bool bSemiAggressive = (GC.getGameINLINE().getNumCivCities() > (GC.getGameINLINE().countCivPlayersAlive() * iCaution / 3));
  2524. bool bPassiveAggressive = (GC.getGameINLINE().getNumCivCities() > (GC.getGameINLINE().countCivPlayersAlive() * iCaution / 4) || bEnemyTerritory);
  2525. // heros and aggressive units will wait till someone else starts defending the plot then move on
  2526. // otherwise switch UnitAIs
  2527. /*
  2528. if (!bHero && plot()->isLair(false, isAnimal()))
  2529. {
  2530. if (plot()->plotCount(PUF_isUnitAIType, UNITAI_LAIRGUARDIAN, -1, (PlayerTypes)BARBARIAN_PLAYER) == 0)
  2531. {
  2532. // ToDo, split off a unit to guard it if we are in a group
  2533. if ((!bHero || iCaution >= 4) && getGroup()->getNumUnits() == 1)
  2534. {
  2535. AI_setUnitAIType(UNITAI_LAIRGUARDIAN);
  2536. getGroup()->pushMission(MISSION_SKIP);
  2537. return;
  2538. }
  2539. else // wait till we have a guard unit
  2540. {
  2541. getGroup()->pushMission(MISSION_SKIP);
  2542. return;
  2543. }
  2544. }
  2545. }
  2546. */
  2547. // Heros shouldn't be guarding cities or goodies
  2548. if (!bHero && ((!bAttackCity || !bAttack) && iCaution > 4))
  2549. {
  2550. if (getDomainType() == DOMAIN_LAND)
  2551. {
  2552. if (AI_guardCity(false, true, 1))
  2553. {
  2554. return;
  2555. }
  2556. }
  2557. if (plot()->isGoody())
  2558. {
  2559. if (plot()->plotCount(PUF_isUnitAIType, UNITAI_ATTACK, -1, getOwnerINLINE()) == 1)
  2560. {
  2561. getGroup()->pushMission(MISSION_SKIP);
  2562. return;
  2563. }
  2564. }
  2565. }
  2566. // new grouping code
  2567. // higher leadership barbs will wait at longer path lengths
  2568. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  2569. int iJoiners = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), (iLeadership > 7 ? 3 : 2));
  2570. // wait for joiners
  2571. int iFollowers = getGroup()->getNumUnits() - 1;
  2572. if (iLeadership > 5)
  2573. {
  2574. if (iJoiners > 0 && !bEnemyTerritory)
  2575. {
  2576. getGroup()->pushMission(MISSION_SKIP);
  2577. return;
  2578. }
  2579. }
  2580. // look for higher leadership barbs to join with
  2581. if (iLeadership <= 8 && (bSemiAggressive || bAggressive))
  2582. {
  2583. if (bEnemyTerritory)
  2584. {
  2585. if (AI_groupBarbLeader(1))
  2586. {
  2587. return;
  2588. }
  2589. }
  2590. else
  2591. {
  2592. if (AI_groupBarbLeader(2))
  2593. {
  2594. return;
  2595. }
  2596. }
  2597. }
  2598. // Pillaging
  2599. if (isAlive())
  2600. {
  2601. if (GC.getGameINLINE().getSorenRandNum(20, "AI Barb") + iPillage >= 15)
  2602. {
  2603. if (AI_pillageRange(1))
  2604. {
  2605. return;
  2606. }
  2607. }
  2608. }
  2609. // General Attack on adjacent units
  2610. if (AI_anyAttack(1, std::max(10, 20 + iRecklessness)))
  2611. {
  2612. return;
  2613. }
  2614. // don't wander aimlessly in Clan territory, please
  2615. if (bFriendlyTerritory)
  2616. {
  2617. if (AI_goToTargetCity(0, 12))
  2618. {
  2619. return;
  2620. }
  2621. if (AI_retreatToCity())
  2622. {
  2623. return;
  2624. }
  2625. }
  2626. // Aggressive movements (actively seek out distant cities)
  2627. if (bAggressive)
  2628. {
  2629. // high pillage barbs get another go at this check
  2630. if (iPillage > 5 && isAlive())
  2631. {
  2632. if (GC.getGameINLINE().getSorenRandNum(20, "AI Barb") + iPillage >= 15)
  2633. {
  2634. if (AI_pillageRange(1))
  2635. {
  2636. return;
  2637. }
  2638. }
  2639. }
  2640. if (AI_cityAttack(1, std::max(8, 15 + iRecklessness)))
  2641. {
  2642. return;
  2643. }
  2644. if (isAlive())
  2645. {
  2646. if (AI_pillageRange(3))
  2647. {
  2648. return;
  2649. }
  2650. }
  2651. if (AI_cityAttack(2, std::max(5, 10 + iRecklessness), true))
  2652. {
  2653. return;
  2654. }
  2655. if (AI_goToTargetCity(0, 12))
  2656. {
  2657. return;
  2658. }
  2659. }
  2660. // Semi-Aggressive Movements (attack cities if nearby)
  2661. if (bSemiAggressive)
  2662. {
  2663. // high pillage barbs get another go at this check
  2664. if (iPillage > 5 && isAlive())
  2665. {
  2666. if (GC.getGameINLINE().getSorenRandNum(20, "AI Barb") + iPillage >= 15)
  2667. {
  2668. if (AI_pillageRange(1))
  2669. {
  2670. return;
  2671. }
  2672. }
  2673. }
  2674. if (AI_cityAttack(1, std::max(8, 15 + iRecklessness)))
  2675. {
  2676. return;
  2677. }
  2678. if (isAlive())
  2679. {
  2680. if (AI_pillageRange(3))
  2681. {
  2682. return;
  2683. }
  2684. }
  2685. if (AI_cityAttack(1, std::max(5, 10 + iRecklessness)))
  2686. {
  2687. return;
  2688. }
  2689. if (AI_goToTargetCity(0, 4))
  2690. {
  2691. return;
  2692. }
  2693. }
  2694. // Cautious Movements (only cause trouble if they stumble into it)
  2695. if (bPassiveAggressive)
  2696. {
  2697. if (isAlive())
  2698. {
  2699. if (AI_pillageRange(2))
  2700. {
  2701. return;
  2702. }
  2703. }
  2704. if (AI_cityAttack(1, std::max(5, 10 + iRecklessness)))
  2705. {
  2706. return;
  2707. }
  2708. }
  2709. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 1))
  2710. {
  2711. return;
  2712. }
  2713. if (AI_heal())
  2714. {
  2715. return;
  2716. }
  2717. if (!bHero && (getDomainType() == DOMAIN_LAND))
  2718. {
  2719. if (AI_guardCity(false, true, 2))
  2720. {
  2721. return;
  2722. }
  2723. }
  2724. /* if (AI_groupBarbLeader(3))
  2725. {
  2726. return;
  2727. } */
  2728. if (AI_patrol())
  2729. {
  2730. return;
  2731. }
  2732. if (AI_retreatToCity())
  2733. {
  2734. return;
  2735. }
  2736. if (AI_safety())
  2737. {
  2738. return;
  2739. }
  2740. getGroup()->pushMission(MISSION_SKIP);
  2741. return;
  2742. }
  2743. void CvUnitAI::AI_attackMove()
  2744. {
  2745. logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_attackMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  2746. PROFILE_FUNC();
  2747. if (GET_PLAYER(getOwnerINLINE()).getNumCities() == 0)
  2748. {
  2749. if (AI_shadow(UNITAI_SETTLE, -1, -1, false, false, 5))
  2750. {
  2751. if( gUnitLogLevel >= 3 ) {logBBAI( " ... defend settler" );}
  2752. return;
  2753. }
  2754. }
  2755. /************************************************************************************************/
  2756. /* BETTER_BTS_AI_MOD 05/14/10 jdog5000 */
  2757. /* */
  2758. /* Unit AI, Settler AI, Efficiency */
  2759. /************************************************************************************************/
  2760. bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
  2761. bool bLandWar = GET_PLAYER(getOwnerINLINE()).AI_isLandWar(area()); // K-Mod
  2762. if( getGroup()->getNumUnits() > 2 )
  2763. {
  2764. UnitAITypes eGroupAI = getGroup()->getHeadUnitAI();
  2765. if( eGroupAI == AI_getUnitAIType() )
  2766. {
  2767. if( plot()->getOwnerINLINE() == getOwnerINLINE() && !bDanger )
  2768. {
  2769. // Shouldn't have groups of > 2 attack units
  2770. if( getGroup()->countNumUnitAIType(UNITAI_ATTACK) > 2 )
  2771. {
  2772. getGroup()->AI_separate(); // will change group
  2773. FAssert( eGroupAI == getGroup()->getHeadUnitAI() );
  2774. }
  2775. // Should never have attack city group lead by attack unit
  2776. if( getGroup()->countNumUnitAIType(UNITAI_ATTACK_CITY) > 0 )
  2777. {
  2778. getGroup()->AI_separateAI(UNITAI_ATTACK_CITY); // will change group
  2779. // Since ATTACK can try to joing ATTACK_CITY again, need these units to
  2780. // take a break to let ATTACK_CITY group move and avoid hang
  2781. getGroup()->pushMission(MISSION_SKIP);
  2782. if( gUnitLogLevel >= 3 ) {logBBAI( " ... take a break while ATTACK_CITY stack move along" );}
  2783. return;
  2784. }
  2785. }
  2786. }
  2787. }
  2788. // Attack choking units
  2789. if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() && bDanger )
  2790. {
  2791. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  2792. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  2793. if( iOurDefense < 3*iEnemyOffense )
  2794. {
  2795. if (AI_guardCity(true))
  2796. {
  2797. if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> guard city" );}
  2798. return;
  2799. }
  2800. }
  2801. if( iOurDefense > 2*iEnemyOffense )
  2802. {
  2803. if (AI_anyAttack(2, 55))
  2804. {
  2805. if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack!" );}
  2806. return;
  2807. }
  2808. }
  2809. if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, false))
  2810. {
  2811. if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> merge" );}
  2812. return;
  2813. }
  2814. if( iOurDefense > 2*iEnemyOffense )
  2815. {
  2816. if (AI_anyAttack(2, 30))
  2817. {
  2818. if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack!" );}
  2819. return;
  2820. }
  2821. }
  2822. }
  2823. {
  2824. PROFILE("CvUnitAI::AI_attackMove() 1");
  2825. // Guard a city we're in if it needs it
  2826. if (AI_guardCity(true))
  2827. {
  2828. if( gUnitLogLevel >= 3 ) {logBBAI( " ... guard city" );}
  2829. return;
  2830. }
  2831. if( !(plot()->isOwned()) )
  2832. {
  2833. // Group with settler after naval drop
  2834. if( AI_groupMergeRange(UNITAI_SETTLE, 2, true, false, false) )
  2835. {
  2836. if( gUnitLogLevel >= 3 ) {logBBAI( " ... group with settler (after naval drop?)" );}
  2837. return;
  2838. }
  2839. }
  2840. if( !(plot()->isOwned()) || (plot()->getOwnerINLINE() == getOwnerINLINE()) )
  2841. {
  2842. if( area()->getCitiesPerPlayer(getOwnerINLINE()) > GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(area(), UNITAI_CITY_DEFENSE) )
  2843. {
  2844. // Defend colonies in new world
  2845. if (AI_guardCity(true, true, 3))
  2846. {
  2847. if( gUnitLogLevel >= 3 ) {logBBAI( " ... defend colonies in new world" );}
  2848. return;
  2849. }
  2850. }
  2851. }
  2852. if (AI_heal(30, 1))
  2853. {
  2854. if( gUnitLogLevel >= 3 ) {logBBAI( " ... heal" );}
  2855. return;
  2856. }
  2857. if (!bDanger)
  2858. {
  2859. if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 3, true))
  2860. {
  2861. if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> group with settler" );}
  2862. return;
  2863. }
  2864. if (AI_group(UNITAI_SETTLE, 2, -1, -1, false, false, false, 3, true))
  2865. {
  2866. if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> group with settler" );}
  2867. return;
  2868. }
  2869. if( AI_guardFortMinDefender( true ) ) {
  2870. if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> defend fort" );}
  2871. return;
  2872. }
  2873. }
  2874. if (AI_guardCityAirlift())
  2875. {
  2876. if( gUnitLogLevel >= 3 ) {logBBAI( " ... AI_guardCityAirlift" );}
  2877. return;
  2878. }
  2879. if (AI_guardCity(false, true, 1))
  2880. {
  2881. if( gUnitLogLevel >= 3 ) {logBBAI( " ... guard city" );}
  2882. return;
  2883. }
  2884. //join any city attacks in progress
  2885. if (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE())
  2886. {
  2887. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
  2888. {
  2889. if( gUnitLogLevel >= 3 ) {logBBAI( " ... join city attack in progress" );}
  2890. return;
  2891. }
  2892. }
  2893. AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
  2894. if (plot()->isCity())
  2895. {
  2896. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  2897. {
  2898. if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
  2899. {
  2900. if (AI_offensiveAirlift())
  2901. {
  2902. if( gUnitLogLevel >= 3 ) {logBBAI( " ... offensive airlift" );}
  2903. return;
  2904. }
  2905. }
  2906. }
  2907. }
  2908. if (bDanger)
  2909. {
  2910. if (AI_cityAttack(1, 55))
  2911. {
  2912. if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack city!" );}
  2913. return;
  2914. }
  2915. if (AI_anyAttack(1, 65))
  2916. {
  2917. if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack!" );}
  2918. return;
  2919. }
  2920. if (collateralDamage() > 0)
  2921. {
  2922. if (AI_anyAttack(1, 45, 3))
  2923. {
  2924. if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack!" );}
  2925. return;
  2926. }
  2927. }
  2928. }
  2929. if (!noDefensiveBonus())
  2930. {
  2931. if (AI_guardCity(false, false))
  2932. {
  2933. if( gUnitLogLevel >= 3 ) {logBBAI( " ... guard city" );}
  2934. return;
  2935. }
  2936. }
  2937. if (!bDanger)
  2938. {
  2939. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  2940. {
  2941. bool bAssault = ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_MASSING) || (eAreaAIType == AREAAI_ASSAULT_ASSIST));
  2942. if ( bAssault )
  2943. {
  2944. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  2945. {
  2946. if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> load" );}
  2947. return;
  2948. }
  2949. }
  2950. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, -1, 1, MOVE_SAFE_TERRITORY, 3))
  2951. {
  2952. if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> load" );}
  2953. return;
  2954. }
  2955. //bool bLandWar = ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
  2956. if (!bLandWar)
  2957. {
  2958. // Fill transports before starting new one, but not just full of our unit ai
  2959. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
  2960. {
  2961. if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> load" );}
  2962. return;
  2963. }
  2964. // Pick new transport which has space for other unit ai types to join
  2965. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, 2, -1, -1, MOVE_SAFE_TERRITORY, 4))
  2966. {
  2967. if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> load" );}
  2968. return;
  2969. }
  2970. }
  2971. if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) > 0) // LFGR_TODO: I don't really understand this
  2972. {
  2973. if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> wait (?)" );}
  2974. getGroup()->pushMission(MISSION_SKIP);
  2975. return;
  2976. }
  2977. }
  2978. }
  2979. // Allow larger groups if outside territory
  2980. if( getGroup()->getNumUnits() < 3 )
  2981. {
  2982. if( plot()->isOwned() && GET_TEAM(getTeam()).isAtWar(plot()->getTeam()) )
  2983. {
  2984. if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, true))
  2985. {
  2986. if( gUnitLogLevel >= 3 ) {logBBAI( " ... outside territory, merge" );}
  2987. return;
  2988. }
  2989. }
  2990. }
  2991. if (AI_goody(3))
  2992. {
  2993. if( gUnitLogLevel >= 3 ) {logBBAI( " ... get goody" );}
  2994. return;
  2995. }
  2996. if (AI_anyAttack(1, 70))
  2997. {
  2998. if( gUnitLogLevel >= 3 ) {logBBAI( " ... attack!" );}
  2999. return;
  3000. }
  3001. }
  3002. {
  3003. PROFILE("CvUnitAI::AI_attackMove() 2");
  3004. if (bDanger)
  3005. {
  3006. if (AI_pillageRange(1, 20))
  3007. {
  3008. return;
  3009. }
  3010. if (AI_cityAttack(1, 35))
  3011. {
  3012. return;
  3013. }
  3014. if (AI_anyAttack(1, 45))
  3015. {
  3016. return;
  3017. }
  3018. if (AI_pillageRange(3, 20))
  3019. {
  3020. return;
  3021. }
  3022. if( getGroup()->getNumUnits() < 4 )
  3023. {
  3024. if (AI_choke(1))
  3025. {
  3026. return;
  3027. }
  3028. }
  3029. if (AI_cityAttack(4, 30))
  3030. {
  3031. return;
  3032. }
  3033. if (AI_anyAttack(2, 40))
  3034. {
  3035. return;
  3036. }
  3037. }
  3038. if (!isEnemy(plot()->getTeam()))
  3039. {
  3040. if (AI_heal())
  3041. {
  3042. return;
  3043. }
  3044. }
  3045. /************************************************************************************************/
  3046. /* REVOLUTION_MOD 02/11/09 jdog5000 */
  3047. /* */
  3048. /* Revolution AI */
  3049. /************************************************************************************************/
  3050. // Change grouping rules shortly after civ creation
  3051. if( GET_PLAYER(getOwnerINLINE()).getFreeUnitCountdown() > 0 )
  3052. {
  3053. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, false, true, true))
  3054. {
  3055. return;
  3056. }
  3057. }
  3058. /************************************************************************************************/
  3059. /* REVOLUTION_MOD END */
  3060. /************************************************************************************************/
  3061. if ((GET_PLAYER(getOwnerINLINE()).AI_getNumAIUnits(UNITAI_CITY_DEFENSE) > 0) || (GET_TEAM(getTeam()).getAtWarCount(true) > 0))
  3062. {
  3063. // BBAI TODO: If we're fast, maybe shadow an attack city stack and pillage off of it
  3064. bool bIgnoreFaster = false;
  3065. if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
  3066. {
  3067. if (area()->getAreaAIType(getTeam()) != AREAAI_ASSAULT)
  3068. {
  3069. bIgnoreFaster = true;
  3070. }
  3071. }
  3072. if (AI_group(UNITAI_ATTACK_CITY, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 5))
  3073. {
  3074. return;
  3075. }
  3076. if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, true, true, false, /*iMaxPath*/ 4))
  3077. {
  3078. return;
  3079. }
  3080. // BBAI TODO: Need group to be fast, need to ignore slower groups
  3081. //if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_FASTMOVERS))
  3082. //{
  3083. // if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 4, /*iMaxOwnUnitAI*/ 1, -1, true, false, false, /*iMaxPath*/ 3))
  3084. // {
  3085. // return;
  3086. // }
  3087. //}
  3088. if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, true, false, false, /*iMaxPath*/ 1))
  3089. {
  3090. return;
  3091. }
  3092. }
  3093. if (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
  3094. {
  3095. if (getGroup()->getNumUnits() > 1)
  3096. {
  3097. //if (AI_targetCity())
  3098. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12))
  3099. {
  3100. return;
  3101. }
  3102. }
  3103. }
  3104. else if( area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE )
  3105. {
  3106. if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0)
  3107. {
  3108. if (getGroup()->getNumUnits() >= GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getBarbarianInitialDefenders())
  3109. {
  3110. if (AI_goToTargetBarbCity(10))
  3111. {
  3112. return;
  3113. }
  3114. }
  3115. }
  3116. }
  3117. if (AI_guardCity(false, true, 3))
  3118. {
  3119. return;
  3120. }
  3121. if ((GET_PLAYER(getOwnerINLINE()).getNumCities() > 1) && (getGroup()->getNumUnits() == 1))
  3122. {
  3123. if (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE)
  3124. {
  3125. if (area()->getNumUnrevealedTiles(getTeam()) > 0)
  3126. {
  3127. if (GET_PLAYER(getOwnerINLINE()).AI_areaMissionAIs(area(), MISSIONAI_EXPLORE, getGroup()) < (GET_PLAYER(getOwnerINLINE()).AI_neededExplorers(area()) + 1))
  3128. {
  3129. if (AI_exploreRange(3))
  3130. {
  3131. return;
  3132. }
  3133. if (AI_explore())
  3134. {
  3135. return;
  3136. }
  3137. }
  3138. }
  3139. }
  3140. }
  3141. if (AI_protect(35, 5))
  3142. {
  3143. return;
  3144. }
  3145. if (AI_offensiveAirlift())
  3146. {
  3147. return;
  3148. }
  3149. if (!bDanger && (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE))
  3150. {
  3151. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  3152. {
  3153. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
  3154. {
  3155. return;
  3156. }
  3157. if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) && !(getGroup()->isHasPathToAreaEnemyCity(false)) )
  3158. {
  3159. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  3160. {
  3161. return;
  3162. }
  3163. }
  3164. }
  3165. }
  3166. if (AI_defend())
  3167. {
  3168. return;
  3169. }
  3170. if (AI_travelToUpgradeCity())
  3171. {
  3172. return;
  3173. }
  3174. if( getGroup()->isStranded() )
  3175. {
  3176. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  3177. {
  3178. return;
  3179. }
  3180. }
  3181. if( !bDanger && !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
  3182. {
  3183. // If no other desireable actions, wait for pickup
  3184. getGroup()->pushMission(MISSION_SKIP);
  3185. return;
  3186. }
  3187. if( getGroup()->getNumUnits() < 4 )
  3188. {
  3189. if (AI_patrol())
  3190. {
  3191. return;
  3192. }
  3193. }
  3194. if (AI_retreatToCity())
  3195. {
  3196. return;
  3197. }
  3198. if (AI_safety())
  3199. {
  3200. return;
  3201. }
  3202. }
  3203. getGroup()->pushMission(MISSION_SKIP);
  3204. return;
  3205. /************************************************************************************************/
  3206. /* BETTER_BTS_AI_MOD END */
  3207. /************************************************************************************************/
  3208. }
  3209. void CvUnitAI::AI_paratrooperMove()
  3210. {
  3211. PROFILE_FUNC();
  3212. bool bHostile = (plot()->isOwned() && isPotentialEnemy(plot()->getTeam()));
  3213. if (!bHostile)
  3214. {
  3215. if (AI_guardCity(true))
  3216. {
  3217. return;
  3218. }
  3219. if (plot()->getTeam() == getTeam())
  3220. {
  3221. if (plot()->isCity())
  3222. {
  3223. if (AI_heal(30, 1))
  3224. {
  3225. return;
  3226. }
  3227. }
  3228. AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
  3229. //bool bLandWar = ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
  3230. bool bLandWar = GET_PLAYER(getOwnerINLINE()).AI_isLandWar(area()); // K-Mod
  3231. if (!bLandWar)
  3232. {
  3233. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, 0, MOVE_SAFE_TERRITORY, 4))
  3234. {
  3235. return;
  3236. }
  3237. }
  3238. }
  3239. if (AI_guardCity(false, true, 1))
  3240. {
  3241. return;
  3242. }
  3243. }
  3244. if (AI_cityAttack(1, 45))
  3245. {
  3246. return;
  3247. }
  3248. if (AI_anyAttack(1, 55))
  3249. {
  3250. return;
  3251. }
  3252. if (!bHostile)
  3253. {
  3254. if (AI_paradrop(getDropRange()))
  3255. {
  3256. return;
  3257. }
  3258. if (AI_offensiveAirlift())
  3259. {
  3260. return;
  3261. }
  3262. if (AI_moveToStagingCity())
  3263. {
  3264. return;
  3265. }
  3266. if (AI_guardFort(true))
  3267. {
  3268. return;
  3269. }
  3270. if (AI_guardCityAirlift())
  3271. {
  3272. return;
  3273. }
  3274. }
  3275. if (collateralDamage() > 0)
  3276. {
  3277. if (AI_anyAttack(1, 45, 3))
  3278. {
  3279. return;
  3280. }
  3281. }
  3282. if (AI_pillageRange(1, 15))
  3283. {
  3284. return;
  3285. }
  3286. if (bHostile)
  3287. {
  3288. if (AI_choke(1))
  3289. {
  3290. return;
  3291. }
  3292. }
  3293. if (AI_heal())
  3294. {
  3295. return;
  3296. }
  3297. if (AI_retreatToCity())
  3298. {
  3299. return;
  3300. }
  3301. /************************************************************************************************/
  3302. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  3303. /* */
  3304. /* Unit AI */
  3305. /************************************************************************************************/
  3306. //if (AI_protect(35))
  3307. if (AI_protect(35, 5))
  3308. {
  3309. return;
  3310. }
  3311. if( getGroup()->isStranded() )
  3312. {
  3313. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  3314. {
  3315. return;
  3316. }
  3317. }
  3318. /************************************************************************************************/
  3319. /* BETTER_BTS_AI_MOD END */
  3320. /************************************************************************************************/
  3321. if (AI_safety())
  3322. {
  3323. return;
  3324. }
  3325. getGroup()->pushMission(MISSION_SKIP);
  3326. return;
  3327. }
  3328. /************************************************************************************************/
  3329. /* BETTER_BTS_AI_MOD 04/02/10 jdog5000 */
  3330. /* */
  3331. /* War tactics AI, Barbarian AI */
  3332. /************************************************************************************************/
  3333. void CvUnitAI::AI_attackCityMove()
  3334. {
  3335. PROFILE_FUNC();
  3336. logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_attackCityMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  3337. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  3338. AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
  3339. //bool bLandWar = !isBarbarian() && ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
  3340. bool bLandWar = !isBarbarian() && kOwner.AI_isLandWar(area()); // K-Mod
  3341. bool bAssault = !isBarbarian() && ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) || (eAreaAIType == AREAAI_ASSAULT_MASSING));
  3342. bool bTurtle = kOwner.AI_isDoStrategy(AI_STRATEGY_TURTLE);
  3343. bool bAlert1 = kOwner.AI_isDoStrategy(AI_STRATEGY_ALERT1);
  3344. bool bIgnoreFaster = false;
  3345. if (kOwner.AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
  3346. {
  3347. if (!bAssault && area()->getCitiesPerPlayer(getOwnerINLINE()) > 0)
  3348. {
  3349. bIgnoreFaster = true;
  3350. }
  3351. }
  3352. // Super Forts begin *AI_offense* - allow stack to split after capturing a fort in addition to cities
  3353. bool bInCity = plot()->isCity(true);
  3354. //bool bInCity = plot()->isCity(); // Original Code
  3355. // Super Forts end
  3356. if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
  3357. {
  3358. // force heal if we in our own city and damaged
  3359. // can we remove this or call AI_heal here?
  3360. if ((getGroup()->getNumUnits() == 1) && (getDamage() > 0))
  3361. {
  3362. getGroup()->pushMission(MISSION_HEAL);
  3363. return;
  3364. }
  3365. if( bIgnoreFaster )
  3366. {
  3367. // BBAI TODO: split out slow units ... will need to test to make sure this doesn't cause loops
  3368. }
  3369. // Super Forts begin *AI_offense* - allow stack to split after capturing a fort in addition to cities
  3370. if (plot()->getOwnershipDuration() <= 1)
  3371. //if ((GC.getGame().getGameTurn() - plot()->getPlotCity()->getGameTurnAcquired()) <= 1) // Original Code
  3372. // Super Forts end
  3373. {
  3374. CvSelectionGroup* pOldGroup = getGroup();
  3375. pOldGroup->AI_separateNonAI(UNITAI_ATTACK_CITY);
  3376. if (pOldGroup != getGroup())
  3377. {
  3378. return;
  3379. }
  3380. }
  3381. if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
  3382. {
  3383. if (AI_offensiveAirlift())
  3384. {
  3385. return;
  3386. }
  3387. }
  3388. }
  3389. bool bAtWar = isEnemy(plot()->getTeam());
  3390. bool bHuntBarbs = false;
  3391. if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0 && !isBarbarian())
  3392. {
  3393. if ((eAreaAIType != AREAAI_OFFENSIVE) && (eAreaAIType != AREAAI_DEFENSIVE) && !bAlert1 && !bTurtle)
  3394. {
  3395. bHuntBarbs = true;
  3396. }
  3397. }
  3398. bool bReadyToAttack = false;
  3399. if( !bTurtle )
  3400. {
  3401. bReadyToAttack = ((getGroup()->getNumUnits() >= ((bHuntBarbs) ? 3 : AI_stackOfDoomExtra())));
  3402. }
  3403. if( isBarbarian() )
  3404. {
  3405. bLandWar = (area()->getNumCities() - area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0);
  3406. bReadyToAttack = (getGroup()->getNumUnits() >= 3);
  3407. }
  3408. if( bReadyToAttack )
  3409. {
  3410. // Check that stack has units which can capture cities
  3411. bReadyToAttack = false;
  3412. int iCityCaptureCount = 0;
  3413. CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
  3414. while (pUnitNode != NULL && !bReadyToAttack)
  3415. {
  3416. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  3417. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  3418. if( !pLoopUnit->isOnlyDefensive() )
  3419. {
  3420. if( !(pLoopUnit->isNoCapture()) && (pLoopUnit->combatLimit() >= 100) )
  3421. {
  3422. iCityCaptureCount++;
  3423. if( iCityCaptureCount > 5 || 3*iCityCaptureCount > getGroup()->getNumUnits() )
  3424. {
  3425. bReadyToAttack = true;
  3426. }
  3427. }
  3428. }
  3429. }
  3430. }
  3431. if (AI_guardCity(false, false))
  3432. {
  3433. if( bReadyToAttack && (eAreaAIType != AREAAI_DEFENSIVE))
  3434. {
  3435. CvSelectionGroup* pOldGroup = getGroup();
  3436. pOldGroup->AI_separateNonAI(UNITAI_ATTACK_CITY);
  3437. }
  3438. return;
  3439. }
  3440. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 0, true, true, bIgnoreFaster))
  3441. {
  3442. return;
  3443. }
  3444. CvCity* pTargetCity = NULL;
  3445. if( isBarbarian() )
  3446. {
  3447. pTargetCity = AI_pickTargetCity(0, 12);
  3448. }
  3449. else
  3450. {
  3451. // BBAI TODO: Find some way of reliably targetting nearby cities with less defense ...
  3452. pTargetCity = AI_pickTargetCity(0, MAX_INT, bHuntBarbs);
  3453. }
  3454. if( pTargetCity != NULL )
  3455. {
  3456. int iStepDistToTarget = stepDistance(pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), getX_INLINE(), getY_INLINE());
  3457. int iAttackRatio = std::max(100, GC.getBBAI_ATTACK_CITY_STACK_RATIO());
  3458. if( isBarbarian() )
  3459. {
  3460. iAttackRatio = 80;
  3461. }
  3462. int iComparePostBombard = 0;
  3463. // AI gets a 1-tile sneak peak to compensate for lack of memory
  3464. if( iStepDistToTarget <= 2 || pTargetCity->isVisible(getTeam(),false) )
  3465. {
  3466. iComparePostBombard = getGroup()->AI_compareStacks(pTargetCity->plot(), true, true, true);
  3467. int iDefenseModifier = pTargetCity->getDefenseModifier(true);
  3468. int iBombardTurns = getGroup()->getBombardTurns(pTargetCity);
  3469. iDefenseModifier *= std::max(0, 20 - iBombardTurns);
  3470. iDefenseModifier /= 20;
  3471. iComparePostBombard *= 100 + std::max(0, iDefenseModifier);
  3472. iComparePostBombard /= 100;
  3473. }
  3474. if( iStepDistToTarget <= 2 )
  3475. {
  3476. if( iComparePostBombard < iAttackRatio )
  3477. {
  3478. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
  3479. {
  3480. return;
  3481. }
  3482. int iOurOffense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),1,false,false,true);
  3483. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pTargetCity->plot(),2,false,false);
  3484. // If in danger, seek defensive ground
  3485. if( 4*iOurOffense < 3*iEnemyOffense )
  3486. {
  3487. if( AI_choke(1, true) )
  3488. {
  3489. return;
  3490. }
  3491. }
  3492. }
  3493. if (iStepDistToTarget == 1)
  3494. {
  3495. // If next to target city and we would attack after bombarding down defenses,
  3496. // or if defenses have crept up past half
  3497. if( (iComparePostBombard >= iAttackRatio) || (pTargetCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE() * 1) / 2)) )
  3498. {
  3499. if( (iComparePostBombard < std::max(150, GC.getDefineINT("BBAI_SKIP_BOMBARD_MIN_STACK_RATIO"))) )
  3500. {
  3501. // Move to good tile to attack from unless we're way more powerful
  3502. if( AI_goToTargetCity(0,1,pTargetCity) )
  3503. {
  3504. return;
  3505. }
  3506. }
  3507. // Bombard may skip if stack is powerful enough
  3508. if (AI_bombardCity())
  3509. {
  3510. return;
  3511. }
  3512. //stack attack
  3513. if (getGroup()->getNumUnits() > 1)
  3514. {
  3515. // BBAI TODO: What is right ratio?
  3516. if (AI_stackAttackCity(1, iAttackRatio, true))
  3517. {
  3518. return;
  3519. }
  3520. }
  3521. // If not strong enough alone, merge if another stack is nearby
  3522. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
  3523. {
  3524. return;
  3525. }
  3526. if( getGroup()->getNumUnits() == 1 )
  3527. {
  3528. if( AI_cityAttack(1, 50) )
  3529. {
  3530. return;
  3531. }
  3532. }
  3533. }
  3534. }
  3535. if( iComparePostBombard < iAttackRatio )
  3536. {
  3537. // If not strong enough, pillage around target city without exposing ourselves
  3538. if( AI_pillageRange(0) )
  3539. {
  3540. return;
  3541. }
  3542. if( AI_anyAttack(1, 60, 0, false) )
  3543. {
  3544. return;
  3545. }
  3546. if (AI_heal(30, 1))
  3547. {
  3548. return;
  3549. }
  3550. // Pillage around enemy city
  3551. if( AI_pillageAroundCity(pTargetCity, 11, 3) )
  3552. {
  3553. return;
  3554. }
  3555. if( AI_pillageAroundCity(pTargetCity, 0, 5) )
  3556. {
  3557. return;
  3558. }
  3559. if( AI_choke(1) )
  3560. {
  3561. return;
  3562. }
  3563. }
  3564. else
  3565. {
  3566. if( AI_goToTargetCity(0,4,pTargetCity) )
  3567. {
  3568. return;
  3569. }
  3570. }
  3571. }
  3572. }
  3573. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
  3574. {
  3575. return;
  3576. }
  3577. if (AI_heal(30, 1))
  3578. {
  3579. return;
  3580. }
  3581. // BBAI TODO: Stack v stack combat ... definitely want to do in own territory, but what about enemy territory?
  3582. if (collateralDamage() > 0 && plot()->getOwnerINLINE() == getOwnerINLINE())
  3583. {
  3584. if (AI_anyAttack(1, 45, 3, false))
  3585. {
  3586. return;
  3587. }
  3588. if( !bReadyToAttack )
  3589. {
  3590. if (AI_anyAttack(1, 25, 5, false))
  3591. {
  3592. return;
  3593. }
  3594. }
  3595. }
  3596. if (AI_anyAttack(1, 60, 0, false))
  3597. {
  3598. return;
  3599. }
  3600. if (bAtWar && (getGroup()->getNumUnits() <= 2))
  3601. {
  3602. if (AI_pillageRange(3, 11))
  3603. {
  3604. return;
  3605. }
  3606. if (AI_pillageRange(1))
  3607. {
  3608. return;
  3609. }
  3610. }
  3611. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  3612. {
  3613. if (!bLandWar)
  3614. {
  3615. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  3616. {
  3617. return;
  3618. }
  3619. }
  3620. if( bReadyToAttack )
  3621. {
  3622. // Wait for units about to join our group
  3623. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  3624. int iJoiners = kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
  3625. if( (iJoiners*5) > getGroup()->getNumUnits() )
  3626. {
  3627. getGroup()->pushMission(MISSION_SKIP);
  3628. return;
  3629. }
  3630. }
  3631. else
  3632. {
  3633. if( !isBarbarian() && (eAreaAIType == AREAAI_DEFENSIVE) )
  3634. {
  3635. // Use smaller attack city stacks on defense
  3636. if (AI_guardCity(false, true, 3))
  3637. {
  3638. return;
  3639. }
  3640. }
  3641. if( bTurtle )
  3642. {
  3643. if (AI_guardCity(false, true, 7))
  3644. {
  3645. return;
  3646. }
  3647. }
  3648. int iTargetCount = kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
  3649. if ((iTargetCount * 5) > getGroup()->getNumUnits())
  3650. {
  3651. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  3652. int iJoiners = kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
  3653. if( (iJoiners*5) > getGroup()->getNumUnits() )
  3654. {
  3655. getGroup()->pushMission(MISSION_SKIP);
  3656. return;
  3657. }
  3658. if (AI_moveToStagingCity())
  3659. {
  3660. return;
  3661. }
  3662. }
  3663. }
  3664. }
  3665. if (AI_heal(50, 3))
  3666. {
  3667. return;
  3668. }
  3669. if (!bAtWar)
  3670. {
  3671. if (AI_heal())
  3672. {
  3673. return;
  3674. }
  3675. if ((getGroup()->getNumUnits() == 1) && (getTeam() != plot()->getTeam()))
  3676. {
  3677. if (AI_retreatToCity())
  3678. {
  3679. return;
  3680. }
  3681. }
  3682. }
  3683. if (!bReadyToAttack && !noDefensiveBonus())
  3684. {
  3685. if (AI_guardCity(false, false))
  3686. {
  3687. return;
  3688. }
  3689. }
  3690. bool bAnyWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
  3691. if (bReadyToAttack)
  3692. {
  3693. if( isBarbarian() )
  3694. {
  3695. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12))
  3696. {
  3697. return;
  3698. }
  3699. if (AI_pillageRange(3, 11))
  3700. {
  3701. return;
  3702. }
  3703. if (AI_pillageRange(1))
  3704. {
  3705. return;
  3706. }
  3707. }
  3708. else if (bHuntBarbs && AI_goToTargetBarbCity((bAnyWarPlan ? 7 : 12)))
  3709. {
  3710. return;
  3711. }
  3712. else if (bLandWar && pTargetCity != NULL)
  3713. {
  3714. // Before heading out, check whether to wait to allow unit upgrades
  3715. if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
  3716. {
  3717. if( !kOwner.AI_isFinancialTrouble() )
  3718. {
  3719. // Check if stack has units which can upgrade
  3720. int iNeedUpgradeCount = 0;
  3721. CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
  3722. while (pUnitNode != NULL)
  3723. {
  3724. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  3725. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  3726. if( pLoopUnit->getUpgradeCity(false) != NULL )
  3727. {
  3728. iNeedUpgradeCount++;
  3729. if( 8*iNeedUpgradeCount > getGroup()->getNumUnits() )
  3730. {
  3731. getGroup()->pushMission(MISSION_SKIP);
  3732. return;
  3733. }
  3734. }
  3735. }
  3736. }
  3737. }
  3738. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 5, pTargetCity))
  3739. {
  3740. return;
  3741. }
  3742. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 2, 2))
  3743. {
  3744. return;
  3745. }
  3746. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 8, pTargetCity))
  3747. {
  3748. return;
  3749. }
  3750. // Load stack if walking will take a long time
  3751. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 3))
  3752. {
  3753. return;
  3754. }
  3755. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12, pTargetCity))
  3756. {
  3757. return;
  3758. }
  3759. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 7))
  3760. {
  3761. return;
  3762. }
  3763. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, MAX_INT, pTargetCity))
  3764. {
  3765. return;
  3766. }
  3767. if (bAnyWarPlan)
  3768. {
  3769. CvCity* pTargetCity = area()->getTargetCity(getOwnerINLINE());
  3770. if (pTargetCity != NULL)
  3771. {
  3772. if (AI_solveBlockageProblem(pTargetCity->plot(), (GET_TEAM(getTeam()).getAtWarCount(true) == 0)))
  3773. {
  3774. return;
  3775. }
  3776. }
  3777. }
  3778. }
  3779. }
  3780. else
  3781. {
  3782. int iTargetCount = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
  3783. if( ((iTargetCount * 4) > getGroup()->getNumUnits()) || ((getGroup()->getNumUnits() + iTargetCount) >= (bHuntBarbs ? 3 : AI_stackOfDoomExtra())) )
  3784. {
  3785. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  3786. int iJoiners = kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
  3787. if( (iJoiners*6) > getGroup()->getNumUnits() )
  3788. {
  3789. getGroup()->pushMission(MISSION_SKIP);
  3790. return;
  3791. }
  3792. if (AI_safety())
  3793. {
  3794. return;
  3795. }
  3796. }
  3797. if ((bombardRate() > 0) && noDefensiveBonus())
  3798. {
  3799. // BBAI Notes: Add this stack lead by bombard unit to stack probably not lead by a bombard unit
  3800. // BBAI TODO: Some sense of minimum stack size? Can have big stack moving 10 turns to merge with tiny stacks
  3801. if (AI_group(UNITAI_ATTACK_CITY, -1, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ true))
  3802. {
  3803. return;
  3804. }
  3805. }
  3806. else
  3807. {
  3808. if (AI_group(UNITAI_ATTACK_CITY, AI_stackOfDoomExtra() * 2, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ false))
  3809. {
  3810. return;
  3811. }
  3812. }
  3813. }
  3814. if (plot()->getOwnerINLINE() == getOwnerINLINE() && bLandWar)
  3815. {
  3816. if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) )
  3817. {
  3818. // if no land path to enemy cities, try getting there another way
  3819. if (AI_offensiveAirlift())
  3820. {
  3821. return;
  3822. }
  3823. if( pTargetCity == NULL )
  3824. {
  3825. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  3826. {
  3827. return;
  3828. }
  3829. }
  3830. }
  3831. }
  3832. if (AI_moveToStagingCity())
  3833. {
  3834. return;
  3835. }
  3836. if (AI_offensiveAirlift())
  3837. {
  3838. return;
  3839. }
  3840. if (AI_retreatToCity())
  3841. {
  3842. return;
  3843. }
  3844. if( getGroup()->isStranded() )
  3845. {
  3846. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  3847. {
  3848. return;
  3849. }
  3850. if( !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
  3851. {
  3852. // If no other desireable actions, wait for pickup
  3853. getGroup()->pushMission(MISSION_SKIP);
  3854. return;
  3855. }
  3856. if (AI_patrol())
  3857. {
  3858. return;
  3859. }
  3860. }
  3861. if (AI_safety())
  3862. {
  3863. return;
  3864. }
  3865. getGroup()->pushMission(MISSION_SKIP);
  3866. return;
  3867. }
  3868. /************************************************************************************************/
  3869. /* BETTER_BTS_AI_MOD END */
  3870. /************************************************************************************************/
  3871. void CvUnitAI::AI_attackCityLemmingMove()
  3872. {
  3873. if (AI_cityAttack(1, 80))
  3874. {
  3875. return;
  3876. }
  3877. if (AI_bombardCity())
  3878. {
  3879. return;
  3880. }
  3881. if (AI_cityAttack(1, 40))
  3882. {
  3883. return;
  3884. }
  3885. /************************************************************************************************/
  3886. /* BETTER_BTS_AI_MOD 03/29/10 jdog5000 */
  3887. /* */
  3888. /* Unit AI */
  3889. /************************************************************************************************/
  3890. if (AI_goToTargetCity(MOVE_THROUGH_ENEMY))
  3891. /************************************************************************************************/
  3892. /* BETTER_BTS_AI_MOD END */
  3893. /************************************************************************************************/
  3894. {
  3895. return;
  3896. }
  3897. if (AI_anyAttack(1, 70))
  3898. {
  3899. return;
  3900. }
  3901. if (AI_anyAttack(1, 0))
  3902. {
  3903. return;
  3904. }
  3905. getGroup()->pushMission(MISSION_SKIP);
  3906. }
  3907. void CvUnitAI::AI_collateralMove()
  3908. {
  3909. PROFILE_FUNC();
  3910. if( gUnitLogLevel >= 2 )
  3911. {
  3912. logBBAI(" Stack %d (led by %S (%d), size %d) starting collateralMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  3913. }
  3914. if (AI_leaveAttack(1, 20, 100))
  3915. {
  3916. return;
  3917. }
  3918. if (AI_guardCity(false, true, 1))
  3919. {
  3920. return;
  3921. }
  3922. if (AI_heal(30, 1))
  3923. {
  3924. return;
  3925. }
  3926. if (AI_cityAttack(1, 35))
  3927. {
  3928. return;
  3929. }
  3930. if (AI_anyAttack(1, 45, 3))
  3931. {
  3932. return;
  3933. }
  3934. if (AI_anyAttack(1, 55, 2))
  3935. {
  3936. return;
  3937. }
  3938. if (AI_anyAttack(1, 35, 3))
  3939. {
  3940. return;
  3941. }
  3942. if (AI_anyAttack(1, 30, 4))
  3943. {
  3944. return;
  3945. }
  3946. if (AI_anyAttack(1, 20, 5))
  3947. {
  3948. return;
  3949. }
  3950. if (AI_heal())
  3951. {
  3952. return;
  3953. }
  3954. if (!noDefensiveBonus())
  3955. {
  3956. if (AI_guardCity(false, false))
  3957. {
  3958. return;
  3959. }
  3960. }
  3961. if (AI_anyAttack(2, 55, 3))
  3962. {
  3963. return;
  3964. }
  3965. if (AI_cityAttack(2, 50))
  3966. {
  3967. return;
  3968. }
  3969. if (AI_anyAttack(2, 60))
  3970. {
  3971. return;
  3972. }
  3973. /************************************************************************************************/
  3974. /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
  3975. /* */
  3976. /* Unit AI */
  3977. /************************************************************************************************/
  3978. //if (AI_protect(50))
  3979. if (AI_protect(50, 8))
  3980. /************************************************************************************************/
  3981. /* BETTER_BTS_AI_MOD END */
  3982. /************************************************************************************************/
  3983. {
  3984. return;
  3985. }
  3986. if (AI_guardCity(false, true, 3))
  3987. {
  3988. return;
  3989. }
  3990. if (AI_retreatToCity())
  3991. {
  3992. return;
  3993. }
  3994. /************************************************************************************************/
  3995. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  3996. /* */
  3997. /* Unit AI */
  3998. /************************************************************************************************/
  3999. if( getGroup()->isStranded() )
  4000. {
  4001. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  4002. {
  4003. return;
  4004. }
  4005. }
  4006. /************************************************************************************************/
  4007. /* BETTER_BTS_AI_MOD END */
  4008. /************************************************************************************************/
  4009. if (AI_safety())
  4010. {
  4011. return;
  4012. }
  4013. getGroup()->pushMission(MISSION_SKIP);
  4014. return;
  4015. }
  4016. void CvUnitAI::AI_pillageMove()
  4017. {
  4018. /************************************************************************************************/
  4019. /* BETTER_BTS_AI_MOD 03/05/10 jdog5000 */
  4020. /* */
  4021. /* Unit AI */
  4022. /************************************************************************************************/
  4023. PROFILE_FUNC();
  4024. if (AI_guardCity(false, true, 1))
  4025. {
  4026. return;
  4027. }
  4028. if (AI_heal(30, 1))
  4029. {
  4030. return;
  4031. }
  4032. // BBAI TODO: Shadow ATTACK_CITY stacks and pillage
  4033. //join any city attacks in progress
  4034. if (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE())
  4035. {
  4036. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
  4037. {
  4038. return;
  4039. }
  4040. }
  4041. if (AI_cityAttack(1, 75))
  4042. {
  4043. return;
  4044. }
  4045. if (AI_anyAttack(1, 65))
  4046. {
  4047. return;
  4048. }
  4049. if (!noDefensiveBonus())
  4050. {
  4051. if (AI_guardCity(false, false))
  4052. {
  4053. return;
  4054. }
  4055. }
  4056. if (AI_pillageRange(3, 11))
  4057. {
  4058. return;
  4059. }
  4060. if (AI_choke(1))
  4061. {
  4062. return;
  4063. }
  4064. if (AI_pillageRange(1))
  4065. {
  4066. return;
  4067. }
  4068. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  4069. {
  4070. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  4071. {
  4072. return;
  4073. }
  4074. }
  4075. if (AI_heal(50, 3))
  4076. {
  4077. return;
  4078. }
  4079. if (!isEnemy(plot()->getTeam()))
  4080. {
  4081. if (AI_heal())
  4082. {
  4083. return;
  4084. }
  4085. }
  4086. if (AI_group(UNITAI_PILLAGE, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, /*bIgnoreFaster*/ true, false, false, /*iMaxPath*/ 3))
  4087. {
  4088. return;
  4089. }
  4090. if ((area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) || isEnemy(plot()->getTeam()))
  4091. {
  4092. if (AI_pillage(20))
  4093. {
  4094. return;
  4095. }
  4096. }
  4097. if (AI_heal())
  4098. {
  4099. return;
  4100. }
  4101. if (AI_guardCity(false, true, 3))
  4102. {
  4103. return;
  4104. }
  4105. if (AI_offensiveAirlift())
  4106. {
  4107. return;
  4108. }
  4109. if (AI_travelToUpgradeCity())
  4110. {
  4111. return;
  4112. }
  4113. if( !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
  4114. {
  4115. getGroup()->pushMission(MISSION_SKIP);
  4116. return;
  4117. }
  4118. if (AI_patrol())
  4119. {
  4120. return;
  4121. }
  4122. if (AI_retreatToCity())
  4123. {
  4124. return;
  4125. }
  4126. if (AI_safety())
  4127. {
  4128. return;
  4129. }
  4130. getGroup()->pushMission(MISSION_SKIP);
  4131. return;
  4132. /************************************************************************************************/
  4133. /* BETTER_BTS_AI_MOD END */
  4134. /************************************************************************************************/
  4135. }
  4136. void CvUnitAI::AI_reserveMove()
  4137. {
  4138. PROFILE_FUNC();
  4139. /************************************************************************************************/
  4140. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  4141. /* */
  4142. /* Unit AI, Efficiency */
  4143. /************************************************************************************************/
  4144. //bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3) > 0);
  4145. bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
  4146. /************************************************************************************************/
  4147. /* BETTER_BTS_AI_MOD END */
  4148. /************************************************************************************************/
  4149. if (bDanger && AI_leaveAttack(2, 55, 130))
  4150. {
  4151. return;
  4152. }
  4153. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  4154. {
  4155. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, 1, -1, MOVE_SAFE_TERRITORY))
  4156. {
  4157. return;
  4158. }
  4159. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_WORKER, -1, -1, 1, -1, MOVE_SAFE_TERRITORY))
  4160. {
  4161. return;
  4162. }
  4163. }
  4164. /************************************************************************************************/
  4165. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  4166. /* */
  4167. /* Settler AI */
  4168. /************************************************************************************************/
  4169. if( !(plot()->isOwned()) )
  4170. {
  4171. if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 1, true))
  4172. {
  4173. return;
  4174. }
  4175. }
  4176. /************************************************************************************************/
  4177. /* BETTER_BTS_AI_MOD END */
  4178. /************************************************************************************************/
  4179. if (!bDanger)
  4180. {
  4181. if (AI_group(UNITAI_SETTLE, 2, -1, -1, false, false, false, 3, true))
  4182. {
  4183. return;
  4184. }
  4185. }
  4186. if (GET_TEAM(getTeam()).getAtWarCount(true) > 0)
  4187. {
  4188. AI_setGroupflag(GROUPFLAG_CONQUEST);
  4189. return;
  4190. }
  4191. if (AI_guardCity(true))
  4192. {
  4193. return;
  4194. }
  4195. if (!noDefensiveBonus())
  4196. {
  4197. if (AI_guardFort(false))
  4198. {
  4199. return;
  4200. }
  4201. }
  4202. if (AI_guardCityAirlift())
  4203. {
  4204. return;
  4205. }
  4206. if (AI_guardCity(false, true, 1))
  4207. {
  4208. return;
  4209. }
  4210. if (AI_guardCitySite())
  4211. {
  4212. return;
  4213. }
  4214. if (!noDefensiveBonus())
  4215. {
  4216. if (AI_guardFort(true))
  4217. {
  4218. return;
  4219. }
  4220. if (AI_guardBonus(15))
  4221. {
  4222. return;
  4223. }
  4224. }
  4225. if (AI_heal(30, 1))
  4226. {
  4227. return;
  4228. }
  4229. if (bDanger)
  4230. {
  4231. if (AI_cityAttack(1, 55))
  4232. {
  4233. return;
  4234. }
  4235. if (AI_anyAttack(1, 60))
  4236. {
  4237. return;
  4238. }
  4239. }
  4240. if (!noDefensiveBonus())
  4241. {
  4242. if (AI_guardCity(false, false))
  4243. {
  4244. return;
  4245. }
  4246. }
  4247. if (bDanger)
  4248. {
  4249. if (AI_cityAttack(3, 45))
  4250. {
  4251. return;
  4252. }
  4253. if (AI_anyAttack(3, 50))
  4254. {
  4255. return;
  4256. }
  4257. }
  4258. /************************************************************************************************/
  4259. /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
  4260. /* */
  4261. /* Unit AI */
  4262. /************************************************************************************************/
  4263. //if (AI_protect(45))
  4264. if (AI_protect(45, 8))
  4265. /************************************************************************************************/
  4266. /* BETTER_BTS_AI_MOD END */
  4267. /************************************************************************************************/
  4268. {
  4269. return;
  4270. }
  4271. if (AI_guardCity(false, true, 3))
  4272. {
  4273. return;
  4274. }
  4275. if (AI_defend())
  4276. {
  4277. return;
  4278. }
  4279. if (AI_retreatToCity())
  4280. {
  4281. return;
  4282. }
  4283. /************************************************************************************************/
  4284. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  4285. /* */
  4286. /* Unit AI */
  4287. /************************************************************************************************/
  4288. if( getGroup()->isStranded() )
  4289. {
  4290. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  4291. {
  4292. return;
  4293. }
  4294. }
  4295. /************************************************************************************************/
  4296. /* BETTER_BTS_AI_MOD END */
  4297. /************************************************************************************************/
  4298. if (AI_safety())
  4299. {
  4300. return;
  4301. }
  4302. getGroup()->pushMission(MISSION_SKIP);
  4303. return;
  4304. }
  4305. void CvUnitAI::AI_counterMove()
  4306. {
  4307. PROFILE_FUNC();
  4308. if( gUnitLogLevel >= 2 )
  4309. {
  4310. logBBAI(" Stack %d (led by %S (%d), size %d) starting counterMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  4311. }
  4312. /************************************************************************************************/
  4313. /* BETTER_BTS_AI_MOD 03/03/10 jdog5000 */
  4314. /* */
  4315. /* Unit AI, Settler AI */
  4316. /************************************************************************************************/
  4317. // Should never have group lead by counter unit
  4318. if( getGroup()->getNumUnits() > 1 )
  4319. {
  4320. UnitAITypes eGroupAI = getGroup()->getHeadUnitAI();
  4321. if( eGroupAI == AI_getUnitAIType() )
  4322. {
  4323. if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
  4324. {
  4325. //FAssert(false); // just interested in when this happens, not a problem
  4326. getGroup()->AI_separate(); // will change group
  4327. return;
  4328. }
  4329. }
  4330. }
  4331. if( !(plot()->isOwned()) )
  4332. {
  4333. if( AI_groupMergeRange(UNITAI_SETTLE, 2, true, false, false) )
  4334. {
  4335. return;
  4336. }
  4337. }
  4338. if (AI_guardCity(false, true, 1))
  4339. {
  4340. return;
  4341. }
  4342. if (getSameTileHeal() > 0)
  4343. {
  4344. if (!canAttack())
  4345. {
  4346. // Don't restrict to groups carrying cargo ... does this apply to any units in standard bts anyway?
  4347. if (AI_shadow(UNITAI_ATTACK_CITY, -1, 21, false, false, 4))
  4348. {
  4349. return;
  4350. }
  4351. }
  4352. }
  4353. bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
  4354. AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
  4355. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  4356. {
  4357. if( !bDanger )
  4358. {
  4359. if (plot()->isCity())
  4360. {
  4361. if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
  4362. {
  4363. if (AI_offensiveAirlift())
  4364. {
  4365. return;
  4366. }
  4367. }
  4368. }
  4369. if( (eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) || (eAreaAIType == AREAAI_ASSAULT_MASSING) )
  4370. {
  4371. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  4372. {
  4373. return;
  4374. }
  4375. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  4376. {
  4377. return;
  4378. }
  4379. }
  4380. }
  4381. if (!noDefensiveBonus())
  4382. {
  4383. if (AI_guardCity(false, false))
  4384. {
  4385. return;
  4386. }
  4387. }
  4388. }
  4389. //join any city attacks in progress
  4390. if (plot()->getOwnerINLINE() != getOwnerINLINE())
  4391. {
  4392. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
  4393. {
  4394. return;
  4395. }
  4396. }
  4397. if (bDanger)
  4398. {
  4399. if (AI_cityAttack(1, 35))
  4400. {
  4401. return;
  4402. }
  4403. if (AI_anyAttack(1, 40))
  4404. {
  4405. return;
  4406. }
  4407. }
  4408. bool bIgnoreFasterStacks = false;
  4409. if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
  4410. {
  4411. if (area()->getAreaAIType(getTeam()) != AREAAI_ASSAULT)
  4412. {
  4413. bIgnoreFasterStacks = true;
  4414. }
  4415. }
  4416. if (AI_group(UNITAI_ATTACK_CITY, /*iMaxGroup*/ -1, 2, -1, bIgnoreFasterStacks, /*bIgnoreOwnUnitType*/ true, /*bStackOfDoom*/ true, /*iMaxPath*/ 6))
  4417. {
  4418. return;
  4419. }
  4420. bool bFastMovers = (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_FASTMOVERS));
  4421. if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 2, -1, -1, bFastMovers, /*bIgnoreOwnUnitType*/ true, /*bStackOfDoom*/ true, /*iMaxPath*/ 5))
  4422. {
  4423. return;
  4424. }
  4425. // BBAI TODO: merge with nearby pillage
  4426. if (AI_guardCity(false, true, 3))
  4427. {
  4428. return;
  4429. }
  4430. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  4431. {
  4432. if( !bDanger )
  4433. {
  4434. if( (eAreaAIType != AREAAI_DEFENSIVE) )
  4435. {
  4436. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  4437. {
  4438. return;
  4439. }
  4440. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  4441. {
  4442. return;
  4443. }
  4444. }
  4445. }
  4446. }
  4447. if (AI_heal())
  4448. {
  4449. return;
  4450. }
  4451. if (AI_offensiveAirlift())
  4452. {
  4453. return;
  4454. }
  4455. if (AI_anyAttack(1, 80))
  4456. {
  4457. return;
  4458. }
  4459. if (AI_retreatToCity())
  4460. {
  4461. return;
  4462. }
  4463. if (AI_safety())
  4464. {
  4465. return;
  4466. }
  4467. getGroup()->pushMission(MISSION_SKIP);
  4468. return;
  4469. /************************************************************************************************/
  4470. /* BETTER_BTS_AI_MOD END */
  4471. /************************************************************************************************/
  4472. }
  4473. void CvUnitAI::AI_cityDefenseMove()
  4474. {
  4475. PROFILE_FUNC();
  4476. /* - a little too spammy - just use for debugging issues
  4477. if( gUnitLogLevel >= 2 )
  4478. {
  4479. logBBAI(" %S (unit %d) starting cityDefenseMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
  4480. }
  4481. */
  4482. /************************************************************************************************/
  4483. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  4484. /* */
  4485. /* Unit AI, Efficiency */
  4486. /************************************************************************************************/
  4487. //bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3) > 0);
  4488. bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
  4489. /************************************************************************************************/
  4490. /* BETTER_BTS_AI_MOD END */
  4491. /************************************************************************************************/
  4492. /************************************************************************************************/
  4493. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  4494. /* */
  4495. /* Settler AI */
  4496. /************************************************************************************************/
  4497. if( !(plot()->isOwned()) )
  4498. {
  4499. if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 2, true))
  4500. {
  4501. return;
  4502. }
  4503. }
  4504. /************************************************************************************************/
  4505. /* BETTER_BTS_AI_MOD END */
  4506. /************************************************************************************************/
  4507. if (bDanger)
  4508. {
  4509. if (AI_leaveAttack(1, 70, 175))
  4510. {
  4511. return;
  4512. }
  4513. if (AI_chokeDefend())
  4514. {
  4515. return;
  4516. }
  4517. }
  4518. if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
  4519. {
  4520. if (AI_mageMove())
  4521. {
  4522. return;
  4523. }
  4524. else if (isBarbarian() && plot()->isCity())
  4525. {
  4526. getGroup()->pushMission(MISSION_SKIP);
  4527. return;
  4528. }
  4529. }
  4530. if (AI_guardCityBestDefender())
  4531. {
  4532. return;
  4533. }
  4534. if (!bDanger)
  4535. {
  4536. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  4537. {
  4538. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, 1, -1, MOVE_SAFE_TERRITORY, 1))
  4539. {
  4540. return;
  4541. }
  4542. }
  4543. }
  4544. if (AI_guardCityMinDefender(true))
  4545. {
  4546. return;
  4547. }
  4548. if (plot()->isCity())
  4549. {
  4550. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  4551. {
  4552. if (plot()->getPlotCity()->AI_neededDefenders() > (plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE())) +
  4553. plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_COUNTER, -1, getOwnerINLINE()))
  4554. {
  4555. getGroup()->pushMission(MISSION_SKIP);
  4556. return;
  4557. }
  4558. }
  4559. }
  4560. // Super Forts begin *AI_defense*
  4561. if (AI_guardFortMinDefender(true))
  4562. {
  4563. logBBAI(" Unit %d (%S) guard fort at [%d, %d] (MinDefender pass 1) \n", getID(), getName().GetCString(), getX_INLINE(), getY_INLINE());
  4564. return;
  4565. }
  4566. // Super Forts end
  4567. if (AI_guardCity(true))
  4568. {
  4569. return;
  4570. }
  4571. if (!bDanger)
  4572. {
  4573. if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 1, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
  4574. {
  4575. return;
  4576. }
  4577. if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 3, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
  4578. {
  4579. return;
  4580. }
  4581. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  4582. {
  4583. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, 1, -1, MOVE_SAFE_TERRITORY))
  4584. {
  4585. return;
  4586. }
  4587. if (plot()->isCity())
  4588. {
  4589. CvCity* pCity = plot()->getPlotCity();
  4590. if (pCity->AI_neededDefenders() > plot()->getNumDefenders(getOwnerINLINE()))
  4591. {
  4592. if (AI_travelToUpgradeCity())
  4593. {
  4594. logBBAI(" %S (unit %d - %S) traveling to upgrade city (DEFENSE)", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription());
  4595. return;
  4596. }
  4597. }
  4598. }
  4599. }
  4600. /*
  4601. if (AI_travelToUpgradeCity())
  4602. {
  4603. return;
  4604. }
  4605. */
  4606. }
  4607. AreaAITypes eAreaAI = area()->getAreaAIType(getTeam());
  4608. if ((eAreaAI == AREAAI_ASSAULT) || (eAreaAI == AREAAI_ASSAULT_MASSING) || (eAreaAI == AREAAI_ASSAULT_ASSIST))
  4609. {
  4610. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, 0, MOVE_SAFE_TERRITORY))
  4611. {
  4612. return;
  4613. }
  4614. }
  4615. if ((AI_getBirthmark() % 4) == 0)
  4616. {
  4617. if (AI_guardFort())
  4618. {
  4619. return;
  4620. }
  4621. }
  4622. if (AI_guardCityAirlift())
  4623. {
  4624. return;
  4625. }
  4626. if (AI_guardCity(false, true, 1))
  4627. {
  4628. return;
  4629. }
  4630. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  4631. {
  4632. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, 3, -1, -1, -1, MOVE_SAFE_TERRITORY))
  4633. {
  4634. // will enter here if in danger
  4635. return;
  4636. }
  4637. }
  4638. /************************************************************************************************/
  4639. /* BETTER_BTS_AI_MOD 04/02/10 jdog5000 */
  4640. /* */
  4641. /* City AI */
  4642. /************************************************************************************************/
  4643. //join any city attacks in progress
  4644. if (plot()->getOwnerINLINE() != getOwnerINLINE())
  4645. {
  4646. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
  4647. {
  4648. return;
  4649. }
  4650. }
  4651. /************************************************************************************************/
  4652. /* BETTER_BTS_AI_MOD END */
  4653. /************************************************************************************************/
  4654. if (AI_guardCity(false, true))
  4655. {
  4656. return;
  4657. }
  4658. /************************************************************************************************/
  4659. /* BETTER_BTS_AI_MOD 03/04/10 jdog5000 */
  4660. /* */
  4661. /* Unit AI */
  4662. /************************************************************************************************/
  4663. if (!isBarbarian() && ((area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) || (area()->getAreaAIType(getTeam()) == AREAAI_MASSING)))
  4664. {
  4665. bool bIgnoreFaster = false;
  4666. if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
  4667. {
  4668. if (area()->getAreaAIType(getTeam()) != AREAAI_ASSAULT)
  4669. {
  4670. bIgnoreFaster = true;
  4671. }
  4672. }
  4673. if (AI_group(UNITAI_ATTACK_CITY, -1, 2, 4, bIgnoreFaster))
  4674. {
  4675. return;
  4676. }
  4677. }
  4678. if (area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT)
  4679. {
  4680. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, 2, -1, -1, 1, MOVE_SAFE_TERRITORY))
  4681. {
  4682. return;
  4683. }
  4684. }
  4685. /************************************************************************************************/
  4686. /* BETTER_BTS_AI_MOD END */
  4687. /************************************************************************************************/
  4688. if (AI_retreatToCity())
  4689. {
  4690. return;
  4691. }
  4692. /************************************************************************************************/
  4693. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  4694. /* */
  4695. /* Unit AI */
  4696. /************************************************************************************************/
  4697. if( getGroup()->isStranded() )
  4698. {
  4699. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  4700. {
  4701. return;
  4702. }
  4703. }
  4704. /************************************************************************************************/
  4705. /* BETTER_BTS_AI_MOD END */
  4706. /************************************************************************************************/
  4707. if (AI_safety())
  4708. {
  4709. return;
  4710. }
  4711. getGroup()->pushMission(MISSION_SKIP);
  4712. return;
  4713. }
  4714. void CvUnitAI::AI_cityDefenseExtraMove()
  4715. {
  4716. PROFILE_FUNC();
  4717. if( gUnitLogLevel >= 2 )
  4718. {
  4719. logBBAI(" Stack %d (led by %S (%d), size %d) starting cityDefenseExtraMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  4720. }
  4721. CvCity* pCity;
  4722. /************************************************************************************************/
  4723. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  4724. /* */
  4725. /* Settler AI */
  4726. /************************************************************************************************/
  4727. if( !(plot()->isOwned()) )
  4728. {
  4729. if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 1, true))
  4730. {
  4731. return;
  4732. }
  4733. }
  4734. /************************************************************************************************/
  4735. /* BETTER_BTS_AI_MOD END */
  4736. /************************************************************************************************/
  4737. if (AI_leaveAttack(2, 55, 150))
  4738. {
  4739. return;
  4740. }
  4741. if (AI_chokeDefend())
  4742. {
  4743. return;
  4744. }
  4745. if (AI_guardCityBestDefender())
  4746. {
  4747. return;
  4748. }
  4749. if (AI_guardCity(true))
  4750. {
  4751. return;
  4752. }
  4753. if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 1, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
  4754. {
  4755. return;
  4756. }
  4757. if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 2, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
  4758. {
  4759. return;
  4760. }
  4761. // Super Forts begin *AI_defense*
  4762. if (AI_guardFortMinDefender(true))
  4763. {
  4764. logBBAI(" Unit %d (%S) guard fort at [%d, %d] (MinDefender pass 2) \n", getID(), getName().GetCString(), getX_INLINE(), getY_INLINE());
  4765. return;
  4766. }
  4767. if ((AI_getBirthmark() % 4) == 0)
  4768. {
  4769. if (AI_guardFort(true))
  4770. {
  4771. return;
  4772. }
  4773. }
  4774. // Super Forts end
  4775. pCity = plot()->getPlotCity();
  4776. if ((pCity != NULL) && (pCity->getOwnerINLINE() == getOwnerINLINE())) // XXX check for other team?
  4777. {
  4778. if (plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isUnitAIType, AI_getUnitAIType()) == 1)
  4779. {
  4780. getGroup()->pushMission(MISSION_SKIP);
  4781. return;
  4782. }
  4783. }
  4784. if (AI_guardCityAirlift())
  4785. {
  4786. return;
  4787. }
  4788. if (AI_guardCity(false, true, 1))
  4789. {
  4790. return;
  4791. }
  4792. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  4793. {
  4794. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, 3, -1, -1, -1, MOVE_SAFE_TERRITORY, 3))
  4795. {
  4796. return;
  4797. }
  4798. }
  4799. if (AI_guardCity(false, true))
  4800. {
  4801. return;
  4802. }
  4803. if (AI_retreatToCity())
  4804. {
  4805. return;
  4806. }
  4807. if (AI_safety())
  4808. {
  4809. return;
  4810. }
  4811. getGroup()->pushMission(MISSION_SKIP);
  4812. return;
  4813. }
  4814. void CvUnitAI::AI_exploreMove()
  4815. {
  4816. PROFILE_FUNC();
  4817. if( gUnitLogLevel >= 2 )
  4818. {
  4819. logBBAI(" %S (unit %d) starting exploreMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
  4820. }
  4821. // Floating Eyes & Hawks
  4822. if (getDomainType() == DOMAIN_AIR)
  4823. {
  4824. if (airRange() > 0)
  4825. {
  4826. if (AI_exploreAir())
  4827. {
  4828. return;
  4829. }
  4830. else
  4831. {
  4832. getGroup()->pushMission(MISSION_SKIP);
  4833. return;
  4834. }
  4835. }
  4836. }
  4837. if (!isHuman() && canAttack())
  4838. {
  4839. if (AI_cityAttack(1, 60))
  4840. {
  4841. return;
  4842. }
  4843. if (AI_anyAttack(1, 70))
  4844. {
  4845. return;
  4846. }
  4847. }
  4848. /*
  4849. if (getDamage() > 0)
  4850. {
  4851. if ((plot()->getFeatureType() == NO_FEATURE) || (GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() <= 0))
  4852. {
  4853. getGroup()->pushMission(MISSION_HEAL);
  4854. return;
  4855. }
  4856. }
  4857. */
  4858. if (AI_heal())
  4859. {
  4860. return;
  4861. }
  4862. if (!isHuman())
  4863. {
  4864. if (AI_pillageRange(1))
  4865. {
  4866. return;
  4867. }
  4868. if (AI_cityAttack(3, 80))
  4869. {
  4870. return;
  4871. }
  4872. }
  4873. if (AI_goody(4))
  4874. {
  4875. return;
  4876. }
  4877. if (AI_pickupEquipment(6))
  4878. {
  4879. return;
  4880. }
  4881. if (!isHuman())
  4882. {
  4883. if (AI_exploreLair(6))
  4884. {
  4885. return;
  4886. }
  4887. }
  4888. if (AI_exploreRange(3))
  4889. {
  4890. return;
  4891. }
  4892. if (!isHuman())
  4893. {
  4894. if (AI_pillageRange(3))
  4895. {
  4896. return;
  4897. }
  4898. }
  4899. if (AI_explore())
  4900. {
  4901. return;
  4902. }
  4903. if (!isHuman())
  4904. {
  4905. if (AI_pillage())
  4906. {
  4907. return;
  4908. }
  4909. }
  4910. if (!isHuman())
  4911. {
  4912. if (AI_travelToUpgradeCity())
  4913. {
  4914. return;
  4915. }
  4916. }
  4917. /************************************************************************************************/
  4918. /* BETTER_BTS_AI_MOD 12/03/08 jdog5000 */
  4919. /* */
  4920. /* Unit AI */
  4921. /************************************************************************************************/
  4922. if( !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
  4923. {
  4924. getGroup()->pushMission(MISSION_SKIP);
  4925. return;
  4926. }
  4927. /************************************************************************************************/
  4928. /* BETTER_BTS_AI_MOD END */
  4929. /************************************************************************************************/
  4930. if (AI_patrol())
  4931. {
  4932. return;
  4933. }
  4934. if (AI_pickupEquipment(12))
  4935. {
  4936. return;
  4937. }
  4938. if (AI_retreatToCity())
  4939. {
  4940. return;
  4941. }
  4942. /************************************************************************************************/
  4943. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  4944. /* */
  4945. /* Unit AI */
  4946. /************************************************************************************************/
  4947. if( getGroup()->isStranded() )
  4948. {
  4949. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  4950. {
  4951. return;
  4952. }
  4953. }
  4954. /************************************************************************************************/
  4955. /* BETTER_BTS_AI_MOD END */
  4956. /************************************************************************************************/
  4957. if (AI_safety())
  4958. {
  4959. return;
  4960. }
  4961. getGroup()->pushMission(MISSION_SKIP);
  4962. return;
  4963. }
  4964. void CvUnitAI::AI_missionaryMove()
  4965. {
  4966. PROFILE_FUNC();
  4967. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  4968. CvCity* pLoopCity;
  4969. CvPlot* pBestGreatWorkPlot = NULL;
  4970. int iLoop;
  4971. // Tholal AI - modifications to improve Missionary AI
  4972. // Initial check to make sure AI doesn't use it's first disciple for a Great Work
  4973. if (!kPlayer.isAgnostic() && kPlayer.getStateReligion() == NO_RELIGION)
  4974. {
  4975. if (AI_spreadReligion())
  4976. {
  4977. return;
  4978. }
  4979. }
  4980. // Catch Disciples who have been upgraded to different units and change their AI
  4981. // Tholal ToDo - Secondary check is for Savants who can never do Great Works. Is there a better way to handle this?
  4982. if (m_pUnitInfo->getGreatWorkCulture() == 0)
  4983. {
  4984. if (m_pUnitInfo->getDefaultUnitAIType() != UNITAI_MISSIONARY)
  4985. {
  4986. AI_setUnitAIType(UNITAI_MEDIC);
  4987. return;
  4988. }
  4989. }
  4990. // Find cities in disorder or who have no culture and perform Great Works
  4991. // Tholal ToDo - Incorporate this into the AI_greatWork() function rather than duplicating code
  4992. /*
  4993. if (AI_greatWork())
  4994. {
  4995. return;
  4996. }
  4997. */
  4998. else
  4999. {
  5000. CvCity* pCity = plot()->getPlotCity();
  5001. CvPlot* pBestPlot = NULL;
  5002. if (pCity != NULL)
  5003. {
  5004. if (pCity->getOwner() == getOwner())
  5005. {
  5006. if (pCity->isDisorder() || pCity->getCultureLevel() == 0)
  5007. {
  5008. getGroup()->pushMission(MISSION_GREAT_WORK);
  5009. return;
  5010. }
  5011. }
  5012. }
  5013. int iBestValue = 0;
  5014. for (pLoopCity = kPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kPlayer.nextCity(&iLoop))
  5015. {
  5016. if (pLoopCity->isDisorder() || pLoopCity->getCulture(pLoopCity->getOwnerINLINE()) == 0)
  5017. {
  5018. if (canGreatWork(pLoopCity->plot()))
  5019. {
  5020. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  5021. {
  5022. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GREAT_WORK, getGroup()) == 0)
  5023. {
  5024. if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true))
  5025. {
  5026. int iValue = pLoopCity->getPopulation() * 10;
  5027. if (pLoopCity->isCapital())
  5028. {
  5029. iValue *= 10;
  5030. }
  5031. if (pLoopCity->isSettlement())
  5032. {
  5033. iValue /= 8;
  5034. }
  5035. if (iValue > iBestValue)
  5036. {
  5037. iBestValue = iValue;
  5038. pBestPlot = getPathEndTurnPlot();
  5039. pBestGreatWorkPlot = pLoopCity->plot();
  5040. }
  5041. }
  5042. }
  5043. }
  5044. }
  5045. }
  5046. }
  5047. if ((pBestPlot != NULL) && (pBestGreatWorkPlot != NULL))
  5048. {
  5049. if (atPlot(pBestGreatWorkPlot))
  5050. {
  5051. getGroup()->pushMission(MISSION_GREAT_WORK);
  5052. return;
  5053. }
  5054. else
  5055. {
  5056. FAssert(!atPlot(pBestPlot));
  5057. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_GREAT_WORK, pBestGreatWorkPlot);
  5058. return;
  5059. }
  5060. }
  5061. }
  5062. //End Tholal AI
  5063. if (AI_spreadReligion())
  5064. {
  5065. return;
  5066. }
  5067. if (AI_spreadCorporation())
  5068. {
  5069. return;
  5070. }
  5071. if (!isHuman() || (isAutomated() && GET_TEAM(getTeam()).getAtWarCount(true) == 0))
  5072. {
  5073. if (!isHuman() || (getGameTurnCreated() < GC.getGame().getGameTurn()))
  5074. {
  5075. if (AI_spreadReligionAirlift())
  5076. {
  5077. return;
  5078. }
  5079. if (AI_spreadCorporationAirlift())
  5080. {
  5081. return;
  5082. }
  5083. }
  5084. if (!isHuman())
  5085. {
  5086. if (AI_load(UNITAI_MISSIONARY_SEA, MISSIONAI_LOAD_SPECIAL, NO_UNITAI, -1, -1, -1, 0, MOVE_SAFE_TERRITORY))
  5087. {
  5088. return;
  5089. }
  5090. if (AI_load(UNITAI_MISSIONARY_SEA, MISSIONAI_LOAD_SPECIAL, NO_UNITAI, -1, -1, -1, 0, MOVE_NO_ENEMY_TERRITORY))
  5091. {
  5092. return;
  5093. }
  5094. }
  5095. }
  5096. if (AI_guardCity())
  5097. {
  5098. return;
  5099. }
  5100. if (AI_retreatToCity())
  5101. {
  5102. return;
  5103. }
  5104. /************************************************************************************************/
  5105. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  5106. /* */
  5107. /* Unit AI */
  5108. /************************************************************************************************/
  5109. if( getGroup()->isStranded() )
  5110. {
  5111. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  5112. {
  5113. return;
  5114. }
  5115. }
  5116. /************************************************************************************************/
  5117. /* BETTER_BTS_AI_MOD END */
  5118. /************************************************************************************************/
  5119. if (AI_safety())
  5120. {
  5121. return;
  5122. }
  5123. getGroup()->pushMission(MISSION_SKIP);
  5124. return;
  5125. }
  5126. void CvUnitAI::AI_prophetMove()
  5127. {
  5128. PROFILE_FUNC();
  5129. logBBAI(" %S (%d) starting ProphetMove", getName().GetCString(), getID());
  5130. // Sephi AI (Altar)
  5131. if (GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_ALTAR1))
  5132. {
  5133. if (AI_construct(10000,10000))
  5134. {
  5135. return;
  5136. }
  5137. }
  5138. // End Sephi AI
  5139. if (AI_construct())
  5140. {
  5141. return;
  5142. }
  5143. if (AI_discover(true, true))
  5144. {
  5145. return;
  5146. }
  5147. if (AI_construct(3))
  5148. {
  5149. return;
  5150. }
  5151. int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
  5152. int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
  5153. if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
  5154. {
  5155. if (AI_goldenAge())
  5156. {
  5157. return;
  5158. }
  5159. if (iDiscoverValue > iGoldenAgeValue)
  5160. {
  5161. if (AI_discover())
  5162. {
  5163. return;
  5164. }
  5165. if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
  5166. {
  5167. if (AI_join())
  5168. {
  5169. return;
  5170. }
  5171. }
  5172. }
  5173. }
  5174. else
  5175. {
  5176. if (AI_discover())
  5177. {
  5178. return;
  5179. }
  5180. if (AI_join())
  5181. {
  5182. return;
  5183. }
  5184. }
  5185. /************************************************************************************************/
  5186. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  5187. /* */
  5188. /* Unit AI, Efficiency */
  5189. /************************************************************************************************/
  5190. //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
  5191. if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
  5192. /************************************************************************************************/
  5193. /* BETTER_BTS_AI_MOD END */
  5194. /************************************************************************************************/
  5195. (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
  5196. {
  5197. if (AI_discover())
  5198. {
  5199. return;
  5200. }
  5201. }
  5202. if (AI_retreatToCity())
  5203. {
  5204. return;
  5205. }
  5206. /************************************************************************************************/
  5207. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  5208. /* */
  5209. /* Unit AI */
  5210. /************************************************************************************************/
  5211. if( getGroup()->isStranded() )
  5212. {
  5213. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  5214. {
  5215. return;
  5216. }
  5217. }
  5218. /************************************************************************************************/
  5219. /* BETTER_BTS_AI_MOD END */
  5220. /************************************************************************************************/
  5221. if (AI_safety())
  5222. {
  5223. return;
  5224. }
  5225. getGroup()->pushMission(MISSION_SKIP);
  5226. return;
  5227. }
  5228. void CvUnitAI::AI_artistMove()
  5229. {
  5230. PROFILE_FUNC();
  5231. if (AI_artistCultureVictoryMove())
  5232. {
  5233. return;
  5234. }
  5235. if (AI_construct())
  5236. {
  5237. return;
  5238. }
  5239. if (AI_discover(true, true))
  5240. {
  5241. return;
  5242. }
  5243. int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
  5244. int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
  5245. if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
  5246. {
  5247. if (AI_goldenAge())
  5248. {
  5249. return;
  5250. }
  5251. if (iDiscoverValue > iGoldenAgeValue)
  5252. {
  5253. if (AI_discover())
  5254. {
  5255. return;
  5256. }
  5257. if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
  5258. {
  5259. if (AI_join())
  5260. {
  5261. return;
  5262. }
  5263. }
  5264. }
  5265. }
  5266. else
  5267. {
  5268. if (AI_discover())
  5269. {
  5270. return;
  5271. }
  5272. if (AI_join())
  5273. {
  5274. return;
  5275. }
  5276. }
  5277. /************************************************************************************************/
  5278. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  5279. /* */
  5280. /* Unit AI, Efficiency */
  5281. /************************************************************************************************/
  5282. //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
  5283. if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
  5284. /************************************************************************************************/
  5285. /* BETTER_BTS_AI_MOD END */
  5286. /************************************************************************************************/
  5287. (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
  5288. {
  5289. if (AI_discover())
  5290. {
  5291. return;
  5292. }
  5293. }
  5294. if (AI_greatWork())
  5295. {
  5296. return;
  5297. }
  5298. if (AI_retreatToCity())
  5299. {
  5300. return;
  5301. }
  5302. /************************************************************************************************/
  5303. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  5304. /* */
  5305. /* Unit AI */
  5306. /************************************************************************************************/
  5307. if( getGroup()->isStranded() )
  5308. {
  5309. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  5310. {
  5311. return;
  5312. }
  5313. }
  5314. /************************************************************************************************/
  5315. /* BETTER_BTS_AI_MOD END */
  5316. /************************************************************************************************/
  5317. if (AI_safety())
  5318. {
  5319. return;
  5320. }
  5321. getGroup()->pushMission(MISSION_SKIP);
  5322. return;
  5323. }
  5324. void CvUnitAI::AI_scientistMove()
  5325. {
  5326. PROFILE_FUNC();
  5327. if (AI_discover(true, true))
  5328. {
  5329. return;
  5330. }
  5331. if (AI_construct(MAX_INT, 1))
  5332. {
  5333. return;
  5334. }
  5335. if (GC.getGameINLINE().getCurrentEra() < 3)
  5336. {
  5337. if (AI_join(2))
  5338. {
  5339. return;
  5340. }
  5341. }
  5342. if (GC.getGameINLINE().getCurrentEra() <= (GC.getNumRealEras() / 2))
  5343. {
  5344. if (AI_construct())
  5345. {
  5346. return;
  5347. }
  5348. }
  5349. int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
  5350. int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
  5351. if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
  5352. {
  5353. if (AI_goldenAge())
  5354. {
  5355. return;
  5356. }
  5357. if (iDiscoverValue > iGoldenAgeValue)
  5358. {
  5359. if (AI_discover())
  5360. {
  5361. return;
  5362. }
  5363. if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
  5364. {
  5365. if (AI_join())
  5366. {
  5367. return;
  5368. }
  5369. }
  5370. }
  5371. }
  5372. else
  5373. {
  5374. if (AI_discover())
  5375. {
  5376. return;
  5377. }
  5378. if (AI_join())
  5379. {
  5380. return;
  5381. }
  5382. }
  5383. /************************************************************************************************/
  5384. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  5385. /* */
  5386. /* Unit AI, Efficiency */
  5387. /************************************************************************************************/
  5388. //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
  5389. if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
  5390. /************************************************************************************************/
  5391. /* BETTER_BTS_AI_MOD END */
  5392. /************************************************************************************************/
  5393. (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
  5394. {
  5395. if (AI_discover())
  5396. {
  5397. return;
  5398. }
  5399. }
  5400. if (AI_retreatToCity())
  5401. {
  5402. return;
  5403. }
  5404. /************************************************************************************************/
  5405. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  5406. /* */
  5407. /* Unit AI */
  5408. /************************************************************************************************/
  5409. if( getGroup()->isStranded() )
  5410. {
  5411. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  5412. {
  5413. return;
  5414. }
  5415. }
  5416. /************************************************************************************************/
  5417. /* BETTER_BTS_AI_MOD END */
  5418. /************************************************************************************************/
  5419. if (AI_safety())
  5420. {
  5421. return;
  5422. }
  5423. getGroup()->pushMission(MISSION_SKIP);
  5424. return;
  5425. }
  5426. void CvUnitAI::AI_generalMove()
  5427. {
  5428. PROFILE_FUNC();
  5429. std::vector<UnitAITypes> aeUnitAITypes;
  5430. int iDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2);
  5431. bool bOffenseWar = (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE);
  5432. if (iDanger > 0)
  5433. {
  5434. aeUnitAITypes.clear();
  5435. aeUnitAITypes.push_back(UNITAI_ATTACK);
  5436. aeUnitAITypes.push_back(UNITAI_COUNTER);
  5437. if (AI_lead(aeUnitAITypes))
  5438. {
  5439. return;
  5440. }
  5441. }
  5442. if (AI_construct())
  5443. {
  5444. return;
  5445. }
  5446. if (AI_join(1))
  5447. {
  5448. return;
  5449. }
  5450. /************************************************************************************************/
  5451. /* BETTER_BTS_AI_MOD 05/14/10 jdog5000 */
  5452. /* */
  5453. /* Unit AI */
  5454. /************************************************************************************************/
  5455. if ((bOffenseWar && (AI_getBirthmark() % 2 == 0)) || GC.getUnitInfo(getUnitType()).getLeaderPromotion() != NO_PROMOTION)
  5456. {
  5457. aeUnitAITypes.clear();
  5458. aeUnitAITypes.push_back(UNITAI_ATTACK_CITY);
  5459. if (AI_lead(aeUnitAITypes))
  5460. {
  5461. return;
  5462. }
  5463. aeUnitAITypes.clear();
  5464. aeUnitAITypes.push_back(UNITAI_ATTACK);
  5465. if (AI_lead(aeUnitAITypes))
  5466. {
  5467. return;
  5468. }
  5469. }
  5470. if (AI_join(2))
  5471. {
  5472. return;
  5473. }
  5474. if (AI_construct(2))
  5475. {
  5476. return;
  5477. }
  5478. if (AI_join(4))
  5479. {
  5480. return;
  5481. }
  5482. if (GC.getGameINLINE().getSorenRandNum(3, "AI General Construct") == 0)
  5483. {
  5484. if (AI_construct())
  5485. {
  5486. return;
  5487. }
  5488. }
  5489. if (AI_join())
  5490. {
  5491. return;
  5492. }
  5493. if (AI_retreatToCity())
  5494. {
  5495. return;
  5496. }
  5497. if( getGroup()->isStranded() )
  5498. {
  5499. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  5500. {
  5501. return;
  5502. }
  5503. }
  5504. /************************************************************************************************/
  5505. /* BETTER_BTS_AI_MOD END */
  5506. /************************************************************************************************/
  5507. if (AI_safety())
  5508. {
  5509. return;
  5510. }
  5511. getGroup()->pushMission(MISSION_SKIP);
  5512. return;
  5513. }
  5514. void CvUnitAI::AI_merchantMove()
  5515. {
  5516. PROFILE_FUNC();
  5517. logBBAI(" %S (%d) starting MerchantMove", getName().GetCString(), getID());
  5518. if (AI_construct())
  5519. {
  5520. return;
  5521. }
  5522. if (AI_discover(true, true))
  5523. {
  5524. return;
  5525. }
  5526. int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
  5527. int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
  5528. if (AI_trade(iGoldenAgeValue * 2))
  5529. {
  5530. return;
  5531. }
  5532. if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
  5533. {
  5534. if (AI_goldenAge())
  5535. {
  5536. return;
  5537. }
  5538. if (AI_trade(iGoldenAgeValue))
  5539. {
  5540. return;
  5541. }
  5542. if (iDiscoverValue > iGoldenAgeValue)
  5543. {
  5544. if (AI_discover())
  5545. {
  5546. return;
  5547. }
  5548. if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
  5549. {
  5550. if (AI_join())
  5551. {
  5552. return;
  5553. }
  5554. }
  5555. }
  5556. }
  5557. else
  5558. {
  5559. if (AI_discover())
  5560. {
  5561. return;
  5562. }
  5563. if (AI_join())
  5564. {
  5565. return;
  5566. }
  5567. }
  5568. /************************************************************************************************/
  5569. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  5570. /* */
  5571. /* Unit AI, Efficiency */
  5572. /************************************************************************************************/
  5573. //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
  5574. if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
  5575. /************************************************************************************************/
  5576. /* BETTER_BTS_AI_MOD END */
  5577. /************************************************************************************************/
  5578. (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
  5579. {
  5580. if (AI_discover())
  5581. {
  5582. return;
  5583. }
  5584. }
  5585. if (AI_retreatToCity())
  5586. {
  5587. return;
  5588. }
  5589. /************************************************************************************************/
  5590. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  5591. /* */
  5592. /* Unit AI */
  5593. /************************************************************************************************/
  5594. if( getGroup()->isStranded() )
  5595. {
  5596. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  5597. {
  5598. return;
  5599. }
  5600. }
  5601. /************************************************************************************************/
  5602. /* BETTER_BTS_AI_MOD END */
  5603. /************************************************************************************************/
  5604. if (AI_safety())
  5605. {
  5606. return;
  5607. }
  5608. getGroup()->pushMission(MISSION_SKIP);
  5609. return;
  5610. }
  5611. void CvUnitAI::AI_engineerMove()
  5612. {
  5613. PROFILE_FUNC();
  5614. if (AI_construct())
  5615. {
  5616. return;
  5617. }
  5618. if (AI_switchHurry())
  5619. {
  5620. return;
  5621. }
  5622. if (AI_hurry())
  5623. {
  5624. return;
  5625. }
  5626. if (AI_discover(true, true))
  5627. {
  5628. return;
  5629. }
  5630. int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
  5631. int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
  5632. if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
  5633. {
  5634. if (AI_goldenAge())
  5635. {
  5636. return;
  5637. }
  5638. if (iDiscoverValue > iGoldenAgeValue)
  5639. {
  5640. if (AI_discover())
  5641. {
  5642. return;
  5643. }
  5644. if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
  5645. {
  5646. if (AI_join())
  5647. {
  5648. return;
  5649. }
  5650. }
  5651. }
  5652. }
  5653. else
  5654. {
  5655. if (AI_discover())
  5656. {
  5657. return;
  5658. }
  5659. if (AI_join())
  5660. {
  5661. return;
  5662. }
  5663. }
  5664. /************************************************************************************************/
  5665. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  5666. /* */
  5667. /* Unit AI, Efficiency */
  5668. /************************************************************************************************/
  5669. //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
  5670. if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
  5671. /************************************************************************************************/
  5672. /* BETTER_BTS_AI_MOD END */
  5673. /************************************************************************************************/
  5674. (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
  5675. {
  5676. if (AI_discover())
  5677. {
  5678. return;
  5679. }
  5680. }
  5681. if (AI_retreatToCity())
  5682. {
  5683. return;
  5684. }
  5685. /************************************************************************************************/
  5686. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  5687. /* */
  5688. /* Unit AI */
  5689. /************************************************************************************************/
  5690. if( getGroup()->isStranded() )
  5691. {
  5692. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  5693. {
  5694. return;
  5695. }
  5696. }
  5697. /************************************************************************************************/
  5698. /* BETTER_BTS_AI_MOD END */
  5699. /************************************************************************************************/
  5700. if (AI_safety())
  5701. {
  5702. return;
  5703. }
  5704. getGroup()->pushMission(MISSION_SKIP);
  5705. return;
  5706. }
  5707. /************************************************************************************************/
  5708. /* BETTER_BTS_AI_MOD 04/25/10 jdog5000 */
  5709. /* */
  5710. /* Espionage AI */
  5711. /************************************************************************************************/
  5712. void CvUnitAI::AI_spyMove()
  5713. {
  5714. PROFILE_FUNC();
  5715. CvTeamAI& kTeam = GET_TEAM(getTeam());
  5716. int iEspionageChance = 0;
  5717. if (plot()->isOwned() && (plot()->getTeam() != getTeam()))
  5718. {
  5719. switch (GET_PLAYER(getOwnerINLINE()).AI_getAttitude(plot()->getOwnerINLINE()))
  5720. {
  5721. case ATTITUDE_FURIOUS:
  5722. iEspionageChance = 100;
  5723. break;
  5724. case ATTITUDE_ANNOYED:
  5725. iEspionageChance = 50;
  5726. break;
  5727. case ATTITUDE_CAUTIOUS:
  5728. iEspionageChance = (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 30 : 10);
  5729. break;
  5730. case ATTITUDE_PLEASED:
  5731. iEspionageChance = (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 20 : 0);
  5732. break;
  5733. case ATTITUDE_FRIENDLY:
  5734. iEspionageChance = 0;
  5735. break;
  5736. default: // lfgr comment: isAIControl() makes isAutomated() true without actually having to have an automate type.
  5737. FAssertMsg( isAIControl(), CvString::format( "Unknown automate type: %d", getGroup()->getAutomateType() ).c_str() );
  5738. break;
  5739. }
  5740. WarPlanTypes eWarPlan = kTeam.AI_getWarPlan(plot()->getTeam());
  5741. if (eWarPlan != NO_WARPLAN)
  5742. {
  5743. if (eWarPlan == WARPLAN_LIMITED)
  5744. {
  5745. iEspionageChance += 50;
  5746. }
  5747. else
  5748. {
  5749. iEspionageChance += 20;
  5750. }
  5751. }
  5752. if (plot()->isCity() && plot()->getTeam() != getTeam())
  5753. {
  5754. bool bTargetCity = false;
  5755. // would we have more power if enemy defenses were down?
  5756. int iOurPower = GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(),1,false,true);
  5757. int iEnemyPower = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),0,false,false);
  5758. if( 5*iOurPower > 6*iEnemyPower && eWarPlan != NO_WARPLAN )
  5759. {
  5760. bTargetCity = true;
  5761. if( AI_revoltCitySpy() )
  5762. {
  5763. return;
  5764. }
  5765. if (GC.getGame().getSorenRandNum(5, "AI Spy Skip Turn") > 0)
  5766. {
  5767. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
  5768. return;
  5769. }
  5770. if ( AI_cityOffenseSpy(5, plot()->getPlotCity()) )
  5771. {
  5772. return;
  5773. }
  5774. }
  5775. if( GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(plot(), MISSIONAI_ASSAULT, getGroup()) > 0 )
  5776. {
  5777. bTargetCity = true;
  5778. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
  5779. return;
  5780. }
  5781. if( !bTargetCity )
  5782. {
  5783. // normal city handling
  5784. if (getFortifyTurns() >= GC.getDefineINT("MAX_FORTIFY_TURNS"))
  5785. {
  5786. if (AI_espionageSpy())
  5787. {
  5788. return;
  5789. }
  5790. }
  5791. else if (GC.getGame().getSorenRandNum(100, "AI Spy Skip Turn") > 5)
  5792. {
  5793. // don't get stuck forever
  5794. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
  5795. return;
  5796. }
  5797. }
  5798. }
  5799. else if (GC.getGameINLINE().getSorenRandNum(100, "AI Spy Espionage") < iEspionageChance)
  5800. {
  5801. // This applies only when not in an enemy city, so for destroying improvements
  5802. if (AI_espionageSpy())
  5803. {
  5804. return;
  5805. }
  5806. }
  5807. }
  5808. if (plot()->getTeam() == getTeam())
  5809. {
  5810. if (kTeam.getAnyWarPlanCount(true) == 0 || GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_SPACE4) || GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE3))
  5811. {
  5812. if( GC.getGame().getSorenRandNum(10, "AI Spy defense") > 0)
  5813. {
  5814. if (AI_guardSpy(0))
  5815. {
  5816. return;
  5817. }
  5818. }
  5819. }
  5820. if (GC.getGame().getSorenRandNum(100, "AI Spy pillage improvement") < 25)
  5821. {
  5822. if (AI_bonusOffenseSpy(5))
  5823. {
  5824. return;
  5825. }
  5826. }
  5827. else
  5828. {
  5829. if (AI_cityOffenseSpy(10))
  5830. {
  5831. return;
  5832. }
  5833. }
  5834. }
  5835. if (iEspionageChance > 0 && (plot()->isCity() || (plot()->getNonObsoleteBonusType(getTeam()) != NO_BONUS)))
  5836. {
  5837. if (GC.getGame().getSorenRandNum(7, "AI Spy Skip Turn") > 0)
  5838. {
  5839. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
  5840. return;
  5841. }
  5842. }
  5843. if( area()->getNumCities() > area()->getCitiesPerPlayer(getOwnerINLINE()) )
  5844. {
  5845. if (GC.getGame().getSorenRandNum(4, "AI Spy Choose Movement") > 0)
  5846. {
  5847. if (AI_reconSpy(3))
  5848. {
  5849. return;
  5850. }
  5851. }
  5852. else
  5853. {
  5854. if (AI_cityOffenseSpy(10))
  5855. {
  5856. return;
  5857. }
  5858. }
  5859. }
  5860. if (AI_load(UNITAI_SPY_SEA, MISSIONAI_LOAD_SPECIAL, NO_UNITAI, -1, -1, -1, 0, MOVE_NO_ENEMY_TERRITORY))
  5861. {
  5862. return;
  5863. }
  5864. if (AI_retreatToCity())
  5865. {
  5866. return;
  5867. }
  5868. if (AI_safety())
  5869. {
  5870. return;
  5871. }
  5872. getGroup()->pushMission(MISSION_SKIP);
  5873. return;
  5874. }
  5875. /************************************************************************************************/
  5876. /* BETTER_BTS_AI_MOD END */
  5877. /************************************************************************************************/
  5878. void CvUnitAI::AI_ICBMMove()
  5879. {
  5880. PROFILE_FUNC();
  5881. // CvCity* pCity = plot()->getPlotCity();
  5882. // if (pCity != NULL)
  5883. // {
  5884. // if (pCity->AI_isDanger())
  5885. // {
  5886. // if (!(pCity->AI_isDefended()))
  5887. // {
  5888. // if (AI_airCarrier())
  5889. // {
  5890. // return;
  5891. // }
  5892. // }
  5893. // }
  5894. // }
  5895. if (airRange() > 0)
  5896. {
  5897. if (AI_nukeRange(airRange()))
  5898. {
  5899. return;
  5900. }
  5901. }
  5902. else if (AI_nuke())
  5903. {
  5904. return;
  5905. }
  5906. if (isCargo())
  5907. {
  5908. getGroup()->pushMission(MISSION_SKIP);
  5909. return;
  5910. }
  5911. if (airRange() > 0)
  5912. {
  5913. /************************************************************************************************/
  5914. /* BETTER_BTS_AI_MOD 04/25/10 jdog5000 */
  5915. /* */
  5916. /* Unit AI */
  5917. /************************************************************************************************/
  5918. if (plot()->isCity(true))
  5919. {
  5920. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  5921. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  5922. if (4*iEnemyOffense > iOurDefense || iOurDefense == 0)
  5923. {
  5924. // Too risky, pull back
  5925. if (AI_airOffensiveCity())
  5926. {
  5927. return;
  5928. }
  5929. }
  5930. }
  5931. /************************************************************************************************/
  5932. /* BETTER_BTS_AI_MOD END */
  5933. /************************************************************************************************/
  5934. if (AI_missileLoad(UNITAI_MISSILE_CARRIER_SEA, 2, true))
  5935. {
  5936. return;
  5937. }
  5938. if (AI_missileLoad(UNITAI_MISSILE_CARRIER_SEA, 1, false))
  5939. {
  5940. return;
  5941. }
  5942. if (AI_getBirthmark() % 3 == 0)
  5943. {
  5944. if (AI_missileLoad(UNITAI_ATTACK_SEA, 0, false))
  5945. {
  5946. return;
  5947. }
  5948. }
  5949. if (AI_airOffensiveCity())
  5950. {
  5951. return;
  5952. }
  5953. }
  5954. getGroup()->pushMission(MISSION_SKIP);
  5955. }
  5956. void CvUnitAI::AI_workerSeaMove()
  5957. {
  5958. PROFILE_FUNC();
  5959. //CvCity* pCity;
  5960. int iI;
  5961. if( gUnitLogLevel >= 2 )
  5962. {
  5963. logBBAI(" Stack %d (led by %S (%d), size %d) starting workerSeaMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  5964. }
  5965. if (!(getGroup()->canDefend()))
  5966. {
  5967. //if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot()))
  5968. if (GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), -1))
  5969. {
  5970. if (AI_retreatToCity())
  5971. {
  5972. return;
  5973. }
  5974. }
  5975. }
  5976. /*************************************************************************************************/
  5977. /** Skyre Mod **/
  5978. /** BETTER AI (Lanun Pirate Coves) merged Sephi **/
  5979. /** **/
  5980. /*************************************************************************************************/
  5981. if (GET_PLAYER(getOwnerINLINE()).isPirate())
  5982. {
  5983. if (AI_buildPirateCove())
  5984. {
  5985. return;
  5986. }
  5987. }
  5988. /*************************************************************************************************/
  5989. /** END **/
  5990. /*************************************************************************************************/
  5991. if (AI_improveBonus(20))
  5992. {
  5993. return;
  5994. }
  5995. if (AI_improveBonus(10))
  5996. {
  5997. return;
  5998. }
  5999. if (AI_improveBonus())
  6000. {
  6001. return;
  6002. }
  6003. if (isHuman())
  6004. {
  6005. FAssert(isAutomated());
  6006. if (plot()->getBonusType() != NO_BONUS)
  6007. {
  6008. if ((plot()->getOwnerINLINE() == getOwnerINLINE()) || (!plot()->isOwned()))
  6009. {
  6010. getGroup()->pushMission(MISSION_SKIP);
  6011. return;
  6012. }
  6013. }
  6014. for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  6015. {
  6016. CvPlot* pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), (DirectionTypes)iI);
  6017. if (pLoopPlot != NULL)
  6018. {
  6019. if (pLoopPlot->getBonusType() != NO_BONUS)
  6020. {
  6021. if (pLoopPlot->isValidDomainForLocation(*this))
  6022. {
  6023. getGroup()->pushMission(MISSION_SKIP);
  6024. return;
  6025. }
  6026. }
  6027. }
  6028. }
  6029. }
  6030. /*
  6031. if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_WORKER_SEA))
  6032. {
  6033. pCity = plot()->getPlotCity();
  6034. if (pCity != NULL)
  6035. {
  6036. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  6037. {
  6038. if (pCity->AI_neededSeaWorkers() == 0)
  6039. {
  6040. if (GC.getGameINLINE().getElapsedGameTurns() > 10)
  6041. {
  6042. if (GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
  6043. {
  6044. scrap();
  6045. return;
  6046. }
  6047. }
  6048. }
  6049. else
  6050. {
  6051. //Probably icelocked since it can't perform actions.
  6052. scrap();
  6053. return;
  6054. }
  6055. }
  6056. }
  6057. }
  6058. */
  6059. if (AI_retreatToCity())
  6060. {
  6061. return;
  6062. }
  6063. if (AI_safety())
  6064. {
  6065. return;
  6066. }
  6067. getGroup()->pushMission(MISSION_SKIP);
  6068. return;
  6069. }
  6070. void CvUnitAI::AI_barbAttackSeaMove()
  6071. {
  6072. PROFILE_FUNC();
  6073. /********************************************************************************/
  6074. /* BETTER_BTS_AI_MOD 9/25/08 jdog5000 */
  6075. /* */
  6076. /* Barbarian AI */
  6077. /********************************************************************************/
  6078. /* original BTS code
  6079. if (GC.getGameINLINE().getSorenRandNum(2, "AI Barb") == 0)
  6080. {
  6081. if (AI_pillageRange(1))
  6082. {
  6083. return;
  6084. }
  6085. }
  6086. if (AI_anyAttack(2, 25))
  6087. {
  6088. return;
  6089. }
  6090. if (AI_pillageRange(4))
  6091. {
  6092. return;
  6093. }
  6094. if (AI_heal())
  6095. {
  6096. return;
  6097. }
  6098. */
  6099. // Less suicide, always chase good targets
  6100. if( AI_anyAttack(2,51) )
  6101. {
  6102. return;
  6103. }
  6104. if (AI_pillageRange(1))
  6105. {
  6106. return;
  6107. }
  6108. if( AI_anyAttack(1,34) )
  6109. {
  6110. return;
  6111. }
  6112. // We're easy to take out if wounded
  6113. if (AI_heal())
  6114. {
  6115. return;
  6116. }
  6117. if (AI_pillageRange(3))
  6118. {
  6119. return;
  6120. }
  6121. // Barb ships will often hang out for a little while blockading before moving on
  6122. if( (GC.getGame().getGameTurn() + getID())%12 > 5 )
  6123. {
  6124. if( AI_pirateBlockade())
  6125. {
  6126. return;
  6127. }
  6128. }
  6129. if( GC.getGameINLINE().getSorenRandNum(3, "AI Check trapped") == 0 )
  6130. {
  6131. // If trapped in small hole in ice or around tiny island, disband to allow other units to be generated
  6132. bool bScrap = true;
  6133. int iMaxRange = baseMoves() + 2;
  6134. for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
  6135. {
  6136. for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
  6137. {
  6138. if( bScrap )
  6139. {
  6140. CvPlot* pLoopPlot = plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), iDX, iDY);
  6141. if (pLoopPlot != NULL && AI_plotValid(pLoopPlot))
  6142. {
  6143. int iPathTurns;
  6144. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  6145. {
  6146. if( iPathTurns > 1 )
  6147. {
  6148. bScrap = false;
  6149. }
  6150. }
  6151. }
  6152. }
  6153. }
  6154. }
  6155. if( bScrap )
  6156. {
  6157. scrap();
  6158. }
  6159. }
  6160. /********************************************************************************/
  6161. /* BETTER_BTS_AI_MOD END */
  6162. /********************************************************************************/
  6163. if (AI_patrol())
  6164. {
  6165. return;
  6166. }
  6167. if (AI_retreatToCity())
  6168. {
  6169. return;
  6170. }
  6171. if (AI_safety())
  6172. {
  6173. return;
  6174. }
  6175. getGroup()->pushMission(MISSION_SKIP);
  6176. return;
  6177. }
  6178. /************************************************************************************************/
  6179. /* BETTER_BTS_AI_MOD 02/23/10 jdog5000 */
  6180. /* */
  6181. /* Pirate AI */
  6182. /************************************************************************************************/
  6183. void CvUnitAI::AI_pirateSeaMove()
  6184. {
  6185. PROFILE_FUNC();
  6186. CvArea* pWaterArea;
  6187. // heal in defended, unthreatened forts and cities
  6188. if (plot()->isCity(true) && (GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(),0,true,false) > 0) && !(GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2, false)) )
  6189. {
  6190. if (AI_heal())
  6191. {
  6192. return;
  6193. }
  6194. }
  6195. if (plot()->isOwned() && (plot()->getTeam() == getTeam()))
  6196. {
  6197. if (AI_anyAttack(2, 55))
  6198. {
  6199. return;
  6200. }
  6201. //if (AI_protect(30))
  6202. if (AI_protect(40, 3))
  6203. {
  6204. return;
  6205. }
  6206. if (((AI_getBirthmark() / 8) % 2) == 0)
  6207. {
  6208. // Previously code actually blocked grouping
  6209. if (AI_group(UNITAI_PIRATE_SEA, -1, 1, -1, true, false, false, 8))
  6210. {
  6211. return;
  6212. }
  6213. }
  6214. }
  6215. else
  6216. {
  6217. if (AI_anyAttack(2, 51))
  6218. {
  6219. return;
  6220. }
  6221. }
  6222. if (GC.getGame().getSorenRandNum(10, "AI Pirate Explore") == 0)
  6223. {
  6224. pWaterArea = plot()->waterArea();
  6225. if (pWaterArea != NULL)
  6226. {
  6227. if (pWaterArea->getNumUnrevealedTiles(getTeam()) > 0)
  6228. {
  6229. if (GET_PLAYER(getOwnerINLINE()).AI_areaMissionAIs(pWaterArea, MISSIONAI_EXPLORE, getGroup()) < (GET_PLAYER(getOwnerINLINE()).AI_neededExplorers(pWaterArea)))
  6230. {
  6231. if (AI_exploreRange(2))
  6232. {
  6233. return;
  6234. }
  6235. }
  6236. }
  6237. }
  6238. }
  6239. if (GC.getGame().getSorenRandNum(11, "AI Pirate Pillage") == 0)
  6240. {
  6241. if (AI_pillageRange(1))
  6242. {
  6243. return;
  6244. }
  6245. }
  6246. //Includes heal and retreat to sea routines.
  6247. if (AI_pirateBlockade())
  6248. {
  6249. return;
  6250. }
  6251. if (AI_retreatToCity())
  6252. {
  6253. return;
  6254. }
  6255. if (AI_safety())
  6256. {
  6257. return;
  6258. }
  6259. getGroup()->pushMission(MISSION_SKIP);
  6260. return;
  6261. }
  6262. /************************************************************************************************/
  6263. /* BETTER_BTS_AI_MOD END */
  6264. /************************************************************************************************/
  6265. void CvUnitAI::AI_attackSeaMove()
  6266. {
  6267. PROFILE_FUNC();
  6268. /********************************************************************************/
  6269. /* BETTER_BTS_AI_MOD 06/14/09 Solver & jdog5000 */
  6270. /* */
  6271. /* Naval AI */
  6272. /********************************************************************************/
  6273. if (plot()->isCity(true))
  6274. {
  6275. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  6276. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  6277. if( getDamage() > 0 ) // extra risk to leaving when wounded
  6278. {
  6279. iOurDefense *= 2;
  6280. }
  6281. if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0) //prioritize getting outta there
  6282. {
  6283. if (AI_anyAttack(2, 50))
  6284. {
  6285. return;
  6286. }
  6287. if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34, false, true, getMoves()))
  6288. {
  6289. return;
  6290. }
  6291. /************************************************************************************************/
  6292. /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
  6293. /* */
  6294. /* Naval AI */
  6295. /************************************************************************************************/
  6296. //if (AI_protect(35))
  6297. if (AI_protect(35, 3))
  6298. /************************************************************************************************/
  6299. /* BETTER_BTS_AI_MOD END */
  6300. /************************************************************************************************/
  6301. {
  6302. return;
  6303. }
  6304. if (AI_retreatToCity())
  6305. {
  6306. return;
  6307. }
  6308. if (AI_safety())
  6309. {
  6310. return;
  6311. }
  6312. }
  6313. }
  6314. /********************************************************************************/
  6315. /* BETTER_BTS_AI_MOD END */
  6316. /********************************************************************************/
  6317. if (AI_heal(30, 1))
  6318. {
  6319. return;
  6320. }
  6321. if (AI_anyAttack(1, 55))
  6322. {
  6323. return;
  6324. }
  6325. if (AI_anyAttack(2, 60))
  6326. {
  6327. return;
  6328. }
  6329. if (AI_seaBombardRange(6))
  6330. {
  6331. return;
  6332. }
  6333. if (AI_heal(50, 3))
  6334. {
  6335. return;
  6336. }
  6337. if (AI_heal())
  6338. {
  6339. return;
  6340. }
  6341. /************************************************************************************************/
  6342. /* BETTER_BTS_AI_MOD 08/10/09 jdog5000 */
  6343. /* */
  6344. /* Naval AI */
  6345. /************************************************************************************************/
  6346. // BBAI TODO: Turn this into a function, have docked escort ships do it to
  6347. //Fuyu: search for more attackers, and when enough are found, always try to break through
  6348. CvCity* pCity = plot()->getPlotCity();
  6349. if( pCity != NULL )
  6350. {
  6351. if( pCity->isBlockaded() )
  6352. {
  6353. int iBlockadeRange = GC.getDefineINT("SHIP_BLOCKADE_RANGE");
  6354. // City under blockade
  6355. // Attacker has low odds since anyAttack checks above passed, try to break if sufficient numbers
  6356. int iAttackers = plot()->plotCount(PUF_isUnitAIType, UNITAI_ATTACK_SEA, -1, NO_PLAYER, getTeam(), PUF_isGroupHead, -1, -1);
  6357. int iBlockaders = GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), (iBlockadeRange + 1));
  6358. //bool bBreakBlockade = (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders);
  6359. if (true)
  6360. {
  6361. int iMaxRange = iBlockadeRange - 1;
  6362. if( gUnitLogLevel > 2 ) logBBAI(" Not enough attack fleet found in %S, searching for more in a %d-tile radius", pCity->getName().GetCString(), iMaxRange);
  6363. for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
  6364. {
  6365. for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
  6366. {
  6367. CvPlot* pLoopPlot = plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), iDX, iDY);
  6368. if (pLoopPlot != NULL && pLoopPlot->isWater())
  6369. {
  6370. if (pLoopPlot->getBlockadedCount(getTeam()) > 0)
  6371. {
  6372. iAttackers += pLoopPlot->plotCount(PUF_isUnitAIType, UNITAI_ATTACK_SEA, -1, NO_PLAYER, getTeam(), PUF_isGroupHead, -1, -1);
  6373. }
  6374. }
  6375. }
  6376. }
  6377. }
  6378. //bBreakBlockade = (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders);
  6379. //if (bBreakBlockade)
  6380. if (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders)
  6381. {
  6382. if( gUnitLogLevel > 2 ) logBBAI(" Found %d attackers and %d blockaders, proceeding to break blockade", iAttackers, iBlockaders);
  6383. if(true) /* (iAttackers > GC.getGameINLINE().getSorenRandNum(2*iBlockaders + 1, "AI - Break blockade")) */
  6384. {
  6385. // BBAI TODO: Make odds scale by # of blockaders vs number of attackers
  6386. if (baseMoves() >= iBlockadeRange)
  6387. {
  6388. if (AI_anyAttack(1, 15))
  6389. {
  6390. return;
  6391. }
  6392. }
  6393. else
  6394. {
  6395. //Fuyu: Even slow ships should attack
  6396. //Assuming that every ship can reach a blockade with 2 moves
  6397. if (AI_anyAttack(2, 15))
  6398. {
  6399. return;
  6400. }
  6401. }
  6402. //If no mission was pushed yet and we have a lot of ships, try again with even lower odds
  6403. if(iAttackers > 2*iBlockaders)
  6404. {
  6405. if (AI_anyAttack(1, 10))
  6406. {
  6407. return;
  6408. }
  6409. }
  6410. }
  6411. }
  6412. }
  6413. }
  6414. /************************************************************************************************/
  6415. /* BETTER_BTS_AI_MOD END */
  6416. /************************************************************************************************/
  6417. if (AI_group(UNITAI_CARRIER_SEA, /*iMaxGroup*/ 4, 1, -1, true, false, false, /*iMaxPath*/ 5))
  6418. {
  6419. return;
  6420. }
  6421. if (AI_group(UNITAI_ATTACK_SEA, /*iMaxGroup*/ 1, -1, -1, true, false, false, /*iMaxPath*/ 3))
  6422. {
  6423. return;
  6424. }
  6425. if (!plot()->isOwned() || !isEnemy(plot()->getTeam()))
  6426. {
  6427. /************************************************************************************************/
  6428. /* BETTER_BTS_AI_MOD 01/11/09 jdog5000 */
  6429. /* */
  6430. /* Naval AI */
  6431. /************************************************************************************************/
  6432. /* original bts code
  6433. if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34))
  6434. {
  6435. return;
  6436. }
  6437. if (AI_shadow(UNITAI_CARRIER_SEA, 4, 51))
  6438. {
  6439. return;
  6440. }
  6441. if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, -1, false, false, false))
  6442. {
  6443. return;
  6444. }
  6445. }
  6446. if (AI_group(UNITAI_CARRIER_SEA, -1, 1, -1, false, false, false))
  6447. {
  6448. return;
  6449. } */
  6450. // K-Mod / BBAI. I've changed the order of group / shadow.
  6451. // What I'd really like is to join the assault group if the group needs escorts, but shadow if it doesn't.
  6452. // Get at least one shadow per assault group.
  6453. if (AI_shadow(UNITAI_ASSAULT_SEA, 1, -1, true, false, 4))
  6454. {
  6455. return;
  6456. }
  6457. // Allow several attack_sea with large flotillas
  6458. if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, 4, false, false, false, 4, false, true, false))
  6459. {
  6460. return;
  6461. }
  6462. // allow just a couple with small asault teams
  6463. if (AI_group(UNITAI_ASSAULT_SEA, -1, 2, -1, false, false, false, 5, false, true, false))
  6464. {
  6465. return;
  6466. }
  6467. // Otherwise, try to shadow.
  6468. if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34, true, false, 4))
  6469. {
  6470. return;
  6471. }
  6472. if (AI_shadow(UNITAI_CARRIER_SEA, 4, 51, true, false, 5))
  6473. {
  6474. return;
  6475. }
  6476. }
  6477. if (AI_group(UNITAI_CARRIER_SEA, -1, 1, -1, false, false, false, 10))
  6478. {
  6479. return;
  6480. }
  6481. // K-Mod / BBAI end
  6482. if (plot()->isOwned() && (isEnemy(plot()->getTeam())))
  6483. {
  6484. if (AI_blockade())
  6485. {
  6486. return;
  6487. }
  6488. }
  6489. if (AI_pillageRange(4))
  6490. {
  6491. return;
  6492. }
  6493. /************************************************************************************************/
  6494. /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
  6495. /* */
  6496. /* Naval AI */
  6497. /************************************************************************************************/
  6498. //if (AI_protect(35))
  6499. if (AI_protect(35, 3))
  6500. {
  6501. return;
  6502. }
  6503. if (AI_protect(35, 8))
  6504. /************************************************************************************************/
  6505. /* BETTER_BTS_AI_MOD END */
  6506. /************************************************************************************************/
  6507. {
  6508. return;
  6509. }
  6510. if (AI_travelToUpgradeCity())
  6511. {
  6512. return;
  6513. }
  6514. // K-Mod
  6515. if (AI_guardBonus(10))
  6516. return;
  6517. if (AI_patrol())
  6518. {
  6519. return;
  6520. }
  6521. if (AI_retreatToCity())
  6522. {
  6523. return;
  6524. }
  6525. if (AI_safety())
  6526. {
  6527. return;
  6528. }
  6529. getGroup()->pushMission(MISSION_SKIP);
  6530. return;
  6531. }
  6532. void CvUnitAI::AI_reserveSeaMove()
  6533. {
  6534. PROFILE_FUNC();
  6535. /********************************************************************************/
  6536. /* BETTER_BTS_AI_MOD 06/14/09 Solver & jdog5000 */
  6537. /* */
  6538. /* Naval AI */
  6539. /********************************************************************************/
  6540. if (plot()->isCity(true))
  6541. {
  6542. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  6543. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  6544. if( getDamage() > 0 ) // extra risk to leaving when wounded
  6545. {
  6546. iOurDefense *= 2;
  6547. }
  6548. if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0) //prioritize getting outta there
  6549. {
  6550. if (AI_anyAttack(2, 60))
  6551. {
  6552. return;
  6553. }
  6554. /************************************************************************************************/
  6555. /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
  6556. /* */
  6557. /* Naval AI */
  6558. /************************************************************************************************/
  6559. //if (AI_protect(40))
  6560. if (AI_protect(40, 3))
  6561. /************************************************************************************************/
  6562. /* BETTER_BTS_AI_MOD END */
  6563. /************************************************************************************************/
  6564. {
  6565. return;
  6566. }
  6567. if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, getMoves()))
  6568. {
  6569. return;
  6570. }
  6571. if (AI_retreatToCity())
  6572. {
  6573. return;
  6574. }
  6575. if (AI_safety())
  6576. {
  6577. return;
  6578. }
  6579. }
  6580. }
  6581. /********************************************************************************/
  6582. /* BETTER_BTS_AI_MOD END */
  6583. /********************************************************************************/
  6584. if (AI_guardBonus(30))
  6585. {
  6586. return;
  6587. }
  6588. if (AI_heal(30, 1))
  6589. {
  6590. return;
  6591. }
  6592. if (AI_anyAttack(1, 55))
  6593. {
  6594. return;
  6595. }
  6596. if (AI_seaBombardRange(6))
  6597. {
  6598. return;
  6599. }
  6600. /************************************************************************************************/
  6601. /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
  6602. /* */
  6603. /* Naval AI */
  6604. /************************************************************************************************/
  6605. //if (AI_protect(40))
  6606. if (AI_protect(40, 5))
  6607. /************************************************************************************************/
  6608. /* BETTER_BTS_AI_MOD END */
  6609. /************************************************************************************************/
  6610. {
  6611. return;
  6612. }
  6613. /************************************************************************************************/
  6614. /* BETTER_BTS_AI_MOD 01/03/09 jdog5000 */
  6615. /* */
  6616. /* Naval AI */
  6617. /************************************************************************************************/
  6618. /* original bts code
  6619. if (AI_shadow(UNITAI_SETTLER_SEA, 1, -1, true))
  6620. {
  6621. return;
  6622. }
  6623. if (AI_group(UNITAI_RESERVE_SEA, 1))
  6624. {
  6625. return;
  6626. }
  6627. if (bombardRate() > 0)
  6628. {
  6629. if (AI_shadow(UNITAI_ASSAULT_SEA, 2, 30, true))
  6630. {
  6631. return;
  6632. }
  6633. }
  6634. */
  6635. // Shadow any nearby settler sea transport out at sea
  6636. if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 5))
  6637. {
  6638. return;
  6639. }
  6640. if (AI_group(UNITAI_RESERVE_SEA, 1, -1, -1, false, false, false, 8))
  6641. {
  6642. return;
  6643. }
  6644. if (bombardRate() > 0)
  6645. {
  6646. if (AI_shadow(UNITAI_ASSAULT_SEA, 2, 30, true, false, 8))
  6647. {
  6648. return;
  6649. }
  6650. }
  6651. /************************************************************************************************/
  6652. /* BETTER_BTS_AI_MOD END */
  6653. /************************************************************************************************/
  6654. if (AI_heal(50, 3))
  6655. {
  6656. return;
  6657. }
  6658. /************************************************************************************************/
  6659. /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
  6660. /* */
  6661. /* Naval AI */
  6662. /************************************************************************************************/
  6663. if (AI_protect(40))
  6664. {
  6665. return;
  6666. }
  6667. /************************************************************************************************/
  6668. /* BETTER_BTS_AI_MOD END */
  6669. /************************************************************************************************/
  6670. if (AI_anyAttack(3, 65))
  6671. {
  6672. return;
  6673. }
  6674. if (AI_heal())
  6675. {
  6676. return;
  6677. }
  6678. if (!isNeverInvisible())
  6679. {
  6680. if (AI_anyAttack(5, 55))
  6681. {
  6682. return;
  6683. }
  6684. }
  6685. /************************************************************************************************/
  6686. /* BETTER_BTS_AI_MOD 01/03/09 jdog5000 */
  6687. /* */
  6688. /* Naval AI */
  6689. /************************************************************************************************/
  6690. // Shadow settler transport with cargo
  6691. if (AI_shadow(UNITAI_SETTLER_SEA, 1, -1, true, false, 10))
  6692. {
  6693. return;
  6694. }
  6695. /************************************************************************************************/
  6696. /* BETTER_BTS_AI_MOD END */
  6697. /************************************************************************************************/
  6698. if (AI_travelToUpgradeCity())
  6699. {
  6700. return;
  6701. }
  6702. if (AI_patrol())
  6703. {
  6704. return;
  6705. }
  6706. if (AI_retreatToCity())
  6707. {
  6708. return;
  6709. }
  6710. if (AI_safety())
  6711. {
  6712. return;
  6713. }
  6714. getGroup()->pushMission(MISSION_SKIP);
  6715. return;
  6716. }
  6717. void CvUnitAI::AI_escortSeaMove()
  6718. {
  6719. PROFILE_FUNC();
  6720. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE()); // K-Mod
  6721. // // if we have cargo, possibly convert to UNITAI_ASSAULT_SEA (this will most often happen with galleons)
  6722. // // note, this should not happen when we are not the group head, so escort galleons are fine joining a group, just not as head
  6723. // if (hasCargo() && (getUnitAICargo(UNITAI_ATTACK_CITY) > 0 || getUnitAICargo(UNITAI_ATTACK) > 0))
  6724. // {
  6725. // // non-zero AI_unitValue means that UNITAI_ASSAULT_SEA is valid for this unit (that is the check used everywhere)
  6726. // if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_ASSAULT_SEA, NULL) > 0)
  6727. // {
  6728. // // save old group, so we can merge it back in
  6729. // CvSelectionGroup* pOldGroup = getGroup();
  6730. //
  6731. // // this will remove this unit from the current group
  6732. // AI_setUnitAIType(UNITAI_ASSAULT_SEA);
  6733. //
  6734. // // merge back the rest of the group into the new group
  6735. // CvSelectionGroup* pNewGroup = getGroup();
  6736. // if (pOldGroup != pNewGroup)
  6737. // {
  6738. // pOldGroup->mergeIntoGroup(pNewGroup);
  6739. // }
  6740. //
  6741. // // perform assault sea action
  6742. // AI_assaultSeaMove();
  6743. // return;
  6744. // }
  6745. // }
  6746. /********************************************************************************/
  6747. /* BETTER_BTS_AI_MOD 06/14/09 Solver & jdog5000 */
  6748. /* */
  6749. /* Naval AI */
  6750. /********************************************************************************/
  6751. if (plot()->isCity(true)) //prioritize getting outta there
  6752. {
  6753. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  6754. int iEnemyOffense = kOwner.AI_getEnemyPlotStrength(plot(),2,false,false);
  6755. if( getDamage() > 0 ) // extra risk to leaving when wounded
  6756. {
  6757. iOurDefense *= 2;
  6758. }
  6759. if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0)
  6760. {
  6761. if (AI_anyAttack(1, 60))
  6762. {
  6763. return;
  6764. }
  6765. if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 1, -1, /*bIgnoreFaster*/ true, false, false, /*iMaxPath*/ getMoves()))
  6766. {
  6767. return;
  6768. }
  6769. if (AI_retreatToCity())
  6770. {
  6771. return;
  6772. }
  6773. if (AI_safety())
  6774. {
  6775. return;
  6776. }
  6777. }
  6778. }
  6779. /********************************************************************************/
  6780. /* BETTER_BTS_AI_MOD END */
  6781. /********************************************************************************/
  6782. if (AI_heal(30, 1))
  6783. {
  6784. return;
  6785. }
  6786. if (AI_anyAttack(1, 55))
  6787. {
  6788. return;
  6789. }
  6790. /********************************************************************************/
  6791. /* BETTER_BTS_AI_MOD 9/14/08 jdog5000 */
  6792. /* */
  6793. /* Naval AI */
  6794. /********************************************************************************/
  6795. // Galleons can get stuck with this AI type since they don't upgrade to any escort unit
  6796. // Galleon escorts are much less useful once Frigates or later are available
  6797. if (!isHuman() && !isBarbarian())
  6798. {
  6799. if( getCargo() > 0 && (GC.getUnitInfo(getUnitType()).getSpecialCargo() == NO_SPECIALUNIT) )
  6800. {
  6801. //Obsolete?
  6802. int iValue = kOwner.AI_unitValue(getUnitType(), AI_getUnitAIType(), area());
  6803. int iBestValue = kOwner.AI_bestAreaUnitAIValue(AI_getUnitAIType(), area());
  6804. if (iValue < iBestValue)
  6805. {
  6806. if (kOwner.AI_unitValue(getUnitType(), UNITAI_ASSAULT_SEA, area()) > 0)
  6807. {
  6808. AI_setUnitAIType(UNITAI_ASSAULT_SEA);
  6809. return;
  6810. }
  6811. if (kOwner.AI_unitValue(getUnitType(), UNITAI_SETTLER_SEA, area()) > 0)
  6812. {
  6813. AI_setUnitAIType(UNITAI_SETTLER_SEA);
  6814. return;
  6815. }
  6816. scrap();
  6817. }
  6818. }
  6819. }
  6820. /********************************************************************************/
  6821. /* BETTER_BTS_AI_MOD END */
  6822. /********************************************************************************/
  6823. if (AI_group(UNITAI_CARRIER_SEA, -1, /*iMaxOwnUnitAI*/ 0, -1, /*bIgnoreFaster*/ true))
  6824. {
  6825. return;
  6826. }
  6827. if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ -1, -1, /*bIgnoreFaster*/ false, false, false, /*iMaxPath*/ 3))
  6828. {
  6829. return;
  6830. }
  6831. if (AI_heal(50, 3))
  6832. {
  6833. return;
  6834. }
  6835. if (AI_pillageRange(2))
  6836. {
  6837. return;
  6838. }
  6839. if (AI_group(UNITAI_MISSILE_CARRIER_SEA, 1, 1, true))
  6840. {
  6841. return;
  6842. }
  6843. if (AI_group(UNITAI_ASSAULT_SEA, 1, /*iMaxOwnUnitAI*/ -1, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ true))
  6844. {
  6845. return;
  6846. }
  6847. if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 2, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ true))
  6848. {
  6849. return;
  6850. }
  6851. if (AI_group(UNITAI_CARRIER_SEA, -1, /*iMaxOwnUnitAI*/ 2, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ true))
  6852. {
  6853. return;
  6854. }
  6855. /************************************************************************************************/
  6856. /* BETTER_BTS_AI_MOD 01/01/09 jdog5000 */
  6857. /* */
  6858. /* Naval AI */
  6859. /************************************************************************************************/
  6860. /* original bts code
  6861. if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, -1, true))
  6862. {
  6863. return;
  6864. }
  6865. */
  6866. // Group only with large flotillas first
  6867. if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 4, /*iMinUnitAI*/ 3, /*bIgnoreFaster*/ true))
  6868. {
  6869. return;
  6870. }
  6871. if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 4))
  6872. {
  6873. return;
  6874. }
  6875. /************************************************************************************************/
  6876. /* BETTER_BTS_AI_MOD END */
  6877. /************************************************************************************************/
  6878. if (AI_heal())
  6879. {
  6880. return;
  6881. }
  6882. if (AI_travelToUpgradeCity())
  6883. {
  6884. return;
  6885. }
  6886. /************************************************************************************************/
  6887. /* BETTER_BTS_AI_MOD 04/18/10 jdog5000 */
  6888. /* */
  6889. /* Naval AI */
  6890. /************************************************************************************************/
  6891. // If nothing else useful to do, escort nearby large flotillas even if they're faster
  6892. // Gives Caravel escorts something to do during the Galleon/pre-Frigate era
  6893. if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 4, /*iMinUnitAI*/ 3, /*bIgnoreFaster*/ false, false, false, 4, false, true))
  6894. {
  6895. return;
  6896. }
  6897. if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 2, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ false, false, false, 1, false, true))
  6898. {
  6899. return;
  6900. }
  6901. // Pull back to primary area if it's not too far so primary area cities know you exist
  6902. // and don't build more, unnecessary escorts
  6903. if (AI_retreatToCity(true,false,6))
  6904. {
  6905. return;
  6906. }
  6907. /************************************************************************************************/
  6908. /* BETTER_BTS_AI_MOD END */
  6909. /************************************************************************************************/
  6910. if (AI_retreatToCity())
  6911. {
  6912. return;
  6913. }
  6914. if (AI_safety())
  6915. {
  6916. return;
  6917. }
  6918. getGroup()->pushMission(MISSION_SKIP);
  6919. return;
  6920. }
  6921. void CvUnitAI::AI_exploreSeaMove()
  6922. {
  6923. PROFILE_FUNC();
  6924. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  6925. /********************************************************************************/
  6926. /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
  6927. /* */
  6928. /* Naval AI */
  6929. /********************************************************************************/
  6930. if (plot()->isCity(true)) //prioritize getting outta there
  6931. {
  6932. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  6933. int iEnemyOffense = kOwner.AI_getEnemyPlotStrength(plot(),2,false,false);
  6934. if( getDamage() > 0 ) // extra risk to leaving when wounded
  6935. {
  6936. iOurDefense *= 2;
  6937. }
  6938. if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 )
  6939. {
  6940. if (!isHuman())
  6941. {
  6942. if (AI_anyAttack(1, 60))
  6943. {
  6944. return;
  6945. }
  6946. }
  6947. if (AI_retreatToCity())
  6948. {
  6949. return;
  6950. }
  6951. if (AI_safety())
  6952. {
  6953. return;
  6954. }
  6955. }
  6956. }
  6957. /********************************************************************************/
  6958. /* BETTER_BTS_AI_MOD END */
  6959. /********************************************************************************/
  6960. if (!isHuman())
  6961. {
  6962. if (AI_exploreLairSea(6))
  6963. {
  6964. return;
  6965. }
  6966. }
  6967. CvArea* pWaterArea = plot()->waterArea();
  6968. if (!isHuman())
  6969. {
  6970. if (AI_anyAttack(1, 60))
  6971. {
  6972. return;
  6973. }
  6974. }
  6975. if (!isHuman() && !isBarbarian()) //XXX move some of this into a function? maybe useful elsewhere
  6976. {
  6977. //Obsolete?
  6978. int iValue = kOwner.AI_unitValue(getUnitType(), AI_getUnitAIType(), area());
  6979. int iBestValue = kOwner.AI_bestAreaUnitAIValue(AI_getUnitAIType(), area());
  6980. if (iValue < iBestValue)
  6981. {
  6982. //Transform
  6983. if (kOwner.AI_unitValue(getUnitType(), UNITAI_WORKER_SEA, area()) > 0)
  6984. {
  6985. AI_setUnitAIType(UNITAI_WORKER_SEA);
  6986. return;
  6987. }
  6988. if (kOwner.AI_unitValue(getUnitType(), UNITAI_PIRATE_SEA, area()) > 0)
  6989. {
  6990. AI_setUnitAIType(UNITAI_PIRATE_SEA);
  6991. return;
  6992. }
  6993. if (kOwner.AI_unitValue(getUnitType(), UNITAI_MISSIONARY_SEA, area()) > 0)
  6994. {
  6995. AI_setUnitAIType(UNITAI_MISSIONARY_SEA);
  6996. return;
  6997. }
  6998. if (kOwner.AI_unitValue(getUnitType(), UNITAI_RESERVE_SEA, area()) > 0)
  6999. {
  7000. AI_setUnitAIType(UNITAI_RESERVE_SEA);
  7001. return;
  7002. }
  7003. scrap();
  7004. }
  7005. }
  7006. if (AI_heal())
  7007. {
  7008. return;
  7009. }
  7010. if (!isHuman())
  7011. {
  7012. if (AI_pillageRange(1))
  7013. {
  7014. return;
  7015. }
  7016. }
  7017. if (AI_exploreRange(4))
  7018. {
  7019. return;
  7020. }
  7021. if (!isHuman())
  7022. {
  7023. if (AI_pillageRange(4))
  7024. {
  7025. return;
  7026. }
  7027. }
  7028. if (AI_explore())
  7029. {
  7030. return;
  7031. }
  7032. if (!isHuman())
  7033. {
  7034. if (AI_pillage())
  7035. {
  7036. return;
  7037. }
  7038. }
  7039. if (!isHuman())
  7040. {
  7041. if (AI_travelToUpgradeCity())
  7042. {
  7043. return;
  7044. }
  7045. }
  7046. if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
  7047. {
  7048. pWaterArea = plot()->waterArea();
  7049. if (pWaterArea != NULL)
  7050. {
  7051. if (kOwner.AI_totalWaterAreaUnitAIs(pWaterArea, UNITAI_EXPLORE_SEA) > kOwner.AI_neededExplorers(pWaterArea))
  7052. {
  7053. if (kOwner.calculateUnitCost() > 0)
  7054. {
  7055. scrap();
  7056. return;
  7057. }
  7058. }
  7059. }
  7060. }
  7061. if (AI_patrol())
  7062. {
  7063. return;
  7064. }
  7065. if (AI_retreatToCity())
  7066. {
  7067. return;
  7068. }
  7069. if (AI_safety())
  7070. {
  7071. return;
  7072. }
  7073. getGroup()->pushMission(MISSION_SKIP);
  7074. return;
  7075. }
  7076. /************************************************************************************************/
  7077. /* BETTER_BTS_AI_MOD 04/18/10 jdog5000 */
  7078. /* */
  7079. /* Naval AI */
  7080. /************************************************************************************************/
  7081. void CvUnitAI::AI_assaultSeaMove()
  7082. {
  7083. PROFILE_FUNC();
  7084. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE()); // K-Mod
  7085. FAssert(AI_getUnitAIType() == UNITAI_ASSAULT_SEA);
  7086. bool bEmpty = !getGroup()->hasCargo();
  7087. bool bFull = (getGroup()->AI_isFull() && (getGroup()->getCargo() > 0));
  7088. if( gUnitLogLevel >= 2 )
  7089. {
  7090. logBBAI(" Stack %d (led by %S (%d), size %d) starting assaultSeaMove (cargo: %d)", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits(), getGroup()->getCargo());
  7091. }
  7092. if (plot()->isCity(true))
  7093. {
  7094. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  7095. int iEnemyOffense = kOwner.AI_getEnemyPlotStrength(plot(),2,false,false);
  7096. if( getDamage() > 0 ) // extra risk to leaving when wounded
  7097. {
  7098. iOurDefense *= 2;
  7099. }
  7100. if (iEnemyOffense > iOurDefense/4) // was 1 vs 1/8
  7101. {
  7102. if (iEnemyOffense > iOurDefense/2) // was 1 vs 1/4
  7103. {
  7104. if( !bEmpty )
  7105. {
  7106. getGroup()->unloadAll();
  7107. }
  7108. if (AI_anyAttack(1, 65))
  7109. {
  7110. return;
  7111. }
  7112. // Retreat to primary area first
  7113. if (AI_retreatToCity(true))
  7114. {
  7115. return;
  7116. }
  7117. if (AI_retreatToCity())
  7118. {
  7119. return;
  7120. }
  7121. if (AI_safety())
  7122. {
  7123. return;
  7124. }
  7125. }
  7126. if( !bFull && !bEmpty )
  7127. {
  7128. getGroup()->unloadAll();
  7129. getGroup()->pushMission(MISSION_SKIP);
  7130. return;
  7131. }
  7132. }
  7133. }
  7134. if (bEmpty)
  7135. {
  7136. if (AI_anyAttack(1, 65))
  7137. {
  7138. return;
  7139. }
  7140. }
  7141. bool bReinforce = false;
  7142. bool bAttack = false;
  7143. bool bNoWarPlans = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) == 0);
  7144. bool bAttackBarbarian = false;
  7145. //bool bLandWar = false;
  7146. bool bIsBarbarian = isBarbarian();
  7147. // Count forts as cities
  7148. bool bIsCity = plot()->isCity(true);
  7149. // Cargo if already at war
  7150. int iTargetReinforcementSize = (bIsBarbarian ? 2 : AI_stackOfDoomExtra());
  7151. // Cargo to launch a new invasion
  7152. int iTargetInvasionSize = 2 * iTargetReinforcementSize;
  7153. int iCargo = getGroup()->getCargo();
  7154. int iEscorts = getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA) + getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA);
  7155. AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
  7156. //bLandWar = !bIsBarbarian && ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
  7157. bool bLandWar = !bIsBarbarian && kOwner.AI_isLandWar(area()); // K-Mod
  7158. // Plot danger case handled above
  7159. if( hasCargo() && (getUnitAICargo(UNITAI_SETTLE) > 0 || getUnitAICargo(UNITAI_WORKER) > 0) )
  7160. {
  7161. // Dump inappropriate load at first oppurtunity after pick up
  7162. if( bIsCity && (plot()->getOwnerINLINE() == getOwnerINLINE()) )
  7163. {
  7164. getGroup()->unloadAll();
  7165. getGroup()->pushMission(MISSION_SKIP);
  7166. return;
  7167. }
  7168. else
  7169. {
  7170. if( !isFull() )
  7171. {
  7172. if(AI_pickupStranded(NO_UNITAI, 1))
  7173. {
  7174. return;
  7175. }
  7176. }
  7177. if (AI_retreatToCity(true))
  7178. {
  7179. return;
  7180. }
  7181. if (AI_retreatToCity())
  7182. {
  7183. return;
  7184. }
  7185. }
  7186. }
  7187. if (bIsCity)
  7188. {
  7189. CvCity* pCity = plot()->getPlotCity();
  7190. if( pCity != NULL && (plot()->getOwnerINLINE() == getOwnerINLINE()) )
  7191. {
  7192. // split out galleys from stack of ocean capable ships
  7193. if( kOwner.AI_unitImpassableCount(getUnitType()) == 0 && getGroup()->getNumUnits() > 1 )
  7194. {
  7195. logBBAI(" ...separating from Galleys");
  7196. getGroup()->AI_separateImpassable();
  7197. }
  7198. // galleys with upgrade available should get that ASAP
  7199. if( kOwner.AI_unitImpassableCount(getUnitType()) > 0 )
  7200. {
  7201. CvCity* pUpgradeCity = getUpgradeCity(false);
  7202. if( pUpgradeCity != NULL && pUpgradeCity == pCity )
  7203. {
  7204. // Wait for upgrade, this unit is top upgrade priority
  7205. logBBAI(" ...skipping turn while waiting for upgrades");
  7206. getGroup()->pushMission(MISSION_SKIP);
  7207. return;
  7208. }
  7209. }
  7210. }
  7211. if( (iCargo > 0) )
  7212. {
  7213. if( pCity != NULL )
  7214. {
  7215. if( (GC.getGameINLINE().getGameTurn() - pCity->getGameTurnAcquired()) <= 1 )
  7216. {
  7217. if( pCity->getPreviousOwner() != NO_PLAYER )
  7218. {
  7219. // Just captured city, probably from naval invasion. If area targets, drop cargo and leave so as to not to be lost in quick counter attack
  7220. if( GET_TEAM(getTeam()).countEnemyPowerByArea(plot()->area()) > 0 )
  7221. {
  7222. getGroup()->unloadAll();
  7223. if( iEscorts > 2 )
  7224. {
  7225. if( getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA) > 1 && getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA) > 0 )
  7226. {
  7227. getGroup()->AI_separateAI(UNITAI_ATTACK_SEA);
  7228. getGroup()->AI_separateAI(UNITAI_RESERVE_SEA);
  7229. iEscorts = getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA);
  7230. }
  7231. }
  7232. iCargo = getGroup()->getCargo();
  7233. }
  7234. }
  7235. }
  7236. }
  7237. }
  7238. if( (iCargo > 0) && (iEscorts == 0) )
  7239. {
  7240. if (AI_group(UNITAI_ASSAULT_SEA,-1,-1,-1,/*bIgnoreFaster*/true,false,false,/*iMaxPath*/1,false,/*bCargoOnly*/true,false,MISSIONAI_ASSAULT))
  7241. {
  7242. return;
  7243. }
  7244. if( plot()->plotCount(PUF_isUnitAIType, UNITAI_ESCORT_SEA, -1, getOwnerINLINE(), NO_TEAM, PUF_isGroupHead, -1, -1) > 0 )
  7245. {
  7246. // Loaded but with no escort, wait for escorts in plot to join us
  7247. logBBAI(" ...waiting for escorts");
  7248. getGroup()->pushMission(MISSION_SKIP);
  7249. return;
  7250. }
  7251. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  7252. if( (kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 3) > 0) || (kOwner.AI_getWaterDanger(plot(), 4, false) > 0) )
  7253. {
  7254. // Loaded but with no escort, wait for others joining us soon or avoid dangerous waters
  7255. logBBAI(" ...waiting for joiners");
  7256. getGroup()->pushMission(MISSION_SKIP);
  7257. return;
  7258. }
  7259. }
  7260. if (bLandWar)
  7261. {
  7262. if ( iCargo > 0 )
  7263. {
  7264. if( (eAreaAIType == AREAAI_DEFENSIVE) || (pCity != NULL && pCity->AI_isDanger()))
  7265. {
  7266. // Unload cargo when on defense or if small load of troops and can reach enemy city over land (generally less risky)
  7267. getGroup()->unloadAll();
  7268. getGroup()->pushMission(MISSION_SKIP);
  7269. return;
  7270. }
  7271. }
  7272. if (iCargo >= iTargetReinforcementSize)
  7273. {
  7274. getGroup()->AI_separateEmptyTransports();
  7275. if( !(getGroup()->hasCargo()) )
  7276. {
  7277. // this unit was empty group leader
  7278. getGroup()->pushMission(MISSION_SKIP);
  7279. return;
  7280. }
  7281. // Send ready transports
  7282. if (AI_assaultSeaReinforce(false))
  7283. {
  7284. return;
  7285. }
  7286. if( iCargo >= iTargetInvasionSize )
  7287. {
  7288. if (AI_assaultSeaTransport(false))
  7289. {
  7290. return;
  7291. }
  7292. }
  7293. }
  7294. }
  7295. else
  7296. {
  7297. if ( (eAreaAIType == AREAAI_ASSAULT) || (getGroup()->AI_getMissionAIType() == MISSIONAI_ASSAULT))
  7298. {
  7299. if( iCargo >= iTargetInvasionSize )
  7300. {
  7301. bAttack = true;
  7302. }
  7303. }
  7304. if( (eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) )
  7305. {
  7306. if( (bFull && iCargo > cargoSpace()) || (iCargo >= iTargetReinforcementSize) )
  7307. {
  7308. bReinforce = true;
  7309. }
  7310. }
  7311. }
  7312. if( !bAttack && !bReinforce && (plot()->getTeam() == getTeam()) )
  7313. {
  7314. if( iEscorts > 3 && iEscorts > (2*getGroup()->countNumUnitAIType(UNITAI_ASSAULT_SEA)) )
  7315. {
  7316. // If we have too many escorts, try freeing some for others
  7317. getGroup()->AI_separateAI(UNITAI_ATTACK_SEA);
  7318. getGroup()->AI_separateAI(UNITAI_RESERVE_SEA);
  7319. iEscorts = getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA);
  7320. if( iEscorts > 3 && iEscorts > (2*getGroup()->countNumUnitAIType(UNITAI_ASSAULT_SEA)) )
  7321. {
  7322. logBBAI(" ...freeing up escorts");
  7323. getGroup()->AI_separateAI(UNITAI_ESCORT_SEA);
  7324. }
  7325. }
  7326. }
  7327. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  7328. if( kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
  7329. {
  7330. // Wait for units which are joining our group this turn
  7331. logBBAI(" ...waiting for joiners 2");
  7332. getGroup()->pushMission(MISSION_SKIP);
  7333. return;
  7334. }
  7335. if( !bFull )
  7336. {
  7337. if( bAttack )
  7338. {
  7339. eMissionAIType = MISSIONAI_LOAD_ASSAULT;
  7340. if( kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
  7341. {
  7342. // Wait for cargo which will load this turn
  7343. logBBAI(" ...waiting for nearby cargo to load");
  7344. getGroup()->pushMission(MISSION_SKIP);
  7345. return;
  7346. }
  7347. }
  7348. else if( kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_ASSAULT) > 0 )
  7349. {
  7350. // Wait for cargo which is on the way
  7351. logBBAI(" ...waiting for any cargo on the way");
  7352. getGroup()->pushMission(MISSION_SKIP);
  7353. return;
  7354. }
  7355. }
  7356. if( !bAttack && !bReinforce )
  7357. {
  7358. if ( iCargo > 0 )
  7359. {
  7360. if (AI_group(UNITAI_ASSAULT_SEA,-1,-1,-1,/*bIgnoreFaster*/true,false,false,/*iMaxPath*/5,false,/*bCargoOnly*/true,false,MISSIONAI_ASSAULT))
  7361. {
  7362. return;
  7363. }
  7364. }
  7365. else if (plot()->getTeam() == getTeam() && getGroup()->getNumUnits() > 1)
  7366. {
  7367. CvCity* pCity = plot()->getPlotCity();
  7368. if( pCity != NULL && (GC.getGameINLINE().getGameTurn() - pCity->getGameTurnAcquired()) > 10 )
  7369. {
  7370. if( pCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, UNITAI_ATTACK_CITY, -1, getOwnerINLINE()) < iTargetReinforcementSize )
  7371. {
  7372. // Not attacking, no cargo so release any escorts, attack ships, etc and split transports
  7373. getGroup()->AI_makeForceSeparate();
  7374. }
  7375. }
  7376. }
  7377. }
  7378. }
  7379. if (!bIsCity)
  7380. {
  7381. if( iCargo >= iTargetInvasionSize )
  7382. {
  7383. bAttack = true;
  7384. }
  7385. if ((iCargo >= iTargetReinforcementSize) || (bFull && iCargo > cargoSpace()))
  7386. {
  7387. bReinforce = true;
  7388. }
  7389. CvPlot* pAdjacentPlot = NULL;
  7390. for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  7391. {
  7392. pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
  7393. if( pAdjacentPlot != NULL )
  7394. {
  7395. if( iCargo > 0 )
  7396. {
  7397. CvCity* pAdjacentCity = pAdjacentPlot->getPlotCity();
  7398. if( pAdjacentCity != NULL)
  7399. {
  7400. if ( GET_TEAM(getTeam()).AI_getWarPlan(pAdjacentPlot->getTeam()) != NO_WARPLAN)
  7401. {
  7402. bAttack = true;
  7403. }
  7404. if (pAdjacentCity->getOwner() == getOwnerINLINE() && pAdjacentCity->getPreviousOwner() != NO_PLAYER )
  7405. {
  7406. if( (GC.getGameINLINE().getGameTurn() - pAdjacentCity->getGameTurnAcquired()) < 5 )
  7407. {
  7408. // If just captured city and we have some cargo, dump units in city
  7409. getGroup()->pushMission(MISSION_MOVE_TO, pAdjacentPlot->getX_INLINE(), pAdjacentPlot->getY_INLINE(), 0, false, false, MISSIONAI_ASSAULT, pAdjacentPlot);
  7410. return;
  7411. }
  7412. }
  7413. }
  7414. }
  7415. else
  7416. {
  7417. if (pAdjacentPlot->isOwned() && isEnemy(pAdjacentPlot->getTeam()))
  7418. {
  7419. if( pAdjacentPlot->getNumDefenders(getOwnerINLINE()) > 2 )
  7420. {
  7421. // if we just made a dropoff in enemy territory, release sea bombard units to support invaders
  7422. if ((getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA) + getGroup()->countNumUnitAIType(UNITAI_RESERVE_SEA)) > 0)
  7423. {
  7424. bool bMissionPushed = false;
  7425. if (AI_seaBombardRange(1))
  7426. {
  7427. bMissionPushed = true;
  7428. }
  7429. CvSelectionGroup* pOldGroup = getGroup();
  7430. //Release any Warships to finish the job.
  7431. getGroup()->AI_separateAI(UNITAI_ATTACK_SEA);
  7432. getGroup()->AI_separateAI(UNITAI_RESERVE_SEA);
  7433. /************************************************************************************************/
  7434. /* UNOFFICIAL_PATCH 05/11/09 jdog5000 */
  7435. /* */
  7436. /* Bugfix */
  7437. /************************************************************************************************/
  7438. /* original bts code
  7439. if (pOldGroup == getGroup() && getUnitType() == UNITAI_ASSAULT_SEA)
  7440. {
  7441. if (AI_retreatToCity(true))
  7442. {
  7443. bMissionPushed = true;
  7444. }
  7445. }
  7446. */
  7447. // Fixed bug in next line with checking unit type instead of unit AI
  7448. if (pOldGroup == getGroup() && AI_getUnitAIType() == UNITAI_ASSAULT_SEA)
  7449. {
  7450. // Need to be sure all units can move
  7451. if( getGroup()->canAllMove() )
  7452. {
  7453. if (AI_retreatToCity(true))
  7454. {
  7455. bMissionPushed = true;
  7456. }
  7457. }
  7458. }
  7459. /************************************************************************************************/
  7460. /* UNOFFICIAL_PATCH END */
  7461. /************************************************************************************************/
  7462. if (bMissionPushed)
  7463. {
  7464. return;
  7465. }
  7466. }
  7467. }
  7468. }
  7469. }
  7470. }
  7471. }
  7472. if(iCargo > 0)
  7473. {
  7474. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  7475. if( kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
  7476. {
  7477. if( iEscorts < GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), 2, false) )
  7478. {
  7479. // Wait for units which are joining our group this turn (hopefully escorts)
  7480. getGroup()->pushMission(MISSION_SKIP);
  7481. return;
  7482. }
  7483. }
  7484. }
  7485. }
  7486. if (bIsBarbarian)
  7487. {
  7488. if (getGroup()->isFull() || iCargo > iTargetInvasionSize)
  7489. {
  7490. if (AI_assaultSeaTransport(false))
  7491. {
  7492. return;
  7493. }
  7494. }
  7495. else
  7496. {
  7497. if (AI_pickup(UNITAI_ATTACK_CITY, true, 5))
  7498. {
  7499. return;
  7500. }
  7501. if (AI_pickup(UNITAI_ATTACK, true, 5))
  7502. {
  7503. return;
  7504. }
  7505. if (AI_retreatToCity())
  7506. {
  7507. return;
  7508. }
  7509. if( !(getGroup()->getCargo()) )
  7510. {
  7511. AI_barbAttackSeaMove();
  7512. return;
  7513. }
  7514. if( AI_safety() )
  7515. {
  7516. return;
  7517. }
  7518. getGroup()->pushMission(MISSION_SKIP);
  7519. return;
  7520. }
  7521. }
  7522. else
  7523. {
  7524. if (bAttack || bReinforce)
  7525. {
  7526. if( bIsCity )
  7527. {
  7528. getGroup()->AI_separateEmptyTransports();
  7529. }
  7530. if( !(getGroup()->hasCargo()) )
  7531. {
  7532. // this unit was empty group leader
  7533. getGroup()->pushMission(MISSION_SKIP);
  7534. return;
  7535. }
  7536. FAssert(getGroup()->hasCargo());
  7537. //BBAI TODO: Check that group has escorts, otherwise usually wait
  7538. if( bAttack )
  7539. {
  7540. if( bReinforce && (AI_getBirthmark()%2 == 0) )
  7541. {
  7542. if (AI_assaultSeaReinforce())
  7543. {
  7544. return;
  7545. }
  7546. bReinforce = false;
  7547. }
  7548. if (AI_assaultSeaTransport())
  7549. {
  7550. return;
  7551. }
  7552. }
  7553. // If not enough troops for own invasion,
  7554. if( bReinforce )
  7555. {
  7556. if (AI_assaultSeaReinforce())
  7557. {
  7558. return;
  7559. }
  7560. }
  7561. }
  7562. if( bNoWarPlans && (iCargo >= iTargetReinforcementSize) )
  7563. {
  7564. bAttackBarbarian = true;
  7565. getGroup()->AI_separateEmptyTransports();
  7566. if( !(getGroup()->hasCargo()) )
  7567. {
  7568. // this unit was empty group leader
  7569. getGroup()->pushMission(MISSION_SKIP);
  7570. return;
  7571. }
  7572. FAssert(getGroup()->hasCargo());
  7573. if (AI_assaultSeaReinforce(bAttackBarbarian))
  7574. {
  7575. return;
  7576. }
  7577. FAssert(getGroup()->hasCargo());
  7578. if (AI_assaultSeaTransport(bAttackBarbarian))
  7579. {
  7580. return;
  7581. }
  7582. }
  7583. }
  7584. if ((bFull || bReinforce) && !bAttack)
  7585. {
  7586. // Group with nearby transports with units on board
  7587. /* original code
  7588. if (AI_group(UNITAI_ASSAULT_SEA, -1, -1, -1, true, false, false, 2, false, true, false, MISSIONAI_ASSAULT))
  7589. {
  7590. return;
  7591. } */ // disabled by K-Mod. This is redundant.
  7592. if (AI_group(UNITAI_ASSAULT_SEA, -1, -1, -1, true, false, false, 10, false, true, false, MISSIONAI_ASSAULT))
  7593. {
  7594. return;
  7595. }
  7596. }
  7597. else if( !bFull )
  7598. {
  7599. bool bHasOneLoad = (getGroup()->getCargo() >= cargoSpace());
  7600. bool bHasCargo = getGroup()->hasCargo();
  7601. if (AI_pickup(UNITAI_ATTACK_CITY, !bHasCargo, (bHasOneLoad ? 3 : 7)))
  7602. {
  7603. return;
  7604. }
  7605. if (AI_pickup(UNITAI_ATTACK, !bHasCargo, (bHasOneLoad ? 3 : 7)))
  7606. {
  7607. return;
  7608. }
  7609. if (AI_pickup(UNITAI_COUNTER, !bHasCargo, (bHasOneLoad ? 3 : 7)))
  7610. {
  7611. return;
  7612. }
  7613. if (AI_pickup(UNITAI_ATTACK_CITY, !bHasCargo))
  7614. {
  7615. return;
  7616. }
  7617. if( !bHasCargo )
  7618. {
  7619. if(AI_pickupStranded(UNITAI_ATTACK_CITY))
  7620. {
  7621. return;
  7622. }
  7623. if(AI_pickupStranded(UNITAI_ATTACK))
  7624. {
  7625. return;
  7626. }
  7627. if(AI_pickupStranded(UNITAI_COUNTER))
  7628. {
  7629. return;
  7630. }
  7631. if( (getGroup()->countNumUnitAIType(AI_getUnitAIType()) == 1) )
  7632. {
  7633. // Try picking up any thing
  7634. if(AI_pickupStranded())
  7635. {
  7636. return;
  7637. }
  7638. }
  7639. }
  7640. }
  7641. if (bIsCity && bLandWar && getGroup()->hasCargo())
  7642. {
  7643. // Enemy units in this player's territory
  7644. if( kOwner.AI_countNumAreaHostileUnits(area(),true,false,false,false) > (getGroup()->getCargo()/2))
  7645. {
  7646. getGroup()->unloadAll();
  7647. getGroup()->pushMission(MISSION_SKIP);
  7648. return;
  7649. }
  7650. }
  7651. if (AI_retreatToCity(true))
  7652. {
  7653. return;
  7654. }
  7655. if (AI_retreatToCity())
  7656. {
  7657. return;
  7658. }
  7659. if (AI_safety())
  7660. {
  7661. return;
  7662. }
  7663. getGroup()->pushMission(MISSION_SKIP);
  7664. return;
  7665. }
  7666. /************************************************************************************************/
  7667. /* BETTER_BTS_AI_MOD END */
  7668. /************************************************************************************************/
  7669. void CvUnitAI::AI_settlerSeaMove()
  7670. {
  7671. PROFILE_FUNC();
  7672. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  7673. if( gUnitLogLevel >= 2 )
  7674. {
  7675. logBBAI(" Stack %d (led by %S (%d), size %d, cargo %d) starting settleSeaMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits(), getGroup()->getCargo());
  7676. }
  7677. bool bEmpty = !getGroup()->hasCargo();
  7678. /********************************************************************************/
  7679. /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
  7680. /* */
  7681. /* Naval AI */
  7682. /********************************************************************************/
  7683. if (plot()->isCity(true))
  7684. {
  7685. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  7686. int iEnemyOffense = kOwner.AI_getEnemyPlotStrength(plot(),2,false,false);
  7687. if( getDamage() > 0 ) // extra risk to leaving when wounded
  7688. {
  7689. iOurDefense *= 2;
  7690. }
  7691. if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
  7692. {
  7693. if( bEmpty )
  7694. {
  7695. if (AI_anyAttack(1, 65))
  7696. {
  7697. return;
  7698. }
  7699. }
  7700. // Retreat to primary area first
  7701. if (AI_retreatToCity(true))
  7702. {
  7703. return;
  7704. }
  7705. if (AI_retreatToCity())
  7706. {
  7707. return;
  7708. }
  7709. if (AI_safety())
  7710. {
  7711. return;
  7712. }
  7713. }
  7714. }
  7715. /********************************************************************************/
  7716. /* BETTER_BTS_AI_MOD END */
  7717. /********************************************************************************/
  7718. if (bEmpty)
  7719. {
  7720. if (AI_anyAttack(1, 65))
  7721. {
  7722. return;
  7723. }
  7724. }
  7725. int iSettlerCount = getUnitAICargo(UNITAI_SETTLE);
  7726. int iWorkerCount = getUnitAICargo(UNITAI_WORKER);
  7727. /************************************************************************************************/
  7728. /* BETTER_BTS_AI_MOD 12/07/08 jdog5000 */
  7729. /* */
  7730. /* Naval AI */
  7731. /************************************************************************************************/
  7732. if( hasCargo() && (iSettlerCount == 0) && (iWorkerCount == 0))
  7733. {
  7734. // Dump troop load at first oppurtunity after pick up
  7735. if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
  7736. {
  7737. getGroup()->unloadAll();
  7738. getGroup()->pushMission(MISSION_SKIP);
  7739. return;
  7740. }
  7741. else
  7742. {
  7743. if( !(isFull()) )
  7744. {
  7745. if(AI_pickupStranded(NO_UNITAI, 1))
  7746. {
  7747. return;
  7748. }
  7749. }
  7750. if (AI_retreatToCity(true))
  7751. {
  7752. return;
  7753. }
  7754. if (AI_retreatToCity())
  7755. {
  7756. return;
  7757. }
  7758. }
  7759. }
  7760. /************************************************************************************************/
  7761. /* BETTER_BTS_AI_MOD END */
  7762. /************************************************************************************************/
  7763. /************************************************************************************************/
  7764. /* BETTER_BTS_AI_MOD 06/02/09 jdog5000 */
  7765. /* */
  7766. /* Settler AI */
  7767. /************************************************************************************************/
  7768. // Don't send transport with settler and no defense
  7769. if( (iSettlerCount > 0) && (iSettlerCount + iWorkerCount == cargoSpace()) )
  7770. {
  7771. // No defenders for settler
  7772. if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
  7773. {
  7774. getGroup()->unloadAll();
  7775. getGroup()->pushMission(MISSION_SKIP);
  7776. return;
  7777. }
  7778. }
  7779. if ((iSettlerCount > 0) && (isFull() ||
  7780. ((getUnitAICargo(UNITAI_CITY_DEFENSE) > 0) &&
  7781. (kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SETTLER) == 0))))
  7782. /************************************************************************************************/
  7783. /* BETTER_BTS_AI_MOD END */
  7784. /************************************************************************************************/
  7785. {
  7786. if (AI_settlerSeaTransport())
  7787. {
  7788. return;
  7789. }
  7790. }
  7791. else if ((getTeam() != plot()->getTeam()) && bEmpty)
  7792. {
  7793. if (AI_pillageRange(3))
  7794. {
  7795. return;
  7796. }
  7797. }
  7798. /************************************************************************************************/
  7799. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  7800. /* */
  7801. /* Naval AI */
  7802. /************************************************************************************************/
  7803. if (plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() && !hasCargo())
  7804. /************************************************************************************************/
  7805. /* BETTER_BTS_AI_MOD END */
  7806. /************************************************************************************************/
  7807. {
  7808. AreaAITypes eAreaAI = area()->getAreaAIType(getTeam());
  7809. if ((eAreaAI == AREAAI_ASSAULT) || (eAreaAI == AREAAI_ASSAULT_MASSING))
  7810. {
  7811. CvArea* pWaterArea = plot()->waterArea();
  7812. FAssert(pWaterArea != NULL);
  7813. if (pWaterArea != NULL)
  7814. {
  7815. if (kOwner.AI_totalWaterAreaUnitAIs(pWaterArea, UNITAI_SETTLER_SEA) > 1)
  7816. {
  7817. if (kOwner.AI_unitValue(getUnitType(), UNITAI_ASSAULT_SEA, pWaterArea) > 0)
  7818. {
  7819. AI_setUnitAIType(UNITAI_ASSAULT_SEA);
  7820. AI_assaultSeaMove();
  7821. return;
  7822. }
  7823. }
  7824. }
  7825. }
  7826. }
  7827. if ((iWorkerCount > 0)
  7828. && kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SETTLER) == 0)
  7829. {
  7830. if (isFull() || (iSettlerCount == 0))
  7831. {
  7832. if (AI_settlerSeaFerry())
  7833. {
  7834. return;
  7835. }
  7836. }
  7837. }
  7838. /************************************************************************************************/
  7839. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  7840. /* */
  7841. /* Settler AI */
  7842. /************************************************************************************************/
  7843. /* original bts code
  7844. if (AI_pickup(UNITAI_SETTLE))
  7845. {
  7846. return;
  7847. }
  7848. */
  7849. if( !(getGroup()->hasCargo()) )
  7850. {
  7851. if(AI_pickupStranded(UNITAI_SETTLE))
  7852. {
  7853. return;
  7854. }
  7855. }
  7856. if( !(getGroup()->isFull()) )
  7857. {
  7858. if( kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SETTLER) > 0 )
  7859. {
  7860. // Wait for units on the way
  7861. getGroup()->pushMission(MISSION_SKIP);
  7862. return;
  7863. }
  7864. if( iSettlerCount > 0 )
  7865. {
  7866. if (AI_pickup(UNITAI_CITY_DEFENSE))
  7867. {
  7868. return;
  7869. }
  7870. }
  7871. else if( cargoSpace() - 2 >= getCargo() + iWorkerCount )
  7872. {
  7873. if (AI_pickup(UNITAI_SETTLE, true))
  7874. {
  7875. return;
  7876. }
  7877. }
  7878. }
  7879. /************************************************************************************************/
  7880. /* BETTER_BTS_AI_MOD END */
  7881. /************************************************************************************************/
  7882. /*
  7883. if ((GC.getGame().getGameTurn() - getGameTurnCreated()) < 8)
  7884. {
  7885. if ((plot()->getPlotCity() == NULL) || GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(plot()->area(), UNITAI_SETTLE) == 0)
  7886. {
  7887. if (AI_explore())
  7888. {
  7889. return;
  7890. }
  7891. }
  7892. }
  7893. */
  7894. /************************************************************************************************/
  7895. /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
  7896. /* */
  7897. /* Naval AI */
  7898. /************************************************************************************************/
  7899. /* original bts code
  7900. if (AI_pickup(UNITAI_WORKER))
  7901. {
  7902. return;
  7903. }
  7904. */
  7905. if( !getGroup()->hasCargo() )
  7906. {
  7907. // Rescue stranded non-settlers
  7908. if(AI_pickupStranded())
  7909. {
  7910. return;
  7911. }
  7912. }
  7913. if( cargoSpace() - 2 < getCargo() + iWorkerCount )
  7914. {
  7915. // If full of workers and not going anywhere, dump them if a settler is available
  7916. if( (iSettlerCount == 0) && (plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, UNITAI_SETTLE, -1, getOwnerINLINE(), NO_TEAM, PUF_isFiniteRange) > 0) )
  7917. {
  7918. getGroup()->unloadAll();
  7919. if (AI_pickup(UNITAI_SETTLE, true))
  7920. {
  7921. return;
  7922. }
  7923. return;
  7924. }
  7925. }
  7926. if( !(getGroup()->isFull()) )
  7927. {
  7928. if (AI_pickup(UNITAI_WORKER))
  7929. {
  7930. return;
  7931. }
  7932. }
  7933. /************************************************************************************************/
  7934. /* BETTER_BTS_AI_MOD END */
  7935. /************************************************************************************************/
  7936. if (AI_retreatToCity(true))
  7937. {
  7938. return;
  7939. }
  7940. if (AI_retreatToCity())
  7941. {
  7942. return;
  7943. }
  7944. if (AI_safety())
  7945. {
  7946. return;
  7947. }
  7948. getGroup()->pushMission(MISSION_SKIP);
  7949. return;
  7950. }
  7951. void CvUnitAI::AI_missionarySeaMove()
  7952. {
  7953. PROFILE_FUNC();
  7954. // Tholal AI - catch for upgraded units
  7955. if (cargoSpace() == 0)
  7956. {
  7957. AI_setUnitAIType(UNITAI_EXPLORE_SEA);
  7958. getGroup()->pushMission(MISSION_SKIP);
  7959. return;
  7960. }
  7961. // End Tholal AI
  7962. /********************************************************************************/
  7963. /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
  7964. /* */
  7965. /* Naval AI */
  7966. /********************************************************************************/
  7967. if (plot()->isCity(true))
  7968. {
  7969. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  7970. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  7971. if( getDamage() > 0 ) // extra risk to leaving when wounded
  7972. {
  7973. iOurDefense *= 2;
  7974. }
  7975. if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
  7976. {
  7977. // Retreat to primary area first
  7978. if (AI_retreatToCity(true))
  7979. {
  7980. return;
  7981. }
  7982. if (AI_retreatToCity())
  7983. {
  7984. return;
  7985. }
  7986. if (AI_safety())
  7987. {
  7988. return;
  7989. }
  7990. }
  7991. }
  7992. /********************************************************************************/
  7993. /* BETTER_BTS_AI_MOD END */
  7994. /********************************************************************************/
  7995. if (getUnitAICargo(UNITAI_MISSIONARY) > 0)
  7996. {
  7997. if (AI_specialSeaTransportMissionary())
  7998. {
  7999. return;
  8000. }
  8001. }
  8002. else if (!(getGroup()->hasCargo()))
  8003. {
  8004. if (AI_pillageRange(4))
  8005. {
  8006. return;
  8007. }
  8008. }
  8009. /************************************************************************************************/
  8010. /* BETTER_BTS_AI_MOD 01/14/09 jdog5000 */
  8011. /* */
  8012. /* Naval AI */
  8013. /************************************************************************************************/
  8014. if( !(getGroup()->isFull()) )
  8015. {
  8016. if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SPECIAL) > 0 )
  8017. {
  8018. // Wait for units on the way
  8019. getGroup()->pushMission(MISSION_SKIP);
  8020. return;
  8021. }
  8022. }
  8023. if (AI_pickup(UNITAI_MISSIONARY, true))
  8024. {
  8025. return;
  8026. }
  8027. /************************************************************************************************/
  8028. /* BETTER_BTS_AI_MOD END */
  8029. /************************************************************************************************/
  8030. if (AI_explore())
  8031. {
  8032. return;
  8033. }
  8034. if (AI_retreatToCity(true))
  8035. {
  8036. return;
  8037. }
  8038. if (AI_retreatToCity())
  8039. {
  8040. return;
  8041. }
  8042. if (AI_safety())
  8043. {
  8044. return;
  8045. }
  8046. getGroup()->pushMission(MISSION_SKIP);
  8047. return;
  8048. }
  8049. void CvUnitAI::AI_spySeaMove()
  8050. {
  8051. PROFILE_FUNC();
  8052. CvCity* pCity;
  8053. /********************************************************************************/
  8054. /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
  8055. /* */
  8056. /* Naval AI */
  8057. /********************************************************************************/
  8058. if (plot()->isCity(true))
  8059. {
  8060. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  8061. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  8062. if( getDamage() > 0 ) // extra risk to leaving when wounded
  8063. {
  8064. iOurDefense *= 2;
  8065. }
  8066. if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
  8067. {
  8068. // Retreat to primary area first
  8069. if (AI_retreatToCity(true))
  8070. {
  8071. return;
  8072. }
  8073. if (AI_retreatToCity())
  8074. {
  8075. return;
  8076. }
  8077. if (AI_safety())
  8078. {
  8079. return;
  8080. }
  8081. }
  8082. }
  8083. /********************************************************************************/
  8084. /* BETTER_BTS_AI_MOD END */
  8085. /********************************************************************************/
  8086. if (getUnitAICargo(UNITAI_SPY) > 0)
  8087. {
  8088. if (AI_specialSeaTransportSpy())
  8089. {
  8090. return;
  8091. }
  8092. pCity = plot()->getPlotCity();
  8093. if (pCity != NULL)
  8094. {
  8095. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  8096. {
  8097. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY, pCity->plot());
  8098. return;
  8099. }
  8100. }
  8101. }
  8102. else if (!(getGroup()->hasCargo()))
  8103. {
  8104. if (AI_pillageRange(5))
  8105. {
  8106. return;
  8107. }
  8108. }
  8109. /************************************************************************************************/
  8110. /* BETTER_BTS_AI_MOD 01/14/09 jdog5000 */
  8111. /* */
  8112. /* Naval AI */
  8113. /************************************************************************************************/
  8114. if( !(getGroup()->isFull()) )
  8115. {
  8116. if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SPECIAL) > 0 )
  8117. {
  8118. // Wait for units on the way
  8119. getGroup()->pushMission(MISSION_SKIP);
  8120. return;
  8121. }
  8122. }
  8123. if (AI_pickup(UNITAI_SPY, true))
  8124. {
  8125. return;
  8126. }
  8127. /************************************************************************************************/
  8128. /* BETTER_BTS_AI_MOD END */
  8129. /************************************************************************************************/
  8130. if (AI_retreatToCity(true))
  8131. {
  8132. return;
  8133. }
  8134. if (AI_retreatToCity())
  8135. {
  8136. return;
  8137. }
  8138. if (AI_safety())
  8139. {
  8140. return;
  8141. }
  8142. getGroup()->pushMission(MISSION_SKIP);
  8143. return;
  8144. }
  8145. void CvUnitAI::AI_carrierSeaMove()
  8146. {
  8147. PROFILE_FUNC();
  8148. /********************************************************************************/
  8149. /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
  8150. /* */
  8151. /* Naval AI */
  8152. /********************************************************************************/
  8153. if (plot()->isCity(true))
  8154. {
  8155. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  8156. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  8157. if( getDamage() > 0 ) // extra risk to leaving when wounded
  8158. {
  8159. iOurDefense *= 2;
  8160. }
  8161. if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
  8162. {
  8163. if (AI_retreatToCity(true))
  8164. {
  8165. return;
  8166. }
  8167. if (AI_retreatToCity())
  8168. {
  8169. return;
  8170. }
  8171. if (AI_safety())
  8172. {
  8173. return;
  8174. }
  8175. }
  8176. }
  8177. /********************************************************************************/
  8178. /* BETTER_BTS_AI_MOD END */
  8179. /********************************************************************************/
  8180. if (AI_heal(50))
  8181. {
  8182. return;
  8183. }
  8184. if (!isEnemy(plot()->getTeam()))
  8185. {
  8186. if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) > 0)
  8187. {
  8188. getGroup()->pushMission(MISSION_SKIP);
  8189. return;
  8190. }
  8191. }
  8192. else
  8193. {
  8194. if (AI_seaBombardRange(1))
  8195. {
  8196. return;
  8197. }
  8198. }
  8199. if (AI_group(UNITAI_CARRIER_SEA, -1, /*iMaxOwnUnitAI*/ 1))
  8200. {
  8201. return;
  8202. }
  8203. if (getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA) + getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA) == 0)
  8204. {
  8205. if (plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE())
  8206. {
  8207. getGroup()->pushMission(MISSION_SKIP);
  8208. return;
  8209. }
  8210. if (AI_retreatToCity())
  8211. {
  8212. return;
  8213. }
  8214. }
  8215. if (getCargo() > 0)
  8216. {
  8217. if (AI_carrierSeaTransport())
  8218. {
  8219. return;
  8220. }
  8221. if (AI_blockade())
  8222. {
  8223. return;
  8224. }
  8225. if (AI_shadow(UNITAI_ASSAULT_SEA))
  8226. {
  8227. return;
  8228. }
  8229. }
  8230. if (AI_travelToUpgradeCity())
  8231. {
  8232. return;
  8233. }
  8234. if (AI_retreatToCity(true))
  8235. {
  8236. return;
  8237. }
  8238. if (AI_retreatToCity())
  8239. {
  8240. return;
  8241. }
  8242. if (AI_safety())
  8243. {
  8244. return;
  8245. }
  8246. getGroup()->pushMission(MISSION_SKIP);
  8247. return;
  8248. }
  8249. void CvUnitAI::AI_missileCarrierSeaMove()
  8250. {
  8251. PROFILE_FUNC();
  8252. bool bIsStealth = (getInvisibleType() != NO_INVISIBLE);
  8253. /********************************************************************************/
  8254. /* BETTER_BTS_AI_MOD 06/14/09 Solver & jdog5000 */
  8255. /* */
  8256. /* Naval AI */
  8257. /********************************************************************************/
  8258. if (plot()->isCity(true))
  8259. {
  8260. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  8261. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  8262. if( getDamage() > 0 ) // extra risk to leaving when wounded
  8263. {
  8264. iOurDefense *= 2;
  8265. }
  8266. if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
  8267. {
  8268. if (AI_shadow(UNITAI_ASSAULT_SEA, 1, 50, false, true, getMoves()))
  8269. {
  8270. return;
  8271. }
  8272. if (AI_retreatToCity())
  8273. {
  8274. return;
  8275. }
  8276. if (AI_safety())
  8277. {
  8278. return;
  8279. }
  8280. }
  8281. }
  8282. /********************************************************************************/
  8283. /* BETTER_BTS_AI_MOD END */
  8284. /********************************************************************************/
  8285. if (plot()->isCity() && plot()->getTeam() == getTeam())
  8286. {
  8287. if (AI_heal())
  8288. {
  8289. return;
  8290. }
  8291. }
  8292. if (((plot()->getTeam() != getTeam()) && getGroup()->hasCargo()) || getGroup()->AI_isFull())
  8293. {
  8294. if (bIsStealth)
  8295. {
  8296. if (AI_carrierSeaTransport())
  8297. {
  8298. return;
  8299. }
  8300. }
  8301. else
  8302. {
  8303. /********************************************************************************/
  8304. /* BETTER_BTS_AI_MOD 06/14/09 jdog5000 */
  8305. /* */
  8306. /* Naval AI */
  8307. /********************************************************************************/
  8308. if (AI_shadow(UNITAI_ASSAULT_SEA, 1, 50, true, false, 12))
  8309. {
  8310. return;
  8311. }
  8312. /********************************************************************************/
  8313. /* BETTER_BTS_AI_MOD END */
  8314. /********************************************************************************/
  8315. if (AI_carrierSeaTransport())
  8316. {
  8317. return;
  8318. }
  8319. }
  8320. }
  8321. // if (AI_pickup(UNITAI_ICBM))
  8322. // {
  8323. // return;
  8324. // }
  8325. //
  8326. // if (AI_pickup(UNITAI_MISSILE_AIR))
  8327. // {
  8328. // return;
  8329. // }
  8330. if (AI_retreatToCity())
  8331. {
  8332. return;
  8333. }
  8334. getGroup()->pushMission(MISSION_SKIP);
  8335. }
  8336. void CvUnitAI::AI_attackAirMove()
  8337. {
  8338. PROFILE_FUNC();
  8339. /********************************************************************************/
  8340. /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
  8341. /* */
  8342. /* Air AI */
  8343. /********************************************************************************/
  8344. CvCity* pCity = plot()->getPlotCity();
  8345. bool bSkiesClear = true;
  8346. int iDX, iDY;
  8347. // Check for sufficient defenders to stay
  8348. int iDefenders = plot()->plotCount(PUF_canDefend, -1, -1, plot()->getOwner());
  8349. int iAttackAirCount = plot()->plotCount(PUF_canAirAttack, -1, -1, NO_PLAYER, getTeam());
  8350. iAttackAirCount += 2 * plot()->plotCount(PUF_isUnitAIType, UNITAI_ICBM, -1, NO_PLAYER, getTeam());
  8351. if( plot()->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()) )
  8352. {
  8353. iDefenders -= 1;
  8354. }
  8355. if( pCity != NULL )
  8356. {
  8357. if( pCity->getDefenseModifier(true) < 40 )
  8358. {
  8359. iDefenders -= 1;
  8360. }
  8361. if( pCity->getOccupationTimer() > 1 )
  8362. {
  8363. iDefenders -= 1;
  8364. }
  8365. }
  8366. if( iAttackAirCount > iDefenders )
  8367. {
  8368. if (AI_airOffensiveCity())
  8369. {
  8370. return;
  8371. }
  8372. }
  8373. // Check for direct threat to current base
  8374. if (plot()->isCity(true))
  8375. {
  8376. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  8377. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  8378. if (iEnemyOffense > iOurDefense || iOurDefense == 0)
  8379. {
  8380. // Too risky, pull back
  8381. if (AI_airOffensiveCity())
  8382. {
  8383. return;
  8384. }
  8385. if( canAirDefend() )
  8386. {
  8387. if (AI_airDefensiveCity())
  8388. {
  8389. return;
  8390. }
  8391. }
  8392. }
  8393. else if( iEnemyOffense > iOurDefense/3 )
  8394. {
  8395. if( getDamage() == 0 )
  8396. {
  8397. if( collateralDamage() == 0 && canAirDefend() )
  8398. {
  8399. if (pCity != NULL)
  8400. {
  8401. // Check for whether city needs this unit to air defend
  8402. if( !(pCity->AI_isAirDefended(true,-1)) )
  8403. {
  8404. getGroup()->pushMission(MISSION_AIRPATROL);
  8405. return;
  8406. }
  8407. }
  8408. }
  8409. // Attack the invaders!
  8410. if (AI_defendBaseAirStrike())
  8411. {
  8412. return;
  8413. }
  8414. if (AI_defensiveAirStrike())
  8415. {
  8416. return;
  8417. }
  8418. if (AI_airStrike())
  8419. {
  8420. return;
  8421. }
  8422. // If no targets, no sense staying in risky place
  8423. if (AI_airOffensiveCity())
  8424. {
  8425. return;
  8426. }
  8427. if( canAirDefend() )
  8428. {
  8429. if (AI_airDefensiveCity())
  8430. {
  8431. return;
  8432. }
  8433. }
  8434. }
  8435. if( healTurns(plot()) > 1 )
  8436. {
  8437. // If very damaged, no sense staying in risky place
  8438. if (AI_airOffensiveCity())
  8439. {
  8440. return;
  8441. }
  8442. if( canAirDefend() )
  8443. {
  8444. if (AI_airDefensiveCity())
  8445. {
  8446. return;
  8447. }
  8448. }
  8449. }
  8450. }
  8451. }
  8452. if( getDamage() > 0 )
  8453. {
  8454. if (((100*currHitPoints()) / maxHitPoints()) < 40)
  8455. {
  8456. getGroup()->pushMission(MISSION_SKIP);
  8457. return;
  8458. }
  8459. else
  8460. {
  8461. CvPlot *pLoopPlot;
  8462. int iSearchRange = airRange();
  8463. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  8464. {
  8465. if (!bSkiesClear) break;
  8466. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  8467. {
  8468. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  8469. if (pLoopPlot != NULL)
  8470. {
  8471. if (bestInterceptor(pLoopPlot) != NULL)
  8472. {
  8473. bSkiesClear = false;
  8474. break;
  8475. }
  8476. }
  8477. }
  8478. }
  8479. if (!bSkiesClear)
  8480. {
  8481. getGroup()->pushMission(MISSION_SKIP);
  8482. return;
  8483. }
  8484. }
  8485. }
  8486. /********************************************************************************/
  8487. /* BETTER_BTS_AI_MOD END */
  8488. /********************************************************************************/
  8489. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  8490. CvArea* pArea = area();
  8491. int iAttackValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_ATTACK_AIR, pArea);
  8492. int iCarrierValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_CARRIER_AIR, pArea);
  8493. if (iCarrierValue > 0)
  8494. {
  8495. int iCarriers = kPlayer.AI_totalUnitAIs(UNITAI_CARRIER_SEA);
  8496. if (iCarriers > 0)
  8497. {
  8498. UnitTypes eBestCarrierUnit = NO_UNIT;
  8499. kPlayer.AI_bestAreaUnitAIValue(UNITAI_CARRIER_SEA, NULL, &eBestCarrierUnit);
  8500. if (eBestCarrierUnit != NO_UNIT)
  8501. {
  8502. int iCarrierAirNeeded = iCarriers * GC.getUnitInfo(eBestCarrierUnit).getCargoSpace();
  8503. if (kPlayer.AI_totalUnitAIs(UNITAI_CARRIER_AIR) < iCarrierAirNeeded)
  8504. {
  8505. AI_setUnitAIType(UNITAI_CARRIER_AIR);
  8506. getGroup()->pushMission(MISSION_SKIP);
  8507. return;
  8508. }
  8509. }
  8510. }
  8511. }
  8512. int iDefenseValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_DEFENSE_AIR, pArea);
  8513. if (iDefenseValue > iAttackValue)
  8514. {
  8515. if (kPlayer.AI_bestAreaUnitAIValue(UNITAI_ATTACK_AIR, pArea) > iAttackValue)
  8516. {
  8517. AI_setUnitAIType(UNITAI_DEFENSE_AIR);
  8518. getGroup()->pushMission(MISSION_SKIP);
  8519. return;
  8520. }
  8521. }
  8522. /********************************************************************************/
  8523. /* BETTER_BTS_AI_MOD 10/6/08 jdog5000 */
  8524. /* */
  8525. /* Air AI */
  8526. /********************************************************************************/
  8527. /* original BTS code
  8528. if (AI_airBombDefenses())
  8529. {
  8530. return;
  8531. }
  8532. if (GC.getGameINLINE().getSorenRandNum(4, "AI Air Attack Move") == 0)
  8533. {
  8534. if (AI_airBombPlots())
  8535. {
  8536. return;
  8537. }
  8538. }
  8539. if (AI_airStrike())
  8540. {
  8541. return;
  8542. }
  8543. if (canAirAttack())
  8544. {
  8545. if (AI_airOffensiveCity())
  8546. {
  8547. return;
  8548. }
  8549. }
  8550. if (canRecon(plot()))
  8551. {
  8552. if (AI_exploreAir())
  8553. {
  8554. return;
  8555. }
  8556. }
  8557. if (canAirDefend())
  8558. {
  8559. getGroup()->pushMission(MISSION_AIRPATROL);
  8560. return;
  8561. }
  8562. */
  8563. bool bDefensive = false;
  8564. if( pArea != NULL )
  8565. {
  8566. bDefensive = pArea->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE;
  8567. }
  8568. if (GC.getGameINLINE().getSorenRandNum(bDefensive ? 3 : 6, "AI Air Attack Move") == 0)
  8569. {
  8570. if( AI_defensiveAirStrike() )
  8571. {
  8572. return;
  8573. }
  8574. }
  8575. if (GC.getGameINLINE().getSorenRandNum(4, "AI Air Attack Move") == 0)
  8576. {
  8577. // only moves unit in a fort
  8578. if (AI_travelToUpgradeCity())
  8579. {
  8580. return;
  8581. }
  8582. }
  8583. // Support ground attacks
  8584. if (AI_airBombDefenses())
  8585. {
  8586. return;
  8587. }
  8588. if (GC.getGameINLINE().getSorenRandNum(bDefensive ? 6 : 4, "AI Air Attack Move") == 0)
  8589. {
  8590. if (AI_airBombPlots())
  8591. {
  8592. return;
  8593. }
  8594. }
  8595. if (AI_airStrike())
  8596. {
  8597. return;
  8598. }
  8599. if (canAirAttack())
  8600. {
  8601. if (AI_airOffensiveCity())
  8602. {
  8603. return;
  8604. }
  8605. }
  8606. else
  8607. {
  8608. if( canAirDefend() )
  8609. {
  8610. if (AI_airDefensiveCity())
  8611. {
  8612. return;
  8613. }
  8614. }
  8615. }
  8616. // BBAI TODO: Support friendly attacks on common enemies, if low risk?
  8617. if (canAirDefend())
  8618. {
  8619. if( bDefensive || GC.getGameINLINE().getSorenRandNum(2, "AI Air Attack Move") == 0 )
  8620. {
  8621. getGroup()->pushMission(MISSION_AIRPATROL);
  8622. return;
  8623. }
  8624. }
  8625. if (canRecon(plot()))
  8626. {
  8627. if (AI_exploreAir())
  8628. {
  8629. return;
  8630. }
  8631. }
  8632. /********************************************************************************/
  8633. /* BETTER_BTS_AI_MOD END */
  8634. /********************************************************************************/
  8635. getGroup()->pushMission(MISSION_SKIP);
  8636. return;
  8637. }
  8638. void CvUnitAI::AI_defenseAirMove()
  8639. {
  8640. PROFILE_FUNC();
  8641. /********************************************************************************/
  8642. /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
  8643. /* */
  8644. /* Air AI */
  8645. /********************************************************************************/
  8646. CvCity* pCity = plot()->getPlotCity();
  8647. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  8648. // includes forts
  8649. if (plot()->isCity(true))
  8650. {
  8651. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  8652. if (3*iEnemyOffense > 4*iOurDefense || iOurDefense == 0)
  8653. {
  8654. // Too risky, pull out
  8655. // AI_airDefensiveCity will leave some air defense, pull extras out
  8656. if (AI_airDefensiveCity())
  8657. {
  8658. return;
  8659. }
  8660. }
  8661. else if ( iEnemyOffense > iOurDefense/3 )
  8662. {
  8663. if (getDamage() > 0)
  8664. {
  8665. if( healTurns(plot()) > 1 + GC.getGameINLINE().getSorenRandNum(2, "AI Air Defense Move") )
  8666. {
  8667. // Can't help current situation, only risk losing unit
  8668. if (AI_airDefensiveCity())
  8669. {
  8670. return;
  8671. }
  8672. }
  8673. // Stay to defend in the future
  8674. getGroup()->pushMission(MISSION_SKIP);
  8675. return;
  8676. }
  8677. if (canAirDefend() && pCity != NULL)
  8678. {
  8679. // Check for whether city needs this unit to air defend
  8680. if( !(pCity->AI_isAirDefended(true,-1)) )
  8681. {
  8682. getGroup()->pushMission(MISSION_AIRPATROL);
  8683. return;
  8684. }
  8685. // Consider adding extra defenders
  8686. if( collateralDamage() == 0 && (!pCity->AI_isAirDefended(false,-2)) )
  8687. {
  8688. if( GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") == 0 )
  8689. {
  8690. getGroup()->pushMission(MISSION_AIRPATROL);
  8691. return;
  8692. }
  8693. }
  8694. }
  8695. // Attack the invaders!
  8696. if (AI_defendBaseAirStrike())
  8697. {
  8698. return;
  8699. }
  8700. if (AI_defensiveAirStrike())
  8701. {
  8702. return;
  8703. }
  8704. if (AI_airStrike())
  8705. {
  8706. return;
  8707. }
  8708. if (AI_airDefensiveCity())
  8709. {
  8710. return;
  8711. }
  8712. }
  8713. }
  8714. /********************************************************************************/
  8715. /* BETTER_BTS_AI_MOD END */
  8716. /********************************************************************************/
  8717. if (getDamage() > 0)
  8718. {
  8719. getGroup()->pushMission(MISSION_SKIP);
  8720. return;
  8721. }
  8722. /********************************************************************************/
  8723. /* BETTER_BTS_AI_MOD 10/17/08 Solver & jdog5000 */
  8724. /* */
  8725. /* Air AI */
  8726. /********************************************************************************/
  8727. /* original BTS code
  8728. if ((GC.getGameINLINE().getSorenRandNum(2, "AI Air Defense Move") == 0))
  8729. {
  8730. if ((pCity != NULL) && pCity->AI_isDanger())
  8731. {
  8732. if (AI_airStrike())
  8733. {
  8734. return;
  8735. }
  8736. }
  8737. else
  8738. {
  8739. if (AI_airBombDefenses())
  8740. {
  8741. return;
  8742. }
  8743. if (AI_airStrike())
  8744. {
  8745. return;
  8746. }
  8747. if (AI_getBirthmark() % 2 == 0)
  8748. {
  8749. if (AI_airBombPlots())
  8750. {
  8751. return;
  8752. }
  8753. }
  8754. }
  8755. if (AI_travelToUpgradeCity())
  8756. {
  8757. return;
  8758. }
  8759. }
  8760. bool bNoWar = (GET_TEAM(getTeam()).getAtWarCount(false) == 0);
  8761. if (canRecon(plot()))
  8762. {
  8763. if (GC.getGame().getSorenRandNum(bNoWar ? 2 : 4, "AI defensive air recon") == 0)
  8764. {
  8765. if (AI_exploreAir())
  8766. {
  8767. return;
  8768. }
  8769. }
  8770. }
  8771. if (AI_airDefensiveCity())
  8772. {
  8773. return;
  8774. }
  8775. */
  8776. if((GC.getGameINLINE().getSorenRandNum(4, "AI Air Defense Move") == 0))
  8777. {
  8778. // only moves unit in a fort
  8779. if (AI_travelToUpgradeCity())
  8780. {
  8781. return;
  8782. }
  8783. }
  8784. if( canAirDefend() )
  8785. {
  8786. // Check for whether city needs this unit for base air defenses
  8787. int iBaseAirDefenders = 0;
  8788. if( iEnemyOffense > 0 )
  8789. {
  8790. iBaseAirDefenders++;
  8791. }
  8792. if( pCity != NULL )
  8793. {
  8794. iBaseAirDefenders += pCity->AI_neededAirDefenders()/2;
  8795. }
  8796. if( plot()->countAirInterceptorsActive(getTeam()) < iBaseAirDefenders )
  8797. {
  8798. getGroup()->pushMission(MISSION_AIRPATROL);
  8799. return;
  8800. }
  8801. }
  8802. CvArea* pArea = area();
  8803. bool bDefensive = false;
  8804. bool bOffensive = false;
  8805. if( pArea != NULL )
  8806. {
  8807. bDefensive = (pArea->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE);
  8808. bOffensive = (pArea->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE);
  8809. }
  8810. if( (iEnemyOffense > 0) || bDefensive )
  8811. {
  8812. if( canAirDefend() )
  8813. {
  8814. if( pCity != NULL )
  8815. {
  8816. // Consider adding extra defenders
  8817. if( !(pCity->AI_isAirDefended(false,-1)) )
  8818. {
  8819. if ((GC.getGameINLINE().getSorenRandNum((bOffensive ? 3 : 2), "AI Air Defense Move") == 0))
  8820. {
  8821. getGroup()->pushMission(MISSION_AIRPATROL);
  8822. return;
  8823. }
  8824. }
  8825. }
  8826. else
  8827. {
  8828. if ((GC.getGameINLINE().getSorenRandNum((bOffensive ? 3 : 2), "AI Air Defense Move") == 0))
  8829. {
  8830. getGroup()->pushMission(MISSION_AIRPATROL);
  8831. return;
  8832. }
  8833. }
  8834. }
  8835. if((GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") > 0))
  8836. {
  8837. if (AI_defensiveAirStrike())
  8838. {
  8839. return;
  8840. }
  8841. if (AI_airStrike())
  8842. {
  8843. return;
  8844. }
  8845. }
  8846. }
  8847. else
  8848. {
  8849. if ((GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") > 0))
  8850. {
  8851. // Clear out any enemy fighters, support offensive units
  8852. if (AI_airBombDefenses())
  8853. {
  8854. return;
  8855. }
  8856. if (GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") == 0)
  8857. {
  8858. // Hit enemy land stacks near our cities
  8859. if (AI_defensiveAirStrike())
  8860. {
  8861. return;
  8862. }
  8863. }
  8864. if (AI_airStrike())
  8865. {
  8866. return;
  8867. }
  8868. if (AI_getBirthmark() % 2 == 0 || bOffensive)
  8869. {
  8870. if (AI_airBombPlots())
  8871. {
  8872. return;
  8873. }
  8874. }
  8875. }
  8876. }
  8877. if (AI_airDefensiveCity())
  8878. {
  8879. return;
  8880. }
  8881. // BBAI TODO: how valuable is recon information to AI in war time?
  8882. if (canRecon(plot()))
  8883. {
  8884. if (GC.getGame().getSorenRandNum(bDefensive ? 6 : 3, "AI defensive air recon") == 0)
  8885. {
  8886. if (AI_exploreAir())
  8887. {
  8888. return;
  8889. }
  8890. }
  8891. }
  8892. /********************************************************************************/
  8893. /* BETTER_BTS_AI_MOD END */
  8894. /********************************************************************************/
  8895. if (canAirDefend())
  8896. {
  8897. getGroup()->pushMission(MISSION_AIRPATROL);
  8898. return;
  8899. }
  8900. getGroup()->pushMission(MISSION_SKIP);
  8901. return;
  8902. }
  8903. void CvUnitAI::AI_carrierAirMove()
  8904. {
  8905. PROFILE_FUNC();
  8906. // XXX maybe protect land troops?
  8907. if (getDamage() > 0)
  8908. {
  8909. getGroup()->pushMission(MISSION_SKIP);
  8910. return;
  8911. }
  8912. if (isCargo())
  8913. {
  8914. int iRand = GC.getGameINLINE().getSorenRandNum(3, "AI Air Carrier Move");
  8915. if (iRand == 2 && canAirDefend())
  8916. {
  8917. getGroup()->pushMission(MISSION_AIRPATROL);
  8918. return;
  8919. }
  8920. else if (AI_airBombDefenses())
  8921. {
  8922. return;
  8923. }
  8924. else if (iRand == 1)
  8925. {
  8926. if (AI_airBombPlots())
  8927. {
  8928. return;
  8929. }
  8930. if (AI_airStrike())
  8931. {
  8932. return;
  8933. }
  8934. }
  8935. else
  8936. {
  8937. if (AI_airStrike())
  8938. {
  8939. return;
  8940. }
  8941. if (AI_airBombPlots())
  8942. {
  8943. return;
  8944. }
  8945. }
  8946. if (AI_travelToUpgradeCity())
  8947. {
  8948. return;
  8949. }
  8950. if (canAirDefend())
  8951. {
  8952. getGroup()->pushMission(MISSION_AIRPATROL);
  8953. return;
  8954. }
  8955. getGroup()->pushMission(MISSION_SKIP);
  8956. return;
  8957. }
  8958. if (AI_airCarrier())
  8959. {
  8960. return;
  8961. }
  8962. if (AI_airDefensiveCity())
  8963. {
  8964. return;
  8965. }
  8966. if (canAirDefend())
  8967. {
  8968. getGroup()->pushMission(MISSION_AIRPATROL);
  8969. return;
  8970. }
  8971. getGroup()->pushMission(MISSION_SKIP);
  8972. return;
  8973. }
  8974. void CvUnitAI::AI_missileAirMove()
  8975. {
  8976. PROFILE_FUNC();
  8977. CvCity* pCity = plot()->getPlotCity();
  8978. /********************************************************************************/
  8979. /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
  8980. /* */
  8981. /* Air AI */
  8982. /********************************************************************************/
  8983. // includes forts
  8984. if (!isCargo() && plot()->isCity(true))
  8985. {
  8986. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  8987. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  8988. if (iEnemyOffense > (iOurDefense/2) || iOurDefense == 0)
  8989. {
  8990. if (AI_airOffensiveCity())
  8991. {
  8992. return;
  8993. }
  8994. }
  8995. }
  8996. /********************************************************************************/
  8997. /* BETTER_BTS_AI_MOD END */
  8998. /********************************************************************************/
  8999. if (isCargo())
  9000. {
  9001. int iRand = GC.getGameINLINE().getSorenRandNum(3, "AI Air Missile plot bombing");
  9002. if (iRand != 0)
  9003. {
  9004. if (AI_airBombPlots())
  9005. {
  9006. return;
  9007. }
  9008. }
  9009. iRand = GC.getGameINLINE().getSorenRandNum(3, "AI Air Missile Carrier Move");
  9010. if (iRand == 0)
  9011. {
  9012. if (AI_airBombDefenses())
  9013. {
  9014. return;
  9015. }
  9016. if (AI_airStrike())
  9017. {
  9018. return;
  9019. }
  9020. }
  9021. else
  9022. {
  9023. if (AI_airStrike())
  9024. {
  9025. return;
  9026. }
  9027. if (AI_airBombDefenses())
  9028. {
  9029. return;
  9030. }
  9031. }
  9032. if (AI_airBombPlots())
  9033. {
  9034. return;
  9035. }
  9036. getGroup()->pushMission(MISSION_SKIP);
  9037. return;
  9038. }
  9039. if (AI_airStrike())
  9040. {
  9041. return;
  9042. }
  9043. if (AI_missileLoad(UNITAI_MISSILE_CARRIER_SEA))
  9044. {
  9045. return;
  9046. }
  9047. if (AI_missileLoad(UNITAI_RESERVE_SEA, 1))
  9048. {
  9049. return;
  9050. }
  9051. if (AI_missileLoad(UNITAI_ATTACK_SEA, 1))
  9052. {
  9053. return;
  9054. }
  9055. if (AI_airBombDefenses())
  9056. {
  9057. return;
  9058. }
  9059. if (!isCargo())
  9060. {
  9061. if (AI_airOffensiveCity())
  9062. {
  9063. return;
  9064. }
  9065. }
  9066. getGroup()->pushMission(MISSION_SKIP);
  9067. return;
  9068. }
  9069. void CvUnitAI::AI_networkAutomated()
  9070. {
  9071. FAssertMsg(canBuildRoute(), "canBuildRoute is expected to be true");
  9072. if (!(getGroup()->canDefend()))
  9073. {
  9074. /************************************************************************************************/
  9075. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  9076. /* */
  9077. /* Unit AI, Efficiency */
  9078. /************************************************************************************************/
  9079. //if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0)
  9080. if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot()))
  9081. /************************************************************************************************/
  9082. /* BETTER_BTS_AI_MOD END */
  9083. /************************************************************************************************/
  9084. {
  9085. if (AI_retreatToCity()) // XXX maybe not do this??? could be working productively somewhere else...
  9086. {
  9087. return;
  9088. }
  9089. }
  9090. }
  9091. if (AI_improveBonus(20))
  9092. {
  9093. return;
  9094. }
  9095. if (AI_improveBonus(10))
  9096. {
  9097. return;
  9098. }
  9099. if (AI_connectBonus())
  9100. {
  9101. return;
  9102. }
  9103. if (AI_connectCity())
  9104. {
  9105. return;
  9106. }
  9107. if (AI_improveBonus())
  9108. {
  9109. return;
  9110. }
  9111. if (AI_routeTerritory(true))
  9112. {
  9113. return;
  9114. }
  9115. if (AI_connectBonus(false))
  9116. {
  9117. return;
  9118. }
  9119. if (AI_routeCity())
  9120. {
  9121. return;
  9122. }
  9123. if (AI_routeTerritory())
  9124. {
  9125. return;
  9126. }
  9127. if (AI_retreatToCity())
  9128. {
  9129. return;
  9130. }
  9131. if (AI_safety())
  9132. {
  9133. return;
  9134. }
  9135. getGroup()->pushMission(MISSION_SKIP);
  9136. return;
  9137. }
  9138. void CvUnitAI::AI_cityAutomated()
  9139. {
  9140. CvCity* pCity;
  9141. if (!(getGroup()->canDefend()))
  9142. {
  9143. /************************************************************************************************/
  9144. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  9145. /* */
  9146. /* Unit AI, Efficiency */
  9147. /************************************************************************************************/
  9148. //if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0)
  9149. if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot()))
  9150. /************************************************************************************************/
  9151. /* BETTER_BTS_AI_MOD END */
  9152. /************************************************************************************************/
  9153. {
  9154. if (AI_retreatToCity()) // XXX maybe not do this??? could be working productively somewhere else...
  9155. {
  9156. return;
  9157. }
  9158. }
  9159. }
  9160. pCity = NULL;
  9161. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  9162. {
  9163. pCity = plot()->getWorkingCity();
  9164. }
  9165. if (pCity == NULL)
  9166. {
  9167. pCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE()); // XXX do team???
  9168. }
  9169. if (pCity != NULL)
  9170. {
  9171. if (AI_improveCity(pCity))
  9172. {
  9173. return;
  9174. }
  9175. }
  9176. if (AI_retreatToCity())
  9177. {
  9178. return;
  9179. }
  9180. if (AI_safety())
  9181. {
  9182. return;
  9183. }
  9184. getGroup()->pushMission(MISSION_SKIP);
  9185. return;
  9186. }
  9187. // XXX make sure we include any new UnitAITypes...
  9188. int CvUnitAI::AI_promotionValue(PromotionTypes ePromotion)
  9189. {
  9190. int iValue;
  9191. int iTemp;
  9192. int iExtra;
  9193. int iI;
  9194. UnitAITypes eUnitAI = AI_getUnitAIType();
  9195. int iLevel = getLevel();
  9196. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  9197. iValue = 0;
  9198. bool bFinancialTrouble = kPlayer.AI_isFinancialTrouble();
  9199. CvPromotionInfo& kPromotion = GC.getPromotionInfo(ePromotion);
  9200. if (kPromotion.isLeader())
  9201. {
  9202. // Don't consume the leader as a regular promotion
  9203. return 0;
  9204. }
  9205. if (kPromotion.isBlitz())
  9206. {
  9207. iValue += (firstStrikes() + getExtraFirstStrikes()) * 100;
  9208. if (baseMoves() > 1)
  9209. {
  9210. iValue += 5 * baseMoves();
  9211. if (eUnitAI == UNITAI_ATTACK_CITY)
  9212. {
  9213. iValue += 50;
  9214. }
  9215. }
  9216. /*
  9217. if ((AI_getUnitAIType() == UNITAI_RESERVE && baseMoves() > 1) ||
  9218. AI_getUnitAIType() == UNITAI_PARADROP)
  9219. {
  9220. iValue += 10;
  9221. }
  9222. else
  9223. {
  9224. //FfH: Modified by Kael 06/28/2008
  9225. // iValue += 2;
  9226. iValue += 5 * baseMoves();
  9227. //FfH: End Modify
  9228. }
  9229. */
  9230. }
  9231. // Tholal AI - account for new FFH promotion tags
  9232. // ToDo - add logic for tags that arent selectable but could be in mods (flying, Dispellable, Immortal, immunetofear, bImmuneToMagic,
  9233. iValue += (kPromotion.getResistMagic() * iLevel) / 5;
  9234. if (kPromotion.isIgnoreBuildingDefense())
  9235. {
  9236. if (eUnitAI == UNITAI_ATTACK_CITY)
  9237. {
  9238. iValue += 25;
  9239. }
  9240. }
  9241. if (kPromotion.isSeeInvisible())
  9242. {
  9243. if (eUnitAI == UNITAI_CITY_DEFENSE)
  9244. {
  9245. iValue += 50;
  9246. }
  9247. else
  9248. {
  9249. iValue += 25;
  9250. }
  9251. }
  9252. if (kPromotion.isInvisible())
  9253. {
  9254. if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_ATTACK_CITY) || (eUnitAI == UNITAI_COUNTER) || (eUnitAI == UNITAI_EXPLORE))
  9255. {
  9256. iValue += 25;
  9257. }
  9258. }
  9259. if (kPromotion.isTargetWeakestUnit())
  9260. {
  9261. if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_ATTACK_CITY) || (eUnitAI == UNITAI_COUNTER))
  9262. {
  9263. iValue += 25;
  9264. }
  9265. }
  9266. if (kPromotion.isTargetWeakestUnitCounter())
  9267. {
  9268. if ((eUnitAI == UNITAI_CITY_DEFENSE) || (eUnitAI == UNITAI_COUNTER) || (eUnitAI == UNITAI_CITY_COUNTER))
  9269. {
  9270. iValue += 25;
  9271. }
  9272. }
  9273. int iCombatHeal = kPromotion.getCombatHealPercent();
  9274. if (iCombatHeal > 0)
  9275. {
  9276. if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_ATTACK_CITY) || (eUnitAI == UNITAI_COUNTER))
  9277. {
  9278. iValue += (iCombatHeal * (iLevel + 1));
  9279. }
  9280. else
  9281. {
  9282. iValue += iCombatHeal;
  9283. }
  9284. }
  9285. iValue += (kPromotion.getCombatCapturePercent() * (iLevel + 2));
  9286. if (kPromotion.isFear())
  9287. {
  9288. iValue += 100;
  9289. }
  9290. //Bounty Hunter
  9291. iValue += kPromotion.getGoldFromCombat() * (iLevel / (bFinancialTrouble ? 1: 2));
  9292. //Twincast
  9293. if (kPromotion.isTwincast())
  9294. {
  9295. if (isSummoner())
  9296. {
  9297. iValue += getLevel() * 8;
  9298. }
  9299. }
  9300. // HARDCODED promotions
  9301. // Inquisitor
  9302. if (ePromotion == ((PromotionTypes)GC.getInfoTypeForString("PROMOTION_INQUISITOR")))
  9303. {
  9304. if (kPlayer.AI_isDoVictoryStrategy(AI_VICTORY_RELIGION2))
  9305. {
  9306. int iNeededInquisitors = (kPlayer.getNumCities() / 5);
  9307. iNeededInquisitors = std::max(1, iNeededInquisitors);
  9308. if (kPlayer.AI_getNumAIUnits(UNITAI_INQUISITOR) < iNeededInquisitors)
  9309. {
  9310. iValue += 140;
  9311. }
  9312. }
  9313. }
  9314. //Metamagic for Tower Victory Strategies
  9315. if (ePromotion == ((PromotionTypes)GC.getInfoTypeForString("PROMOTION_METAMAGIC1")) || ePromotion == ((PromotionTypes)GC.getInfoTypeForString("PROMOTION_METAMAGIC2")))
  9316. {
  9317. if (kPlayer.AI_isDoVictoryStrategy(AI_VICTORY_TOWERMASTERY1))
  9318. {
  9319. if ((eUnitAI == UNITAI_MANA_UPGRADE))
  9320. {
  9321. iValue += 100;
  9322. }
  9323. }
  9324. }
  9325. // Nature 1
  9326. if (ePromotion == ((PromotionTypes)GC.getInfoTypeForString("PROMOTION_NATURE1")))
  9327. {
  9328. if (GC.getCivilizationInfo(getCivilizationType()).getDefaultRace() == (GC.getInfoTypeForString("PROMOTION_ELF") || GC.getInfoTypeForString("PROMOTION_DARK_ELF")))
  9329. {
  9330. iValue += 30;
  9331. }
  9332. if (kPlayer.getStateReligion() != NO_RELIGION)
  9333. {
  9334. if (kPlayer.getStateReligion() == ((ReligionTypes)GC.getInfoTypeForString("RELIGION_FELLOWSHIP_OF_LEAVES")))
  9335. {
  9336. iValue += 25;
  9337. }
  9338. }
  9339. }
  9340. // End Tholal AI
  9341. if (kPromotion.isAmphib())
  9342. {
  9343. if ((eUnitAI == UNITAI_ATTACK) ||
  9344. (eUnitAI == UNITAI_ATTACK_CITY))
  9345. {
  9346. iValue += 5;
  9347. }
  9348. else
  9349. {
  9350. iValue++;
  9351. }
  9352. }
  9353. if (kPromotion.isRiver())
  9354. {
  9355. if ((eUnitAI == UNITAI_ATTACK) ||
  9356. (eUnitAI == UNITAI_ATTACK_CITY))
  9357. {
  9358. iValue += 5;
  9359. }
  9360. else
  9361. {
  9362. iValue++;
  9363. }
  9364. }
  9365. if (kPromotion.isEnemyRoute())
  9366. {
  9367. if (eUnitAI == UNITAI_PILLAGE || isBlitz())
  9368. {
  9369. iValue += 25;
  9370. }
  9371. else if ((eUnitAI == UNITAI_ATTACK) ||
  9372. (eUnitAI == UNITAI_ATTACK_CITY))
  9373. {
  9374. iValue += 15;
  9375. }
  9376. else if (eUnitAI == UNITAI_PARADROP || eUnitAI == UNITAI_EXPLORE)
  9377. {
  9378. iValue += 10;
  9379. }
  9380. else
  9381. {
  9382. iValue += 4;
  9383. }
  9384. }
  9385. if (kPromotion.isAlwaysHeal())
  9386. {
  9387. if ((eUnitAI == UNITAI_ATTACK) ||
  9388. (eUnitAI == UNITAI_ATTACK_CITY) ||
  9389. (eUnitAI == UNITAI_PILLAGE) ||
  9390. (eUnitAI == UNITAI_COUNTER) ||
  9391. (eUnitAI == UNITAI_ATTACK_SEA) ||
  9392. (eUnitAI == UNITAI_PIRATE_SEA) ||
  9393. (eUnitAI == UNITAI_ESCORT_SEA) ||
  9394. (eUnitAI == UNITAI_PARADROP) ||
  9395. (eUnitAI == UNITAI_HERO))
  9396. {
  9397. iValue += 12;
  9398. }
  9399. else
  9400. {
  9401. iValue += 8;
  9402. }
  9403. }
  9404. if (kPromotion.isHillsDoubleMove())
  9405. {
  9406. if (eUnitAI == UNITAI_EXPLORE)
  9407. {
  9408. iValue += 20;
  9409. }
  9410. else
  9411. {
  9412. iValue += 10;
  9413. }
  9414. }
  9415. if (kPromotion.isImmuneToFirstStrikes()
  9416. && !immuneToFirstStrikes())
  9417. {
  9418. if ((eUnitAI == UNITAI_ATTACK_CITY))
  9419. {
  9420. iValue += 20;
  9421. }
  9422. else if ((eUnitAI == UNITAI_ATTACK))
  9423. {
  9424. iValue += 8;
  9425. }
  9426. else
  9427. {
  9428. iValue += 4;
  9429. }
  9430. }
  9431. iTemp = kPromotion.getVisibilityChange();
  9432. if ((eUnitAI == UNITAI_EXPLORE_SEA) ||
  9433. (eUnitAI == UNITAI_EXPLORE))
  9434. {
  9435. iValue += (iTemp * 40);
  9436. }
  9437. else if (eUnitAI == UNITAI_PIRATE_SEA)
  9438. {
  9439. iValue += (iTemp * 25);
  9440. }
  9441. // mobility
  9442. iTemp = 0;
  9443. if (eUnitAI != UNITAI_CITY_DEFENSE && eUnitAI != UNITAI_CITY_COUNTER && eUnitAI != UNITAI_CITY_SPECIAL && eUnitAI != UNITAI_MAGE)
  9444. {
  9445. iTemp += 20;
  9446. iTemp += (isAlive() ? 10 : 20); //slight bonus for non-alive units since they cant be Hasted
  9447. if (m_pUnitInfo->getMoves() == 1)
  9448. {
  9449. iTemp += 20 + (iLevel * 6);
  9450. }
  9451. if (isBlitz() || eUnitAI == UNITAI_PILLAGE || isWaterWalking())
  9452. {
  9453. iTemp+= 20;
  9454. }
  9455. }
  9456. iValue += iTemp * kPromotion.getMovesChange();
  9457. iTemp = kPromotion.getMoveDiscountChange();
  9458. if (eUnitAI == UNITAI_PILLAGE)
  9459. {
  9460. iValue += (iTemp * 10);
  9461. }
  9462. else
  9463. {
  9464. iValue += (iTemp * 2);
  9465. }
  9466. iTemp = kPromotion.getAirRangeChange();
  9467. if (eUnitAI == UNITAI_ATTACK_AIR ||
  9468. eUnitAI == UNITAI_CARRIER_AIR)
  9469. {
  9470. iValue += (iTemp * 20);
  9471. }
  9472. else if (eUnitAI == UNITAI_DEFENSE_AIR)
  9473. {
  9474. iValue += (iTemp * 10);
  9475. }
  9476. iTemp = kPromotion.getInterceptChange();
  9477. if (eUnitAI == UNITAI_DEFENSE_AIR)
  9478. {
  9479. iValue += (iTemp * 3);
  9480. }
  9481. else if (eUnitAI == UNITAI_CITY_SPECIAL || eUnitAI == UNITAI_CARRIER_AIR)
  9482. {
  9483. iValue += (iTemp * 2);
  9484. }
  9485. else
  9486. {
  9487. iValue += (iTemp / 10);
  9488. }
  9489. iTemp = kPromotion.getEvasionChange();
  9490. if (eUnitAI == UNITAI_ATTACK_AIR || eUnitAI == UNITAI_CARRIER_AIR)
  9491. {
  9492. iValue += (iTemp * 3);
  9493. }
  9494. else
  9495. {
  9496. iValue += (iTemp / 10);
  9497. }
  9498. iTemp = kPromotion.getFirstStrikesChange() * 2;
  9499. iTemp += kPromotion.getChanceFirstStrikesChange();
  9500. /*
  9501. if ((eUnitAI == UNITAI_RESERVE) ||
  9502. (eUnitAI == UNITAI_COUNTER) ||
  9503. (eUnitAI == UNITAI_CITY_DEFENSE) ||
  9504. (eUnitAI == UNITAI_CITY_COUNTER) ||
  9505. (eUnitAI == UNITAI_CITY_SPECIAL) ||
  9506. (eUnitAI == UNITAI_ATTACK) ||
  9507. (eUnitAI == UNITAI_HERO))*/
  9508. {
  9509. iTemp *= iLevel;
  9510. iExtra = getExtraChanceFirstStrikes() + getExtraFirstStrikes() * 2;
  9511. iTemp *= 100 + iExtra * 15;
  9512. iTemp /= 100;
  9513. iValue += iTemp;
  9514. }
  9515. /*
  9516. else
  9517. {
  9518. iValue += (iTemp * 5);
  9519. }
  9520. */
  9521. iTemp = kPromotion.getWithdrawalChange();
  9522. if (iTemp != 0)
  9523. {
  9524. iExtra = (m_pUnitInfo->getWithdrawalProbability() + (getExtraWithdrawal() * 4));
  9525. iTemp *= (100 + iExtra);
  9526. iTemp /= 100;
  9527. if ((eUnitAI == UNITAI_ATTACK_CITY) ||
  9528. (eUnitAI == UNITAI_ATTACK) ||
  9529. (eUnitAI == UNITAI_ATTACK_SEA) ||
  9530. (eUnitAI == UNITAI_HERO))
  9531. {
  9532. iValue += (iTemp * 4) / 3;
  9533. }
  9534. else if ((eUnitAI == UNITAI_COLLATERAL) ||
  9535. (eUnitAI == UNITAI_RESERVE) ||
  9536. (eUnitAI == UNITAI_RESERVE_SEA) ||
  9537. getLeaderUnitType() != NO_UNIT)
  9538. {
  9539. iValue += iTemp * 1;
  9540. }
  9541. else
  9542. {
  9543. iValue += (iTemp / 4);
  9544. }
  9545. }
  9546. iTemp = kPromotion.getCollateralDamageChange();
  9547. if (iTemp != 0)
  9548. {
  9549. iExtra = (getExtraCollateralDamage());//collateral has no strong synergy (not like retreat)
  9550. iTemp *= (100 + iExtra);
  9551. iTemp /= 100;
  9552. if (eUnitAI == UNITAI_COLLATERAL)
  9553. {
  9554. iValue += (iTemp * 2);
  9555. }
  9556. else if (eUnitAI == UNITAI_ATTACK_CITY)
  9557. {
  9558. iValue += iTemp;
  9559. }
  9560. else
  9561. {
  9562. iValue += (iTemp / 8);
  9563. }
  9564. }
  9565. iTemp = kPromotion.getBombardRateChange();
  9566. if (eUnitAI == UNITAI_ATTACK_CITY)
  9567. {
  9568. iValue += (iTemp * 2);
  9569. }
  9570. else
  9571. {
  9572. iValue += (iTemp / 8);
  9573. }
  9574. /************************************************************************************************/
  9575. /* BETTER_BTS_AI_MOD 04/26/10 jdog5000 */
  9576. /* */
  9577. /* Unit AI */
  9578. /************************************************************************************************/
  9579. iTemp = kPromotion.getEnemyHealChange();
  9580. if ((eUnitAI == UNITAI_ATTACK) ||
  9581. (eUnitAI == UNITAI_ATTACK_CITY) ||
  9582. (eUnitAI == UNITAI_PILLAGE) ||
  9583. (eUnitAI == UNITAI_ATTACK_SEA) ||
  9584. (eUnitAI == UNITAI_PARADROP) ||
  9585. (eUnitAI == UNITAI_PIRATE_SEA) ||
  9586. (AI_getGroupflag() == GROUPFLAG_CONQUEST))
  9587. /************************************************************************************************/
  9588. /* BETTER_BTS_AI_MOD END */
  9589. /************************************************************************************************/
  9590. {
  9591. iValue += iTemp;
  9592. }
  9593. else
  9594. {
  9595. iValue += (iTemp / 2);
  9596. }
  9597. iTemp = kPromotion.getNeutralHealChange();
  9598. iValue += (iTemp / 2);
  9599. iTemp = kPromotion.getFriendlyHealChange();
  9600. if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
  9601. (eUnitAI == UNITAI_CITY_COUNTER) ||
  9602. (eUnitAI == UNITAI_CITY_SPECIAL))
  9603. {
  9604. iValue += iTemp;
  9605. }
  9606. else
  9607. {
  9608. iValue += (iTemp / 4);
  9609. }
  9610. /************************************************************************************************/
  9611. /* BETTER_BTS_AI_MOD 04/26/10 jdog5000 */
  9612. /* */
  9613. /* Unit AI */
  9614. /************************************************************************************************/
  9615. if ( getDamage() > 0 || ((AI_getBirthmark() % 8 == 0) && (eUnitAI == UNITAI_COUNTER ||
  9616. eUnitAI == UNITAI_PILLAGE ||
  9617. eUnitAI == UNITAI_ATTACK_CITY ||
  9618. eUnitAI == UNITAI_MEDIC ||
  9619. eUnitAI == UNITAI_RESERVE )) )
  9620. {
  9621. /************************************************************************************************/
  9622. /* BETTER_BTS_AI_MOD END */
  9623. /************************************************************************************************/
  9624. iTemp = kPromotion.getSameTileHealChange() + getSameTileHeal();
  9625. iExtra = getSameTileHeal();
  9626. iTemp *= (100 + iExtra * 5);
  9627. iTemp /= 100;
  9628. if (iTemp > 0)
  9629. {
  9630. if (healRate(plot()) < iTemp)
  9631. {
  9632. iValue += iTemp * ((getGroup()->getNumUnits() > 4) ? 4 : 2);
  9633. }
  9634. else
  9635. {
  9636. iValue += (iTemp / 8);
  9637. }
  9638. }
  9639. iTemp = kPromotion.getAdjacentTileHealChange();
  9640. iExtra = getAdjacentTileHeal();
  9641. iTemp *= (100 + iExtra * 5);
  9642. iTemp /= 100;
  9643. if ((eUnitAI == UNITAI_MEDIC))
  9644. {
  9645. iTemp *= 2;
  9646. }
  9647. if (getSameTileHeal() >= iTemp)
  9648. {
  9649. iValue += (iTemp * ((getGroup()->getNumUnits() > 9) ? 4 : 2));
  9650. }
  9651. else
  9652. {
  9653. iValue += (iTemp / 4);
  9654. }
  9655. }
  9656. //FfH: Modified by Kael 11/14/2009 0.41k
  9657. // try to use Warlords to create super-medic units
  9658. // if (kPromotion.getAdjacentTileHealChange() > 0 || kPromotion.getSameTileHealChange() > 0)
  9659. // {
  9660. // PromotionTypes eLeader = NO_PROMOTION;
  9661. // for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
  9662. // {
  9663. // if (GC.getPromotionInfo((PromotionTypes)iI).isLeader())
  9664. // {
  9665. // eLeader = (PromotionTypes)iI;
  9666. // }
  9667. // }
  9668. //
  9669. // if (isHasPromotion(eLeader) && eLeader != NO_PROMOTION)
  9670. // {
  9671. // iValue += kPromotion.getAdjacentTileHealChange() + kPromotion.getSameTileHealChange();
  9672. // }
  9673. // }
  9674. //FfH: End Modify
  9675. // lfgr AI 04/2021: Summoners no longer prefer CombatPercent.
  9676. // Combat I-V's granted empower promotions are counted below anyway.
  9677. iTemp = kPromotion.getCombatPercent();
  9678. if ((eUnitAI == UNITAI_ATTACK) ||
  9679. (eUnitAI == UNITAI_COUNTER) ||
  9680. (eUnitAI == UNITAI_CITY_COUNTER) ||
  9681. (eUnitAI == UNITAI_ATTACK_SEA) ||
  9682. (eUnitAI == UNITAI_RESERVE_SEA) ||
  9683. (eUnitAI == UNITAI_PARADROP) ||
  9684. (eUnitAI == UNITAI_PIRATE_SEA) ||
  9685. (eUnitAI == UNITAI_ESCORT_SEA) ||
  9686. (eUnitAI == UNITAI_CARRIER_SEA) ||
  9687. (eUnitAI == UNITAI_ATTACK_AIR) ||
  9688. (eUnitAI == UNITAI_CARRIER_AIR) ||
  9689. //isSummoner() ||
  9690. (eUnitAI == UNITAI_HERO))
  9691. {
  9692. iValue += (iTemp * 2);
  9693. }
  9694. else
  9695. {
  9696. iValue += (iTemp * 1);
  9697. }
  9698. if (isDirectDamageCaster())
  9699. {
  9700. iValue += kPromotion.getSpellDamageModify() * 4;
  9701. }
  9702. iTemp = kPromotion.getCityAttackPercent();
  9703. if (iTemp != 0)
  9704. {
  9705. if (m_pUnitInfo->getUnitAIType(UNITAI_ATTACK) || m_pUnitInfo->getUnitAIType(UNITAI_ATTACK_CITY) || m_pUnitInfo->getUnitAIType(UNITAI_ATTACK_CITY_LEMMING))
  9706. {
  9707. iExtra = (m_pUnitInfo->getCityAttackModifier() + (getExtraCityAttackPercent() * 2));
  9708. iTemp *= (100 + iExtra);
  9709. iTemp /= 100;
  9710. if (eUnitAI == UNITAI_ATTACK_CITY)
  9711. {
  9712. iValue += (iTemp * 1);
  9713. }
  9714. else
  9715. {
  9716. iValue -= iTemp / 4;
  9717. }
  9718. }
  9719. }
  9720. if (kPromotion.isImmuneToDefensiveStrike())
  9721. {
  9722. if (eUnitAI == UNITAI_ATTACK_CITY)
  9723. {
  9724. iValue += 50;
  9725. }
  9726. }
  9727. iTemp = kPromotion.getCityDefensePercent();
  9728. if (iTemp != 0)
  9729. {
  9730. if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
  9731. (eUnitAI == UNITAI_CITY_SPECIAL))
  9732. {
  9733. iExtra = m_pUnitInfo->getCityDefenseModifier() + (getExtraCityDefensePercent() * 2);
  9734. iValue += ((iTemp * (100 + iExtra)) / 100);
  9735. }
  9736. else
  9737. {
  9738. iValue += (iTemp / 4);
  9739. }
  9740. }
  9741. if (kPromotion.isDoubleFortifyBonus())
  9742. {
  9743. if (eUnitAI == UNITAI_CITY_DEFENSE)
  9744. {
  9745. iValue += 50;
  9746. }
  9747. }
  9748. iTemp = kPromotion.getHillsAttackPercent();
  9749. if (iTemp != 0)
  9750. {
  9751. iExtra = getExtraHillsAttackPercent();
  9752. iTemp *= (100 + iExtra * 2);
  9753. iTemp /= 100;
  9754. if ((eUnitAI == UNITAI_ATTACK) ||
  9755. (eUnitAI == UNITAI_COUNTER))
  9756. {
  9757. iValue += (iTemp / 4);
  9758. }
  9759. else
  9760. {
  9761. iValue += (iTemp / 16);
  9762. }
  9763. }
  9764. iTemp = kPromotion.getHillsDefensePercent();
  9765. if (iTemp != 0)
  9766. {
  9767. iExtra = (m_pUnitInfo->getHillsDefenseModifier() + (getExtraHillsDefensePercent() * 2));
  9768. iTemp *= (100 + iExtra);
  9769. iTemp /= 100;
  9770. if (eUnitAI == UNITAI_CITY_DEFENSE)
  9771. {
  9772. if (plot()->isCity() && plot()->isHills())
  9773. {
  9774. iValue += (iTemp * 2) / 3;
  9775. }
  9776. }
  9777. else if (eUnitAI == UNITAI_COUNTER)
  9778. {
  9779. if (plot()->isHills())
  9780. {
  9781. iValue += (iTemp / 4);
  9782. }
  9783. else
  9784. {
  9785. iValue++;
  9786. }
  9787. }
  9788. else
  9789. {
  9790. iValue += (iTemp / 16);
  9791. }
  9792. }
  9793. iTemp = kPromotion.getRevoltProtection();
  9794. if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
  9795. (eUnitAI == UNITAI_CITY_COUNTER) ||
  9796. (eUnitAI == UNITAI_CITY_SPECIAL))
  9797. {
  9798. if (iTemp > 0)
  9799. {
  9800. PlayerTypes eOwner = plot()->calculateCulturalOwner();
  9801. if (eOwner != NO_PLAYER && GET_PLAYER(eOwner).getTeam() != kPlayer.getTeam())
  9802. {
  9803. iValue += (iTemp / 2);
  9804. }
  9805. }
  9806. }
  9807. iTemp = kPromotion.getCollateralDamageProtection();
  9808. if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
  9809. (eUnitAI == UNITAI_CITY_COUNTER) ||
  9810. (eUnitAI == UNITAI_CITY_SPECIAL))
  9811. {
  9812. iValue += (iTemp / 3);
  9813. }
  9814. else if ((eUnitAI == UNITAI_ATTACK) ||
  9815. (eUnitAI == UNITAI_COUNTER))
  9816. {
  9817. iValue += (iTemp / 4);
  9818. }
  9819. else
  9820. {
  9821. iValue += (iTemp / 8);
  9822. }
  9823. iTemp = kPromotion.getPillageChange();
  9824. if (eUnitAI == UNITAI_PILLAGE ||
  9825. eUnitAI == UNITAI_ATTACK_SEA ||
  9826. eUnitAI == UNITAI_PIRATE_SEA)
  9827. {
  9828. iValue += (iTemp / 4);
  9829. }
  9830. else
  9831. {
  9832. iValue += (iTemp / 16);
  9833. }
  9834. iTemp = kPromotion.getUpgradeDiscount();
  9835. iValue += (iTemp / 16);
  9836. iTemp = kPromotion.getExperiencePercent();
  9837. if ((eUnitAI == UNITAI_ATTACK) ||
  9838. (eUnitAI == UNITAI_ATTACK_SEA) ||
  9839. (eUnitAI == UNITAI_PIRATE_SEA) ||
  9840. (eUnitAI == UNITAI_RESERVE_SEA) ||
  9841. (eUnitAI == UNITAI_ESCORT_SEA) ||
  9842. (eUnitAI == UNITAI_CARRIER_SEA) ||
  9843. (eUnitAI == UNITAI_MISSILE_CARRIER_SEA))
  9844. {
  9845. iValue += (iTemp * 1);
  9846. }
  9847. else
  9848. {
  9849. iValue += (iTemp / 2);
  9850. }
  9851. iTemp = kPromotion.getKamikazePercent();
  9852. if (eUnitAI == UNITAI_ATTACK_CITY)
  9853. {
  9854. iValue += (iTemp / 16);
  9855. }
  9856. else
  9857. {
  9858. iValue += (iTemp / 64);
  9859. }
  9860. //>>>>Better AI: Added by Denev 2010/03/25
  9861. iTemp = kPromotion.getCargoChange();
  9862. if (eUnitAI == UNITAI_ASSAULT_SEA || eUnitAI == UNITAI_SETTLER_SEA)
  9863. {
  9864. iValue += (iTemp * 24);
  9865. }
  9866. //<<<<Better AI: End Add
  9867. for (iI = 0; iI < GC.getNumTerrainInfos(); iI++)
  9868. {
  9869. iTemp = kPromotion.getTerrainAttackPercent(iI);
  9870. if (iTemp != 0)
  9871. {
  9872. iExtra = getExtraTerrainAttackPercent((TerrainTypes)iI);
  9873. iTemp *= (100 + iExtra * 2);
  9874. iTemp /= 100;
  9875. if ((eUnitAI == UNITAI_ATTACK) ||
  9876. (eUnitAI == UNITAI_COUNTER))
  9877. {
  9878. iValue += (iTemp / 4);
  9879. }
  9880. else
  9881. {
  9882. iValue += (iTemp / 16);
  9883. }
  9884. }
  9885. iTemp = kPromotion.getTerrainDefensePercent(iI);
  9886. if (iTemp != 0)
  9887. {
  9888. iExtra = getExtraTerrainDefensePercent((TerrainTypes)iI);
  9889. iTemp *= (100 + iExtra);
  9890. iTemp /= 100;
  9891. if (eUnitAI == UNITAI_COUNTER)
  9892. {
  9893. if (plot()->getTerrainType() == (TerrainTypes)iI)
  9894. {
  9895. iValue += (iTemp / 4);
  9896. }
  9897. else
  9898. {
  9899. iValue++;
  9900. }
  9901. }
  9902. else
  9903. {
  9904. iValue += (iTemp / 16);
  9905. }
  9906. }
  9907. if (kPromotion.getTerrainDoubleMove(iI))
  9908. {
  9909. if (eUnitAI == UNITAI_EXPLORE)
  9910. {
  9911. iValue += 20;
  9912. }
  9913. else if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_PILLAGE))
  9914. {
  9915. iValue += 10;
  9916. }
  9917. else
  9918. {
  9919. iValue += 1;
  9920. }
  9921. }
  9922. }
  9923. for (iI = 0; iI < GC.getNumFeatureInfos(); iI++)
  9924. {
  9925. iTemp = kPromotion.getFeatureAttackPercent(iI);
  9926. if (iTemp != 0)
  9927. {
  9928. iExtra = getExtraFeatureAttackPercent((FeatureTypes)iI);
  9929. iTemp *= (100 + iExtra * 2);
  9930. iTemp /= 100;
  9931. if ((eUnitAI == UNITAI_ATTACK) ||
  9932. (eUnitAI == UNITAI_COUNTER))
  9933. {
  9934. iValue += (iTemp / 4);
  9935. }
  9936. else
  9937. {
  9938. iValue += (iTemp / 16);
  9939. }
  9940. }
  9941. iTemp = kPromotion.getFeatureDefensePercent(iI);
  9942. if (iTemp != 0)
  9943. {
  9944. iExtra = getExtraFeatureDefensePercent((FeatureTypes)iI);
  9945. iTemp *= (100 + iExtra * 2);
  9946. iTemp /= 100;
  9947. if (!noDefensiveBonus())
  9948. {
  9949. if (eUnitAI == UNITAI_COUNTER)
  9950. {
  9951. if (plot()->getFeatureType() == (FeatureTypes)iI)
  9952. {
  9953. iValue += (iTemp / 4);
  9954. }
  9955. else
  9956. {
  9957. iValue++;
  9958. }
  9959. }
  9960. else
  9961. {
  9962. iValue += (iTemp / 16);
  9963. }
  9964. }
  9965. }
  9966. if (kPromotion.getFeatureDoubleMove(iI))
  9967. {
  9968. if (eUnitAI == UNITAI_EXPLORE)
  9969. {
  9970. iValue += 20;
  9971. }
  9972. else if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_PILLAGE))
  9973. {
  9974. iValue += 10;
  9975. }
  9976. else
  9977. {
  9978. iValue += 1;
  9979. }
  9980. }
  9981. }
  9982. int iTempValue = 0;
  9983. for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
  9984. {
  9985. int iPromoCombatValue = kPromotion.getUnitCombatModifierPercent(iI);
  9986. if (iPromoCombatValue > 0)
  9987. {
  9988. int iTempPromoValue = 0;
  9989. // prepare counters for the Favorite Unit Combats of whoever we have warplans against
  9990. for (int iK = 0; iK < MAX_PLAYERS; iK++)
  9991. {
  9992. CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iK);
  9993. if (kLoopPlayer.isAlive())
  9994. {
  9995. if (GET_TEAM(getTeam()).AI_getWarPlan(kLoopPlayer.getTeam()) != NO_WARPLAN)
  9996. {
  9997. if (GC.getLeaderHeadInfo(kLoopPlayer.getLeaderType()).getFavoriteUnitCombat() != NO_UNITCOMBAT)
  9998. {
  9999. if (GC.getLeaderHeadInfo(kLoopPlayer.getLeaderType()).getFavoriteUnitCombat() == iI)
  10000. {
  10001. iTempPromoValue += 5;
  10002. }
  10003. }
  10004. }
  10005. }
  10006. }
  10007. // extra value if we already have modifiers against this Unit Combat type
  10008. if (unitCombatModifier((UnitCombatTypes)iI) > 0)
  10009. {
  10010. iTempPromoValue += iPromoCombatValue * iLevel;
  10011. }
  10012. else // otherwise...
  10013. {
  10014. // first make sure we dont have a counter to a different combat type already
  10015. bool bHasOtherCombatCounter = false;
  10016. for (int iJ = 0; iJ < GC.getNumUnitCombatInfos(); iJ++)
  10017. {
  10018. if (iJ != iI)
  10019. {
  10020. if (unitCombatModifier((UnitCombatTypes)iJ) > 0)
  10021. {
  10022. bHasOtherCombatCounter = true;
  10023. break;
  10024. }
  10025. }
  10026. }
  10027. if (!bHasOtherCombatCounter)
  10028. {
  10029. iTempPromoValue += iPromoCombatValue;
  10030. }
  10031. else
  10032. {
  10033. iTempPromoValue = 0;
  10034. }
  10035. }
  10036. iTempValue += iTempPromoValue;
  10037. }
  10038. }
  10039. if ((eUnitAI == UNITAI_COUNTER) || (eUnitAI == UNITAI_CITY_COUNTER))
  10040. {
  10041. iValue += iTempValue * 2;
  10042. }
  10043. else if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_ATTACK_CITY))
  10044. {
  10045. if (AI_getBirthmark() % 2 == 0)
  10046. {
  10047. iValue += iTempValue;
  10048. }
  10049. }
  10050. else
  10051. {
  10052. iValue += iTempValue / 2;
  10053. }
  10054. // Slaying
  10055. if (kPromotion.getPromotionCombatType() != -1)
  10056. {
  10057. // first make sure we dont have a counter to a different combat type already
  10058. // note - doesnt count PromoCombats :(
  10059. /*
  10060. bool bHasOtherCombatCounter = false;
  10061. for (int iJ = 0; iJ < GC.getNumUnitCombatInfos(); iJ++)
  10062. {
  10063. if (unitCombatModifier((UnitCombatTypes)iJ) > 10)
  10064. {
  10065. logBBAI("has other combat promo");
  10066. bHasOtherCombatCounter = true;
  10067. break;
  10068. }
  10069. }
  10070. */
  10071. int iPromoCombatBonus = kPromotion.getPromotionCombatMod();
  10072. for (int iI = 0; iI < MAX_PLAYERS; iI++)
  10073. {
  10074. if( GET_PLAYER((PlayerTypes)iI).isAlive() )
  10075. {
  10076. if (GET_TEAM(getTeam()).isAtWar(GET_PLAYER((PlayerTypes)iI).getTeam()))
  10077. {
  10078. if (GC.getCivilizationInfo((GET_PLAYER((PlayerTypes)iI).getCivilizationType())).getDefaultRace() == kPromotion.getPromotionCombatType())
  10079. {
  10080. logBBAI("%d bonus to slaying promo for enemy civ", iPromoCombatBonus);
  10081. iValue += iPromoCombatBonus * 2;
  10082. }
  10083. }
  10084. }
  10085. }
  10086. //if (!bHasOtherCombatCounter)
  10087. {
  10088. if ((eUnitAI == UNITAI_CITY_COUNTER) || (eUnitAI == UNITAI_COUNTER) || (eUnitAI == UNITAI_ATTACK))
  10089. {
  10090. iValue += iPromoCombatBonus;
  10091. }
  10092. else
  10093. {
  10094. iValue += iPromoCombatBonus / 2;
  10095. }
  10096. }
  10097. }
  10098. // unit combat type captures (subdue animal)
  10099. if (kPromotion.getCaptureUnitCombat() != NO_UNITCOMBAT)
  10100. {
  10101. iValue += 25;
  10102. if (unitCombatModifier(UnitCombatTypes(kPromotion.getCaptureUnitCombat())) > 0)
  10103. {
  10104. iValue += 15 * iLevel;
  10105. }
  10106. }
  10107. for (iI = 0; iI < NUM_DOMAIN_TYPES; iI++)
  10108. {
  10109. //WTF? why float and cast to int?
  10110. //iTemp = ((int)((kPromotion.getDomainModifierPercent(iI) + getExtraDomainModifier((DomainTypes)iI)) * 100.0f));
  10111. iTemp = kPromotion.getDomainModifierPercent(iI);
  10112. if (eUnitAI == UNITAI_COUNTER)
  10113. {
  10114. iValue += (iTemp * 1);
  10115. }
  10116. else if ((eUnitAI == UNITAI_ATTACK) ||
  10117. (eUnitAI == UNITAI_RESERVE))
  10118. {
  10119. iValue += (iTemp / 2);
  10120. }
  10121. else
  10122. {
  10123. iValue += (iTemp / 8);
  10124. }
  10125. }
  10126. //FfH: Added by Kael 07/30/2007
  10127. iTemp = kPromotion.getDefensiveStrikeChance() + kPromotion.getDefensiveStrikeDamage();
  10128. iTemp /= 2;
  10129. if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
  10130. (eUnitAI == UNITAI_CITY_COUNTER) ||
  10131. (eUnitAI == UNITAI_COUNTER))
  10132. {
  10133. iTemp *= 2;
  10134. }
  10135. iValue += iTemp;
  10136. // Tholal AI - mage promotion: loop through spells, check that they require ePromotion, add value for spell, check various arcane leader and civ Traits
  10137. if (isChanneler())
  10138. {
  10139. // traits - HARDCODE
  10140. bool bSundered = kPlayer.hasTrait((TraitTypes)GC.getInfoTypeForString("TRAIT_SUNDERED"));
  10141. bool bArcane = kPlayer.hasTrait((TraitTypes)GC.getInfoTypeForString("TRAIT_ARCANE"));
  10142. int iSummonDurationBonus = kPlayer.getSummonDuration();
  10143. /* - all sorts of traits give free promos - need way to properly sort out ones that are useful to mages
  10144. int iNumMageTraits = 0;
  10145. for (int iJ = 0; iJ < GC.getNumTraitInfos(); iJ++)
  10146. {
  10147. if (GC.getTraitInfo((TraitTypes)iJ).isFreePromotionUnitCombat(GC.getDefineINT("UNITCOMBAT_ADEPT")))
  10148. {
  10149. if (kPlayer.hasTrait((TraitTypes)iJ))
  10150. {
  10151. iNumMageTraits++;
  10152. }
  10153. }
  10154. }
  10155. */
  10156. // summoners like promotions that give bonuses to their summons
  10157. if (kPromotion.getPromotionSummonPerk() != NO_PROMOTION)
  10158. {
  10159. if (isSummoner())
  10160. {
  10161. iValue += 35;
  10162. // mobility is especially valuable
  10163. if (GC.getPromotionInfo((PromotionTypes)kPromotion.getPromotionSummonPerk()).getMovesChange() > 0)
  10164. {
  10165. iValue += 35;
  10166. }
  10167. }
  10168. }
  10169. for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
  10170. {
  10171. CvSpellInfo &kSpellInfo = GC.getSpellInfo((SpellTypes)iSpell);
  10172. if (kSpellInfo.getPromotionPrereq1() != NO_PROMOTION)
  10173. {
  10174. if (kSpellInfo.getPromotionPrereq1() == ePromotion)
  10175. {
  10176. iValue += GC.getGameINLINE().getSorenRandNum(10, "AI Spell Promote") + kPlayer.AI_getMojoFactor(); // added this to try and get a better distribution of spells
  10177. if (!isDirectDamageCaster()) // if we dont already have a damage spell
  10178. {
  10179. iValue += kSpellInfo.getDamage() * kSpellInfo.getRange();
  10180. iValue += kSpellInfo.getDamageLimit() / 5;
  10181. }
  10182. if (kSpellInfo.getCreateUnitType() != NO_UNIT)
  10183. {
  10184. int iTempValue = (GC.getUnitInfo((UnitTypes)kSpellInfo.getCreateUnitType()).getCombat());
  10185. CvUnitInfo &kCreateUnitInfo = GC.getUnitInfo((UnitTypes)kSpellInfo.getCreateUnitType());
  10186. if (kCreateUnitInfo.getNumSeeInvisibleTypes() > 0)
  10187. {
  10188. iTempValue += 2;
  10189. }
  10190. if (kCreateUnitInfo.getBombardRate() > 0)
  10191. {
  10192. iTempValue += 2;
  10193. }
  10194. for (int iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
  10195. {
  10196. iTempValue += (kCreateUnitInfo.getDamageTypeCombat(iI) * 2);
  10197. }
  10198. iTempValue += kCreateUnitInfo.getTier();
  10199. // account for Bonus Affinities
  10200. for (int iBonuses = 0; iBonuses < GC.getNumBonusInfos(); iBonuses++)
  10201. {
  10202. if (kCreateUnitInfo.getBonusAffinity((BonusTypes)iBonuses) != 0)
  10203. {
  10204. iTempValue += kPlayer.countOwnedBonuses((BonusTypes)iBonuses);
  10205. }
  10206. }
  10207. int iModValue = 0; //iNumMageTraits;
  10208. if (bSundered || bArcane)
  10209. {
  10210. iModValue += 1;
  10211. }
  10212. if (!kSpellInfo.isPermanentUnitCreate())
  10213. {
  10214. iModValue += iSummonDurationBonus;
  10215. }
  10216. // heroes make powerful summoners
  10217. if (eUnitAI == UNITAI_HERO || !isSummoner())
  10218. {
  10219. iModValue += 2;
  10220. }
  10221. iValue += (iTempValue * (4 + iModValue));
  10222. }
  10223. if (kSpellInfo.getAddPromotionType1() != NO_PROMOTION)
  10224. {
  10225. if (AI_getGroupflag()==GROUPFLAG_CONQUEST)// && !isBuffer())
  10226. {
  10227. iValue += 25;
  10228. if (GC.getPromotionInfo((PromotionTypes)kSpellInfo.getAddPromotionType1()).getAIWeight() < 0) // its a negative effect spell
  10229. {
  10230. iValue += kSpellInfo.getRange() * 50;
  10231. }
  10232. }
  10233. else
  10234. {
  10235. iValue += 15;
  10236. }
  10237. // extra value for haste if we can use enemy roads
  10238. // ToDo - use this format to pull other tidbits about the promotion
  10239. if (GC.getPromotionInfo((PromotionTypes)kSpellInfo.getAddPromotionType1()).getMovesChange() > 0)
  10240. {
  10241. if (isEnemyRoute())
  10242. {
  10243. iValue += 15;
  10244. }
  10245. }
  10246. }
  10247. /* - promotiontype2 is only used to add fatigued to centaurs; promotiontype3 isnt used at all
  10248. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
  10249. {
  10250. if (AI_getGroupflag()==GROUPFLAG_CONQUEST && !isBuffer())
  10251. {
  10252. iValue += 25;
  10253. }
  10254. else
  10255. {
  10256. iValue += 15;
  10257. }
  10258. }
  10259. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
  10260. {
  10261. if (AI_getGroupflag()==GROUPFLAG_CONQUEST && !isBuffer())
  10262. {
  10263. iValue += 25;
  10264. }
  10265. else
  10266. {
  10267. iValue += 15;
  10268. }
  10269. }
  10270. */
  10271. if (kSpellInfo.getRemovePromotionType1() != NO_PROMOTION)
  10272. {
  10273. if (kSpellInfo.isResistable())
  10274. {
  10275. if (AI_getGroupflag()==GROUPFLAG_CONQUEST || eUnitAI == UNITAI_MAGE)
  10276. {
  10277. iValue += 25;
  10278. }
  10279. }
  10280. else // if its not resistable, that means its a spell you cast on your own troops
  10281. {
  10282. if (isBuffer() || AI_getGroupflag() == GROUPFLAG_PERMDEFENSE)
  10283. {
  10284. iValue += 25;
  10285. }
  10286. else
  10287. {
  10288. iValue += 15;
  10289. }
  10290. }
  10291. }
  10292. if (kSpellInfo.getRemovePromotionType2() != NO_PROMOTION)
  10293. {
  10294. if (kSpellInfo.isResistable())
  10295. {
  10296. if (AI_getGroupflag()==GROUPFLAG_CONQUEST || eUnitAI == UNITAI_MAGE)
  10297. {
  10298. iValue += 25;
  10299. }
  10300. }
  10301. else // if its not resistable, that means its a spell you cast on your own troops
  10302. {
  10303. if (isBuffer() || AI_getGroupflag() == GROUPFLAG_PERMDEFENSE)
  10304. {
  10305. iValue += 25;
  10306. }
  10307. else
  10308. {
  10309. iValue += 15;
  10310. }
  10311. }
  10312. }
  10313. if (kSpellInfo.getRemovePromotionType3() != NO_PROMOTION)
  10314. {
  10315. if (kSpellInfo.isResistable())
  10316. {
  10317. if (AI_getGroupflag()==GROUPFLAG_CONQUEST || eUnitAI == UNITAI_MAGE)
  10318. {
  10319. iValue += 25;
  10320. }
  10321. }
  10322. else // if its not resistable, that means its a spell you cast on your own troops
  10323. {
  10324. if (isBuffer() || AI_getGroupflag() == GROUPFLAG_PERMDEFENSE)
  10325. {
  10326. iValue += 25;
  10327. }
  10328. else
  10329. {
  10330. iValue += 15;
  10331. }
  10332. }
  10333. }
  10334. if (kSpellInfo.getCreateBuildingType() != NO_BUILDING)
  10335. {
  10336. if (eUnitAI == UNITAI_MAGE || AI_getGroupflag() == GROUPFLAG_PERMDEFENSE)
  10337. {
  10338. iValue += 50;
  10339. }
  10340. }
  10341. // Bloom - not currently used for any selectable spell promotions in base FFH
  10342. if (kSpellInfo.getCreateFeatureType() != NO_FEATURE)
  10343. {
  10344. if (plot()->getOwner() == getOwner())
  10345. {
  10346. if (eUnitAI == UNITAI_TERRAFORMER)
  10347. {
  10348. iValue += 35;
  10349. }
  10350. else
  10351. {
  10352. iValue += 10;
  10353. }
  10354. }
  10355. }
  10356. // Blaze
  10357. if (kSpellInfo.getCreateImprovementType() != NO_IMPROVEMENT)
  10358. {
  10359. if (AI_getGroupflag()==GROUPFLAG_CONQUEST || eUnitAI == UNITAI_TERRAFORMER)
  10360. {
  10361. iValue += 35;
  10362. }
  10363. else
  10364. {
  10365. iValue += 10;
  10366. }
  10367. }
  10368. if (kSpellInfo.isDispel())
  10369. {
  10370. iValue += 25;
  10371. }
  10372. if (kSpellInfo.isPush())
  10373. {
  10374. iValue += 20;
  10375. }
  10376. if (kSpellInfo.getImmobileTurns() != 0)
  10377. {
  10378. iValue += 30 * kSpellInfo.getImmobileTurns();
  10379. }
  10380. if (kSpellInfo.isAllowAutomateTerrain())
  10381. {
  10382. if (eUnitAI == UNITAI_TERRAFORMER)
  10383. {
  10384. iValue += 50;
  10385. }
  10386. else
  10387. {
  10388. iValue += 10;
  10389. }
  10390. }
  10391. if (kSpellInfo.isResistable())
  10392. {
  10393. if (eUnitAI != UNITAI_WARWIZARD && eUnitAI != UNITAI_HERO)
  10394. {
  10395. iValue /= 2;
  10396. }
  10397. }
  10398. }
  10399. }
  10400. }
  10401. iValue += ((kPromotion.getAIWeight() / 10) * (getChannelingLevel() + 1));
  10402. }
  10403. // End Tholal AI
  10404. //FfH: End Add
  10405. if (iValue > 0)
  10406. {
  10407. iValue += GC.getGameINLINE().getSorenRandNum(15, "AI Promote");
  10408. }
  10409. return iValue;
  10410. }
  10411. // Returns true if a mission was pushed...
  10412. bool CvUnitAI::AI_shadow(UnitAITypes eUnitAI, int iMax, int iMaxRatio, bool bWithCargoOnly, bool bOutsideCityOnly, int iMaxPath)
  10413. {
  10414. PROFILE_FUNC();
  10415. CvUnit* pLoopUnit;
  10416. CvUnit* pBestUnit;
  10417. int iPathTurns;
  10418. int iValue;
  10419. int iBestValue;
  10420. int iLoop;
  10421. iBestValue = 0;
  10422. pBestUnit = NULL;
  10423. for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
  10424. {
  10425. if (pLoopUnit != this)
  10426. {
  10427. if (AI_plotValid(pLoopUnit->plot()))
  10428. {
  10429. if (pLoopUnit->isGroupHead())
  10430. {
  10431. if (!(pLoopUnit->isCargo()))
  10432. {
  10433. if (pLoopUnit->AI_getUnitAIType() == eUnitAI)
  10434. {
  10435. if ((pLoopUnit->getGroup()->baseMoves() <= getGroup()->baseMoves()) || (eUnitAI == UNITAI_SETTLE))
  10436. {
  10437. if (!bWithCargoOnly || pLoopUnit->getGroup()->hasCargo())
  10438. {
  10439. /************************************************************************************************/
  10440. /* BETTER_BTS_AI_MOD 12/08/08 jdog5000 */
  10441. /* */
  10442. /* Naval AI */
  10443. /************************************************************************************************/
  10444. if( bOutsideCityOnly && pLoopUnit->plot()->isCity() )
  10445. {
  10446. continue;
  10447. }
  10448. /************************************************************************************************/
  10449. /* BETTER_BTS_AI_MOD END */
  10450. /************************************************************************************************/
  10451. int iShadowerCount = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, MISSIONAI_SHADOW, getGroup());
  10452. if (((-1 == iMax) || (iShadowerCount < iMax)) &&
  10453. ((-1 == iMaxRatio) || (iShadowerCount == 0) || (((100 * iShadowerCount) / std::max(1, pLoopUnit->getGroup()->countNumUnitAIType(eUnitAI))) <= iMaxRatio)))
  10454. {
  10455. if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
  10456. {
  10457. if (generatePath(pLoopUnit->plot(), 0, true, &iPathTurns))
  10458. {
  10459. /************************************************************************************************/
  10460. /* BETTER_BTS_AI_MOD 12/08/08 jdog5000 */
  10461. /* */
  10462. /* Naval AI */
  10463. /************************************************************************************************/
  10464. /* original bts code
  10465. //if (iPathTurns <= iMaxPath) XXX
  10466. */
  10467. if (iPathTurns <= iMaxPath)
  10468. /************************************************************************************************/
  10469. /* BETTER_BTS_AI_MOD END */
  10470. /************************************************************************************************/
  10471. {
  10472. iValue = 1 + pLoopUnit->getGroup()->getCargo();
  10473. iValue *= 1000;
  10474. iValue /= 1 + iPathTurns;
  10475. if (iValue > iBestValue)
  10476. {
  10477. iBestValue = iValue;
  10478. pBestUnit = pLoopUnit;
  10479. }
  10480. }
  10481. }
  10482. }
  10483. }
  10484. }
  10485. }
  10486. }
  10487. }
  10488. }
  10489. }
  10490. }
  10491. }
  10492. if (pBestUnit != NULL)
  10493. {
  10494. if (atPlot(pBestUnit->plot()))
  10495. {
  10496. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_SHADOW, NULL, pBestUnit);
  10497. return true;
  10498. }
  10499. else
  10500. {
  10501. getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_SHADOW, NULL, pBestUnit);
  10502. return true;
  10503. }
  10504. }
  10505. return false;
  10506. }
  10507. /************************************************************************************************/
  10508. /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
  10509. /* */
  10510. /* Unit AI */
  10511. /************************************************************************************************/
  10512. // Added new options to aid transport grouping
  10513. // Returns true if a group was joined or a mission was pushed...
  10514. bool CvUnitAI::AI_group(UnitAITypes eUnitAI, int iMaxGroup, int iMaxOwnUnitAI, int iMinUnitAI, bool bIgnoreFaster, bool bIgnoreOwnUnitType, bool bStackOfDoom, int iMaxPath, bool bAllowRegrouping, bool bWithCargoOnly, bool bInCityOnly, MissionAITypes eIgnoreMissionAIType)
  10515. {
  10516. PROFILE_FUNC();
  10517. CvUnit* pLoopUnit;
  10518. CvUnit* pBestUnit;
  10519. int iPathTurns;
  10520. int iValue;
  10521. int iBestValue;
  10522. int iLoop;
  10523. // if we are on a transport, then do not regroup
  10524. if (isCargo())
  10525. {
  10526. return false;
  10527. }
  10528. if (!bAllowRegrouping)
  10529. {
  10530. if (getGroup()->getNumUnits() > 1)
  10531. {
  10532. return false;
  10533. }
  10534. }
  10535. if ((getDomainType() == DOMAIN_LAND) && !canMoveAllTerrain())
  10536. {
  10537. if (area()->getNumAIUnits(getOwnerINLINE(), eUnitAI) == 0)
  10538. {
  10539. return false;
  10540. }
  10541. }
  10542. if (!AI_canGroupWithAIType(eUnitAI))
  10543. {
  10544. return false;
  10545. }
  10546. // lfgr fix: copied this check from AI_counterMove(), else it is possible that a group is created and then splitted indefinitely
  10547. // "Should never have group lead by counter unit"
  10548. if( getGroup()->getHeadUnitAI() == UNITAI_COUNTER && getGroup()->getNumUnits() == 1 )
  10549. {
  10550. if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
  10551. {
  10552. return false;
  10553. }
  10554. }
  10555. // lfgr fix end
  10556. int iOurImpassableCount = 0;
  10557. CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
  10558. while (pUnitNode != NULL)
  10559. {
  10560. CvUnit* pImpassUnit = ::getUnit(pUnitNode->m_data);
  10561. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  10562. iOurImpassableCount = std::max(iOurImpassableCount, GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(pImpassUnit->getUnitType()));
  10563. }
  10564. iBestValue = MAX_INT;
  10565. pBestUnit = NULL;
  10566. // Loop over groups, ai_allowgroup blocks non-head units anyway
  10567. CvSelectionGroup* pLoopGroup = NULL;
  10568. for(pLoopGroup = GET_PLAYER(getOwnerINLINE()).firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = GET_PLAYER(getOwnerINLINE()).nextSelectionGroup(&iLoop))
  10569. {
  10570. pLoopUnit = pLoopGroup->getHeadUnit();
  10571. if( pLoopUnit == NULL )
  10572. {
  10573. continue;
  10574. }
  10575. CvPlot* pPlot = pLoopUnit->plot();
  10576. if (pLoopUnit->AI_getUnitAIType() == eUnitAI)
  10577. {
  10578. if (AI_plotValid(pPlot))
  10579. {
  10580. if (iMaxPath > 0 || pPlot == plot())
  10581. {
  10582. if (!isEnemy(pPlot->getTeam()))
  10583. {
  10584. if (AI_allowGroup(pLoopUnit, eUnitAI))
  10585. {
  10586. if ((iMaxGroup == -1) || ((pLoopGroup->getNumUnits() + GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, MISSIONAI_GROUP, getGroup())) <= (iMaxGroup + ((bStackOfDoom) ? AI_stackOfDoomExtra() : 0))))
  10587. {
  10588. if ((iMaxOwnUnitAI == -1) || (pLoopGroup->countNumUnitAIType(AI_getUnitAIType()) <= (iMaxOwnUnitAI + ((bStackOfDoom) ? AI_stackOfDoomExtra() : 0))))
  10589. {
  10590. if ((iMinUnitAI == -1) || (pLoopGroup->countNumUnitAIType(eUnitAI) >= iMinUnitAI))
  10591. {
  10592. if (!bIgnoreFaster || (pLoopGroup->baseMoves() <= baseMoves()))
  10593. {
  10594. if (!bIgnoreOwnUnitType || (pLoopUnit->getUnitType() != getUnitType()))
  10595. {
  10596. if (!bWithCargoOnly || pLoopUnit->getGroup()->hasCargo())
  10597. {
  10598. if( !bInCityOnly || pLoopUnit->plot()->isCity() )
  10599. {
  10600. if( (eIgnoreMissionAIType == NO_MISSIONAI) || (eIgnoreMissionAIType != pLoopUnit->getGroup()->AI_getMissionAIType()) )
  10601. {
  10602. if (!(pPlot->isVisibleEnemyUnit(this)))
  10603. {
  10604. if( iOurImpassableCount > 0 || AI_getUnitAIType() == UNITAI_ASSAULT_SEA )
  10605. {
  10606. int iTheirImpassableCount = 0;
  10607. pUnitNode = pLoopGroup->headUnitNode();
  10608. while (pUnitNode != NULL)
  10609. {
  10610. CvUnit* pImpassUnit = ::getUnit(pUnitNode->m_data);
  10611. pUnitNode = pLoopGroup->nextUnitNode(pUnitNode);
  10612. iTheirImpassableCount = std::max(iTheirImpassableCount, GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(pImpassUnit->getUnitType()));
  10613. }
  10614. if( iOurImpassableCount != iTheirImpassableCount )
  10615. {
  10616. continue;
  10617. }
  10618. }
  10619. if (generatePath(pPlot, 0, true, &iPathTurns))
  10620. {
  10621. if (iPathTurns <= iMaxPath)
  10622. {
  10623. iValue = 1000 / (iPathTurns + 1);
  10624. iValue *= 4 + pLoopGroup->getCargo();
  10625. iValue /= pLoopGroup->getNumUnits();
  10626. if (iValue < iBestValue)
  10627. {
  10628. iBestValue = iValue;
  10629. pBestUnit = pLoopUnit;
  10630. }
  10631. }
  10632. }
  10633. }
  10634. }
  10635. }
  10636. }
  10637. }
  10638. }
  10639. }
  10640. }
  10641. }
  10642. }
  10643. }
  10644. }
  10645. }
  10646. }
  10647. }
  10648. if (pBestUnit != NULL)
  10649. {
  10650. if (atPlot(pBestUnit->plot()))
  10651. {
  10652. joinGroup(pBestUnit->getGroup());
  10653. return true;
  10654. }
  10655. else
  10656. {
  10657. getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
  10658. return true;
  10659. }
  10660. }
  10661. return false;
  10662. }
  10663. /************************************************************************************************/
  10664. /* BETTER_BTS_AI_MOD END */
  10665. /************************************************************************************************/
  10666. bool CvUnitAI::AI_groupMergeRange(UnitAITypes eUnitAI, int iMaxRange, bool bBiggerOnly, bool bAllowRegrouping, bool bIgnoreFaster)
  10667. {
  10668. PROFILE_FUNC();
  10669. // if we are on a transport, then do not regroup
  10670. if (isCargo())
  10671. {
  10672. return false;
  10673. }
  10674. if (!bAllowRegrouping)
  10675. {
  10676. if (getGroup()->getNumUnits() > 1)
  10677. {
  10678. return false;
  10679. }
  10680. }
  10681. if ((getDomainType() == DOMAIN_LAND) && !canMoveAllTerrain())
  10682. {
  10683. if (area()->getNumAIUnits(getOwnerINLINE(), eUnitAI) == 0)
  10684. {
  10685. return false;
  10686. }
  10687. }
  10688. if (!AI_canGroupWithAIType(eUnitAI))
  10689. {
  10690. return false;
  10691. }
  10692. // cached values
  10693. CvPlot* pPlot = plot();
  10694. CvSelectionGroup* pGroup = getGroup();
  10695. // best match
  10696. CvUnit* pBestUnit = NULL;
  10697. int iBestValue = MAX_INT;
  10698. // iterate over plots at each range
  10699. for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
  10700. {
  10701. for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
  10702. {
  10703. CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
  10704. if (pLoopPlot != NULL && pLoopPlot->getArea() == pPlot->getArea())
  10705. {
  10706. CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
  10707. while (pUnitNode != NULL)
  10708. {
  10709. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  10710. pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
  10711. CvSelectionGroup* pLoopGroup = pLoopUnit->getGroup();
  10712. if (pLoopUnit->AI_getUnitAIType() == eUnitAI)
  10713. {
  10714. if (AI_allowGroup(pLoopUnit, eUnitAI))
  10715. {
  10716. if (!bIgnoreFaster || (pLoopUnit->getGroup()->baseMoves() <= baseMoves()))
  10717. {
  10718. if (!bBiggerOnly || (pLoopGroup->getNumUnits() >= pGroup->getNumUnits()))
  10719. {
  10720. /*************************************************************************************************/
  10721. /** SPEED TWEAK Sephi **/
  10722. /** We don't have to check for a path to distant shores if we want to move only short distance **/
  10723. /** anyway, so approx maximum distance for a possible path by iMaxPath **/
  10724. /*************************************************************************************************/
  10725. // int iPathTurns;
  10726. // if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  10727. // {
  10728. // if (iPathTurns <= (iMaxRange + 2))
  10729. // {
  10730. // int iValue = 1000 * (iPathTurns + 1);
  10731. // iValue /= pLoopGroup->getNumUnits();
  10732. // if (iValue < iBestValue)
  10733. // {
  10734. // iBestValue = iValue;
  10735. // pBestUnit = pLoopUnit;
  10736. // }
  10737. // }
  10738. // }
  10739. int XDist=pLoopPlot->getX_INLINE() - plot()->getX_INLINE();
  10740. int YDist=pLoopPlot->getY_INLINE() - plot()->getY_INLINE();
  10741. if (((XDist*XDist)+(YDist*YDist))<(iMaxRange + 2)*(iMaxRange + 2)*4)
  10742. {
  10743. int iPathTurns;
  10744. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  10745. {
  10746. if (iPathTurns <= (iMaxRange + 2))
  10747. {
  10748. int iValue = 1000 * (iPathTurns + 1);
  10749. iValue /= pLoopGroup->getNumUnits();
  10750. if (iValue < iBestValue)
  10751. {
  10752. iBestValue = iValue;
  10753. pBestUnit = pLoopUnit;
  10754. }
  10755. }
  10756. }
  10757. }
  10758. /*************************************************************************************************/
  10759. /** END **/
  10760. /*************************************************************************************************/
  10761. }
  10762. }
  10763. }
  10764. }
  10765. }
  10766. }
  10767. }
  10768. }
  10769. if (pBestUnit != NULL)
  10770. {
  10771. if (atPlot(pBestUnit->plot()))
  10772. {
  10773. pGroup->mergeIntoGroup(pBestUnit->getGroup());
  10774. return true;
  10775. }
  10776. else
  10777. {
  10778. if (getGroup()->getNumUnits() > 1)
  10779. {
  10780. pGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
  10781. return true;
  10782. }
  10783. else
  10784. {
  10785. pGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
  10786. return true;
  10787. }
  10788. }
  10789. }
  10790. return false;
  10791. }
  10792. /************************************************************************************************/
  10793. /* BETTER_BTS_AI_MOD 04/18/10 jdog5000 */
  10794. /* */
  10795. /* War tactics AI, Unit AI */
  10796. /************************************************************************************************/
  10797. // Returns true if we loaded onto a transport or a mission was pushed...
  10798. bool CvUnitAI::AI_load(UnitAITypes eUnitAI, MissionAITypes eMissionAI, UnitAITypes eTransportedUnitAI, int iMinCargo, int iMinCargoSpace, int iMaxCargoSpace, int iMaxCargoOurUnitAI, int iFlags, int iMaxPath, int iMaxTransportPath)
  10799. {
  10800. PROFILE_FUNC();
  10801. CvUnit* pLoopUnit;
  10802. CvUnit* pBestUnit;
  10803. int iPathTurns;
  10804. int iValue;
  10805. int iBestValue;
  10806. int iLoop;
  10807. if (getCargo() > 0)
  10808. {
  10809. return false;
  10810. }
  10811. if (isCargo())
  10812. {
  10813. getGroup()->pushMission(MISSION_SKIP);
  10814. return true;
  10815. }
  10816. if ((getDomainType() == DOMAIN_LAND) && !canMoveAllTerrain())
  10817. {
  10818. if (area()->getNumAIUnits(getOwnerINLINE(), eUnitAI) == 0)
  10819. {
  10820. return false;
  10821. }
  10822. }
  10823. iBestValue = MAX_INT;
  10824. pBestUnit = NULL;
  10825. const int iLoadMissionAICount = 4;
  10826. MissionAITypes aeLoadMissionAI[iLoadMissionAICount] = {MISSIONAI_LOAD_ASSAULT, MISSIONAI_LOAD_SETTLER, MISSIONAI_LOAD_SPECIAL, MISSIONAI_ATTACK_SPY};
  10827. int iCurrentGroupSize = getGroup()->getNumUnits();
  10828. for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
  10829. {
  10830. if (pLoopUnit != this)
  10831. {
  10832. if (AI_plotValid(pLoopUnit->plot()))
  10833. {
  10834. if (canLoadUnit(pLoopUnit, pLoopUnit->plot()))
  10835. {
  10836. // special case ASSAULT_SEA UnitAI, so that, if a unit is marked escort, but can load units, it will load them
  10837. // transport units might have been built as escort, this most commonly happens with galleons
  10838. UnitAITypes eLoopUnitAI = pLoopUnit->AI_getUnitAIType();
  10839. if (eLoopUnitAI == eUnitAI)// || (eUnitAI == UNITAI_ASSAULT_SEA && eLoopUnitAI == UNITAI_ESCORT_SEA))
  10840. {
  10841. int iCargoSpaceAvailable = pLoopUnit->cargoSpaceAvailable(getSpecialUnitType(), getDomainType());
  10842. iCargoSpaceAvailable -= GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, aeLoadMissionAI, iLoadMissionAICount, getGroup());
  10843. if (iCargoSpaceAvailable > 0)
  10844. {
  10845. if ((eTransportedUnitAI == NO_UNITAI) || (pLoopUnit->getUnitAICargo(eTransportedUnitAI) > 0))
  10846. {
  10847. if ((iMinCargo == -1) || (pLoopUnit->getCargo() >= iMinCargo))
  10848. {
  10849. // Use existing count of cargo space available
  10850. if ((iMinCargoSpace == -1) || (iCargoSpaceAvailable >= iMinCargoSpace))
  10851. {
  10852. if ((iMaxCargoSpace == -1) || (iCargoSpaceAvailable <= iMaxCargoSpace))
  10853. {
  10854. if ((iMaxCargoOurUnitAI == -1) || (pLoopUnit->getUnitAICargo(AI_getUnitAIType()) <= iMaxCargoOurUnitAI))
  10855. {
  10856. // Don't block city defense from getting on board
  10857. if (true)
  10858. {
  10859. if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
  10860. {
  10861. CvPlot* pUnitTargetPlot = pLoopUnit->getGroup()->AI_getMissionAIPlot();
  10862. if ((pUnitTargetPlot == NULL) || (pUnitTargetPlot->getTeam() == getTeam()) || (!pUnitTargetPlot->isOwned() || !isPotentialEnemy(pUnitTargetPlot->getTeam(), pUnitTargetPlot)))
  10863. {
  10864. /*************************************************************************************************/
  10865. /** SPEED TWEAK Sephi **/
  10866. /** We don't have to check for a path to distant shores if we want to move only short distance **/
  10867. /** anyway, so approx maximum distance for a possible path by iMaxPath **/
  10868. /*************************************************************************************************/
  10869. // if (generatePath(pLoopUnit->plot(), iFlags, true, &iPathTurns))
  10870. // {
  10871. // if (iPathTurns <= iMaxPath)
  10872. // {
  10873. // // prefer a transport that can hold as much of our group as possible
  10874. // iValue = (std::max(0, iCurrentGroupSize - iCargoSpaceAvailable) * 5) + iPathTurns;
  10875. // if (iValue < iBestValue)
  10876. // {
  10877. // iBestValue = iValue;
  10878. // pBestUnit = pLoopUnit;
  10879. // }
  10880. // }
  10881. // }
  10882. int XDist=pLoopUnit->plot()->getX_INLINE() - plot()->getX_INLINE();
  10883. int YDist=pLoopUnit->plot()->getY_INLINE() - plot()->getY_INLINE();
  10884. if (((XDist*XDist)+(YDist*YDist))<iMaxPath*iMaxPath*4)
  10885. {
  10886. if (generatePath(pLoopUnit->plot(), iFlags, true, &iPathTurns))
  10887. {
  10888. if (iPathTurns <= iMaxPath || (iMaxPath == 0 && plot() == pLoopUnit->plot()))
  10889. {
  10890. // prefer a transport that can hold as much of our group as possible
  10891. iValue = (std::max(0, iCurrentGroupSize - iCargoSpaceAvailable) * 5) + iPathTurns;
  10892. if (iValue < iBestValue)
  10893. {
  10894. iBestValue = iValue;
  10895. pBestUnit = pLoopUnit;
  10896. }
  10897. }
  10898. }
  10899. }
  10900. /*************************************************************************************************/
  10901. /** END **/
  10902. /*************************************************************************************************/
  10903. }
  10904. }
  10905. }
  10906. }
  10907. }
  10908. }
  10909. }
  10910. }
  10911. }
  10912. }
  10913. }
  10914. }
  10915. }
  10916. }
  10917. if( pBestUnit != NULL && iMaxTransportPath < MAX_INT )
  10918. {
  10919. // Can transport reach enemy in requested time
  10920. bool bFoundEnemyPlotInRange = false;
  10921. int iPathTurns;
  10922. int iRange = iMaxTransportPath * pBestUnit->baseMoves();
  10923. CvPlot* pAdjacentPlot = NULL;
  10924. for( int iDX = -iRange; (iDX <= iRange && !bFoundEnemyPlotInRange); iDX++ )
  10925. {
  10926. for( int iDY = -iRange; (iDY <= iRange && !bFoundEnemyPlotInRange); iDY++ )
  10927. {
  10928. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  10929. if( pLoopPlot != NULL )
  10930. {
  10931. if( pLoopPlot->isCoastalLand() )
  10932. {
  10933. if( pLoopPlot->isOwned() )
  10934. {
  10935. if( isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot) && !isBarbarian() )
  10936. {
  10937. if( pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE()) > 0 )
  10938. {
  10939. // Transport cannot enter land plot without cargo, so generate path only works properly if
  10940. // land units are already loaded
  10941. for( int iI = 0; (iI < NUM_DIRECTION_TYPES && !bFoundEnemyPlotInRange); iI++ )
  10942. {
  10943. pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), (DirectionTypes)iI);
  10944. if (pAdjacentPlot != NULL)
  10945. {
  10946. if( pAdjacentPlot->isWater() )
  10947. {
  10948. if( pBestUnit->generatePath(pAdjacentPlot, 0, true, &iPathTurns) )
  10949. {
  10950. if (pBestUnit->getPathLastNode()->m_iData1 == 0)
  10951. {
  10952. iPathTurns++;
  10953. }
  10954. if( iPathTurns <= iMaxTransportPath )
  10955. {
  10956. bFoundEnemyPlotInRange = true;
  10957. }
  10958. }
  10959. }
  10960. }
  10961. }
  10962. }
  10963. }
  10964. }
  10965. }
  10966. }
  10967. }
  10968. }
  10969. if( !bFoundEnemyPlotInRange )
  10970. {
  10971. pBestUnit = NULL;
  10972. }
  10973. }
  10974. if (pBestUnit != NULL)
  10975. {
  10976. if (atPlot(pBestUnit->plot()))
  10977. {
  10978. CvSelectionGroup* pOtherGroup = NULL;
  10979. getGroup()->setTransportUnit(pBestUnit, &pOtherGroup); // XXX is this dangerous (not pushing a mission...) XXX air units?
  10980. // If part of large group loaded, then try to keep loading the rest
  10981. if( eUnitAI == UNITAI_ASSAULT_SEA && eMissionAI == MISSIONAI_LOAD_ASSAULT )
  10982. {
  10983. if( pOtherGroup != NULL && pOtherGroup->getNumUnits() > 0 )
  10984. {
  10985. if( pOtherGroup->getHeadUnitAI() == AI_getUnitAIType() )
  10986. {
  10987. pOtherGroup->getHeadUnit()->AI_load( eUnitAI, eMissionAI, eTransportedUnitAI, iMinCargo, iMinCargoSpace, iMaxCargoSpace, iMaxCargoOurUnitAI, iFlags, 0, iMaxTransportPath );
  10988. }
  10989. else if( eTransportedUnitAI == NO_UNITAI && iMinCargo < 0 && iMinCargoSpace < 0 && iMaxCargoSpace < 0 && iMaxCargoOurUnitAI < 0 )
  10990. {
  10991. pOtherGroup->getHeadUnit()->AI_load( eUnitAI, eMissionAI, NO_UNITAI, -1, -1, -1, -1, iFlags, 0, iMaxTransportPath );
  10992. }
  10993. }
  10994. }
  10995. return true;
  10996. }
  10997. else
  10998. {
  10999. // BBAI TODO: To split or not to split?
  11000. int iCargoSpaceAvailable = pBestUnit->cargoSpaceAvailable(getSpecialUnitType(), getDomainType());
  11001. FAssertMsg(iCargoSpaceAvailable > 0, "best unit has no space");
  11002. // split our group to fit on the transport
  11003. CvSelectionGroup* pOtherGroup = NULL;
  11004. CvSelectionGroup* pSplitGroup = getGroup()->splitGroup(iCargoSpaceAvailable, this, &pOtherGroup);
  11005. FAssertMsg(pSplitGroup != NULL, "splitGroup failed");
  11006. FAssertMsg(m_iGroupID == pSplitGroup->getID(), "splitGroup failed to put unit in the new group");
  11007. if (pSplitGroup != NULL)
  11008. {
  11009. CvPlot* pOldPlot = pSplitGroup->plot();
  11010. pSplitGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), iFlags, false, false, eMissionAI, NULL, pBestUnit);
  11011. bool bMoved = (pSplitGroup->plot() != pOldPlot);
  11012. if (!bMoved && pOtherGroup != NULL)
  11013. {
  11014. joinGroup(pOtherGroup);
  11015. }
  11016. return bMoved;
  11017. }
  11018. }
  11019. }
  11020. return false;
  11021. }
  11022. /************************************************************************************************/
  11023. /* BETTER_BTS_AI_MOD END */
  11024. /************************************************************************************************/
  11025. // Returns true if a mission was pushed...
  11026. bool CvUnitAI::AI_guardCityBestDefender()
  11027. {
  11028. CvCity* pCity;
  11029. CvPlot* pPlot;
  11030. pPlot = plot();
  11031. pCity = pPlot->getPlotCity();
  11032. if (pCity != NULL)
  11033. {
  11034. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  11035. {
  11036. if (pPlot->getBestDefender(getOwnerINLINE()) == this)
  11037. {
  11038. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
  11039. return true;
  11040. }
  11041. }
  11042. }
  11043. return false;
  11044. }
  11045. bool CvUnitAI::AI_guardCityMinDefender(bool bSearch)
  11046. {
  11047. PROFILE_FUNC();
  11048. CvCity* pPlotCity = plot()->getPlotCity();
  11049. if ((pPlotCity != NULL) && (pPlotCity->getOwnerINLINE() == getOwnerINLINE()))
  11050. {
  11051. int iCityDefenderCount;
  11052. // lfgr AI 06/2020: Non-city-defender units now may also call this. If they do, they count every unit.
  11053. // City defenders still only count their own.
  11054. if( AI_getUnitAIType() == UNITAI_CITY_DEFENSE ) {
  11055. iCityDefenderCount = pPlotCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE());
  11056. }
  11057. else {
  11058. iCityDefenderCount = pPlotCity->plot()->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE());
  11059. }
  11060. if ((iCityDefenderCount - 1) < pPlotCity->AI_minDefenders()) // LFGR_TODO: Use -stacksize instead of -1?
  11061. {
  11062. if ((iCityDefenderCount <= 2) || (GC.getGame().getSorenRandNum(5, "AI shuffle defender") != 0)) // LFGR_TODO: make "AI shuffle defender" optional?
  11063. {
  11064. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
  11065. return true;
  11066. }
  11067. }
  11068. }
  11069. if (bSearch)
  11070. {
  11071. int iBestValue = 0;
  11072. CvPlot* pBestPlot = NULL;
  11073. CvPlot* pBestGuardPlot = NULL;
  11074. CvCity* pLoopCity;
  11075. int iLoop;
  11076. int iCurrentTurn = GC.getGame().getGameTurn();
  11077. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  11078. {
  11079. if (AI_plotValid(pLoopCity->plot()))
  11080. {
  11081. /************************************************************************************************/
  11082. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  11083. /* */
  11084. /* Unit AI, Efficiency */
  11085. /************************************************************************************************/
  11086. // BBAI efficiency: check area for land units
  11087. if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
  11088. {
  11089. continue;
  11090. }
  11091. /************************************************************************************************/
  11092. /* BETTER_BTS_AI_MOD END */
  11093. /************************************************************************************************/
  11094. int iDefendersHave = pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE());
  11095. int iDefendersNeed = pLoopCity->AI_minDefenders();
  11096. if (iDefendersHave < iDefendersNeed)
  11097. {
  11098. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  11099. {
  11100. iDefendersHave += GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GUARD_CITY, getGroup());
  11101. if (iDefendersHave < iDefendersNeed + 1)
  11102. {
  11103. /*************************************************************************************************/
  11104. /** SPEED TWEAK Sephi **/
  11105. /** We don't have to check for a path to distant shores if we want to move only short distance **/
  11106. /** anyway, so approx maximum distance for a possible path by iMaxPath **/
  11107. /*************************************************************************************************/
  11108. // int iPathTurns;
  11109. // if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  11110. // {
  11111. // if (iPathTurns <= 10)
  11112. // {
  11113. // int iValue = (iDefendersNeed - iDefendersHave) * 20;
  11114. // iValue += 2 * std::min(15, iCurrentTurn - pLoopCity->getGameTurnAcquired());
  11115. // if (pLoopCity->isOccupation())
  11116. // {
  11117. // iValue += 5;
  11118. // }
  11119. // iValue -= iPathTurns;
  11120. // if (iValue > iBestValue)
  11121. // {
  11122. // iBestValue = iValue;
  11123. // pBestPlot = getPathEndTurnPlot();
  11124. // pBestGuardPlot = pLoopCity->plot();
  11125. // }
  11126. // }
  11127. // }
  11128. int XDist=pLoopCity->plot()->getX_INLINE() - plot()->getX_INLINE();
  11129. int YDist=pLoopCity->plot()->getY_INLINE() - plot()->getY_INLINE();
  11130. if (((XDist*XDist)+(YDist*YDist))<200)
  11131. {
  11132. int iPathTurns;
  11133. if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  11134. {
  11135. if (iPathTurns <= 10)
  11136. {
  11137. int iValue = (iDefendersNeed - iDefendersHave) * 20;
  11138. iValue += 2 * std::min(15, iCurrentTurn - pLoopCity->getGameTurnAcquired());
  11139. if (pLoopCity->isOccupation())
  11140. {
  11141. iValue += 5;
  11142. }
  11143. iValue -= iPathTurns;
  11144. if (iValue > iBestValue)
  11145. {
  11146. iBestValue = iValue;
  11147. pBestPlot = getPathEndTurnPlot();
  11148. pBestGuardPlot = pLoopCity->plot();
  11149. }
  11150. }
  11151. }
  11152. }
  11153. /*************************************************************************************************/
  11154. /** END **/
  11155. /*************************************************************************************************/
  11156. }
  11157. }
  11158. }
  11159. }
  11160. }
  11161. if (pBestPlot != NULL)
  11162. {
  11163. if (atPlot(pBestGuardPlot))
  11164. {
  11165. FAssert(pBestGuardPlot == pBestPlot);
  11166. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
  11167. return true;
  11168. }
  11169. FAssert(!atPlot(pBestPlot));
  11170. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
  11171. return true;
  11172. }
  11173. }
  11174. return false;
  11175. }
  11176. // Returns true if a mission was pushed...
  11177. bool CvUnitAI::AI_guardCity(bool bLeave, bool bSearch, int iMaxPath)
  11178. {
  11179. PROFILE_FUNC();
  11180. CLLNode<IDInfo>* pUnitNode;
  11181. CvCity* pCity;
  11182. CvCity* pLoopCity;
  11183. CvUnit* pLoopUnit;
  11184. CvPlot* pPlot;
  11185. CvPlot* pBestPlot;
  11186. CvPlot* pBestGuardPlot;
  11187. bool bDefend;
  11188. int iExtra;
  11189. int iCount;
  11190. int iPathTurns;
  11191. int iValue;
  11192. int iBestValue;
  11193. int iLoop;
  11194. FAssert(getDomainType() == DOMAIN_LAND);
  11195. //FAssert(getGroup()->canDefend());
  11196. if (!getGroup()->canDefend())
  11197. {
  11198. return false;
  11199. }
  11200. pPlot = plot();
  11201. pCity = pPlot->getPlotCity();
  11202. int pCities = GET_PLAYER(getOwnerINLINE()).getNumCities();
  11203. if (pCities > 1)
  11204. {
  11205. if ((getGroup()->getNumUnits() > (pCities * 5)) && (GET_TEAM(getTeam()).getAtWarCount(true) > 0))
  11206. {
  11207. return false;
  11208. }
  11209. }
  11210. if ((pCity != NULL) && (pCity->getOwnerINLINE() == getOwnerINLINE())) // XXX check for other team?
  11211. {
  11212. if (bLeave && !(pCity->AI_isDanger()))
  11213. {
  11214. iExtra = 1;
  11215. }
  11216. else
  11217. {
  11218. iExtra = (bSearch ? 0 : -GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pPlot, 2));
  11219. }
  11220. bDefend = false;
  11221. if (pPlot->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE()) == 1) // XXX check for other team's units?
  11222. {
  11223. bDefend = true;
  11224. }
  11225. else if (!(pCity->AI_isDefended(((AI_isCityAIType()) ? -1 : 0) + iExtra))) // XXX check for other team's units?
  11226. {
  11227. if (AI_isCityAIType())
  11228. {
  11229. bDefend = true;
  11230. }
  11231. else
  11232. {
  11233. iCount = 0;
  11234. pUnitNode = pPlot->headUnitNode();
  11235. while (pUnitNode != NULL)
  11236. {
  11237. pLoopUnit = ::getUnit(pUnitNode->m_data);
  11238. pUnitNode = pPlot->nextUnitNode(pUnitNode);
  11239. if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
  11240. {
  11241. if (pLoopUnit->isGroupHead())
  11242. {
  11243. if (!(pLoopUnit->isCargo()))
  11244. {
  11245. if (pLoopUnit->canDefend())
  11246. {
  11247. if (!(pLoopUnit->AI_isCityAIType()))
  11248. {
  11249. if (!(pLoopUnit->isHurt()))
  11250. {
  11251. if (pLoopUnit->isWaiting())
  11252. {
  11253. /************************************************************************************************/
  11254. /* BETTER_BTS_AI_MOD 05/24/09 jdog5000 */
  11255. /* */
  11256. /* Unit AI */
  11257. /************************************************************************************************/
  11258. //FAssert(pLoopUnit != this);
  11259. if( pLoopUnit != this )
  11260. {
  11261. iCount++;
  11262. }
  11263. /************************************************************************************************/
  11264. /* BETTER_BTS_AI_MOD END */
  11265. /************************************************************************************************/
  11266. }
  11267. }
  11268. }
  11269. else
  11270. {
  11271. if (pLoopUnit->getGroup()->getMissionType(0) != MISSION_SKIP)
  11272. {
  11273. iCount++;
  11274. }
  11275. }
  11276. }
  11277. }
  11278. }
  11279. }
  11280. }
  11281. if (!(pCity->AI_isDefended(iCount + iExtra))) // XXX check for other team's units?
  11282. {
  11283. bDefend = true;
  11284. }
  11285. }
  11286. }
  11287. if (bDefend)
  11288. {
  11289. CvSelectionGroup* pOldGroup = getGroup();
  11290. CvUnit* pEjectedUnit = getGroup()->AI_ejectBestDefender(pPlot);
  11291. if (pEjectedUnit != NULL)
  11292. {
  11293. if (pPlot->plotCount(PUF_isCityAIType, -1, -1, getOwnerINLINE()) == 0)
  11294. {
  11295. //if (pEjectedUnit->cityDefenseModifier() > 0)
  11296. //if (pEjectedUnit->isUnitAllowedPermDefense())
  11297. {
  11298. logBBAI(" ...setting %S (%d) to city defense from ai_guardcity function", pEjectedUnit->getNameKey(), pEjectedUnit->getID());
  11299. pEjectedUnit->AI_setUnitAIType(UNITAI_CITY_DEFENSE);
  11300. }
  11301. }
  11302. pEjectedUnit->getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
  11303. if (pEjectedUnit->getGroup() == pOldGroup || pEjectedUnit == this)
  11304. {
  11305. return true;
  11306. }
  11307. else
  11308. {
  11309. return false;
  11310. }
  11311. }
  11312. else
  11313. {
  11314. //This unit is not suited for defense, skip the mission
  11315. //to protect this city but encourage others to defend instead.
  11316. getGroup()->pushMission(MISSION_SKIP);
  11317. if (!isHurt())
  11318. {
  11319. finishMoves();
  11320. }
  11321. }
  11322. return true;
  11323. }
  11324. }
  11325. if (bSearch)
  11326. {
  11327. iBestValue = MAX_INT;
  11328. pBestPlot = NULL;
  11329. pBestGuardPlot = NULL;
  11330. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  11331. {
  11332. if (AI_plotValid(pLoopCity->plot()))
  11333. {
  11334. /************************************************************************************************/
  11335. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  11336. /* */
  11337. /* Unit AI, Efficiency */
  11338. /************************************************************************************************/
  11339. // BBAI efficiency: check area for land units
  11340. if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
  11341. {
  11342. continue;
  11343. }
  11344. /************************************************************************************************/
  11345. /* BETTER_BTS_AI_MOD END */
  11346. /************************************************************************************************/
  11347. if (!(pLoopCity->AI_isDefended((!AI_isCityAIType()) ? pLoopCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isNotCityAIType) : 0))) // XXX check for other team's units?
  11348. {
  11349. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  11350. {
  11351. if ((GC.getGame().getGameTurn() - pLoopCity->getGameTurnAcquired() < 10) || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GUARD_CITY, getGroup()) < 2)
  11352. {
  11353. /*************************************************************************************************/
  11354. /** SPEED TWEAK Sephi **/
  11355. /** We don't have to check for a path to distant shores if we want to move only short distance **/
  11356. /** anyway, so approx maximum distance for a possible path by iMaxPath **/
  11357. /*************************************************************************************************/
  11358. // if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  11359. // {
  11360. // if (iPathTurns <= iMaxPath)
  11361. // {
  11362. // iValue = iPathTurns;
  11363. // if (iValue < iBestValue)
  11364. // {
  11365. // iBestValue = iValue;
  11366. // pBestPlot = getPathEndTurnPlot();
  11367. // pBestGuardPlot = pLoopCity->plot();
  11368. // FAssert(!atPlot(pBestPlot));
  11369. // }
  11370. // }
  11371. // }
  11372. int XDist=pLoopCity->plot()->getX_INLINE() - plot()->getX_INLINE();
  11373. int YDist=pLoopCity->plot()->getY_INLINE() - plot()->getY_INLINE();
  11374. if (((XDist*XDist)+(YDist*YDist))<iMaxPath*iMaxPath*4)
  11375. {
  11376. if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  11377. {
  11378. if (iPathTurns <= iMaxPath)
  11379. {
  11380. iValue = iPathTurns;
  11381. if (iValue < iBestValue)
  11382. {
  11383. iBestValue = iValue;
  11384. pBestPlot = getPathEndTurnPlot();
  11385. pBestGuardPlot = pLoopCity->plot();
  11386. FAssert(!atPlot(pBestPlot));
  11387. }
  11388. }
  11389. }
  11390. }
  11391. /*************************************************************************************************/
  11392. /** END **/
  11393. /*************************************************************************************************/
  11394. }
  11395. }
  11396. }
  11397. if (pBestPlot != NULL)
  11398. {
  11399. break;
  11400. }
  11401. }
  11402. }
  11403. if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
  11404. {
  11405. FAssert(!atPlot(pBestPlot));
  11406. // split up group if we are going to defend, so rest of group has opportunity to do something else
  11407. // if (getGroup()->getNumUnits() > 1)
  11408. // {
  11409. // getGroup()->AI_separate(); // will change group
  11410. // }
  11411. //
  11412. // getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
  11413. // return true;
  11414. CvSelectionGroup* pOldGroup = getGroup();
  11415. CvUnit* pEjectedUnit = getGroup()->AI_ejectBestDefender(pPlot);
  11416. if (pEjectedUnit != NULL)
  11417. {
  11418. pEjectedUnit->getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL);
  11419. if (pEjectedUnit->getGroup() == pOldGroup || pEjectedUnit == this)
  11420. {
  11421. return true;
  11422. }
  11423. else
  11424. {
  11425. return false;
  11426. }
  11427. }
  11428. else
  11429. {
  11430. //This unit is not suited for defense, skip the mission
  11431. //to protect this city but encourage others to defend instead.
  11432. if (atPlot(pBestGuardPlot))
  11433. {
  11434. getGroup()->pushMission(MISSION_SKIP);
  11435. }
  11436. else
  11437. {
  11438. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL);
  11439. }
  11440. return true;
  11441. }
  11442. }
  11443. }
  11444. return false;
  11445. }
  11446. // Returns true if a mission was pushed...
  11447. bool CvUnitAI::AI_guardCityAirlift()
  11448. {
  11449. PROFILE_FUNC();
  11450. CvCity* pCity;
  11451. CvCity* pLoopCity;
  11452. CvPlot* pBestPlot;
  11453. int iValue;
  11454. int iBestValue;
  11455. int iLoop;
  11456. if (getGroup()->getNumUnits() > 1)
  11457. {
  11458. return false;
  11459. }
  11460. pCity = plot()->getPlotCity();
  11461. if (pCity == NULL)
  11462. {
  11463. return false;
  11464. }
  11465. if (pCity->getMaxAirlift() == 0)
  11466. {
  11467. return false;
  11468. }
  11469. iBestValue = 0;
  11470. pBestPlot = NULL;
  11471. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  11472. {
  11473. if (pLoopCity != pCity)
  11474. {
  11475. if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
  11476. {
  11477. if (!(pLoopCity->AI_isDefended((!AI_isCityAIType()) ? pLoopCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isNotCityAIType) : 0))) // XXX check for other team's units?
  11478. {
  11479. iValue = pLoopCity->getPopulation();
  11480. if (pLoopCity->AI_isDanger())
  11481. {
  11482. iValue *= 2;
  11483. }
  11484. if (iValue > iBestValue)
  11485. {
  11486. iBestValue = iValue;
  11487. pBestPlot = pLoopCity->plot();
  11488. FAssert(pLoopCity != pCity);
  11489. }
  11490. }
  11491. }
  11492. }
  11493. }
  11494. if (pBestPlot != NULL)
  11495. {
  11496. getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  11497. return true;
  11498. }
  11499. return false;
  11500. }
  11501. // Returns true if a mission was pushed...
  11502. bool CvUnitAI::AI_guardBonus(int iMinValue)
  11503. {
  11504. PROFILE_FUNC();
  11505. CvPlot* pLoopPlot;
  11506. CvPlot* pBestPlot;
  11507. CvPlot* pBestGuardPlot;
  11508. ImprovementTypes eImprovement;
  11509. BonusTypes eNonObsoleteBonus;
  11510. int iPathTurns;
  11511. int iValue;
  11512. int iBestValue;
  11513. int iI;
  11514. iBestValue = 0;
  11515. pBestPlot = NULL;
  11516. pBestGuardPlot = NULL;
  11517. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  11518. {
  11519. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  11520. if (AI_plotValid(pLoopPlot))
  11521. {
  11522. if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
  11523. {
  11524. eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());
  11525. //FfH: Modified by Kael 03/22/2008
  11526. // if (eNonObsoleteBonus != NO_BONUS)
  11527. // {
  11528. // eImprovement = pLoopPlot->getImprovementType();
  11529. //
  11530. // if ((eImprovement != NO_IMPROVEMENT) && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
  11531. // {
  11532. // iValue = GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus);
  11533. // iValue += std::max(0, 200 * GC.getBonusInfo(eNonObsoleteBonus).getAIObjective());
  11534. //
  11535. // if (pLoopPlot->getPlotGroupConnectedBonus(getOwnerINLINE(), eNonObsoleteBonus) == 1)
  11536. // {
  11537. // iValue *= 2;
  11538. // }
  11539. iValue = 0;
  11540. eImprovement = pLoopPlot->getImprovementType();
  11541. if (eImprovement != NO_IMPROVEMENT)
  11542. {
  11543. if (eNonObsoleteBonus != NO_BONUS && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
  11544. {
  11545. iValue += GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus);
  11546. iValue += std::max(0, 200 * GC.getBonusInfo(eNonObsoleteBonus).getAIObjective());
  11547. if (pLoopPlot->getPlotGroupConnectedBonus(getOwnerINLINE(), eNonObsoleteBonus) == 1)
  11548. {
  11549. iValue *= 2;
  11550. }
  11551. }
  11552. iValue += GC.getImprovementInfo(eImprovement).getRangeDefenseModifier() * GC.getImprovementInfo(eImprovement).getRange() * 200;
  11553. iValue += GC.getImprovementInfo(eImprovement).getHealRateChange() * 10;
  11554. iValue += GC.getImprovementInfo(eImprovement).getDefenseModifier();
  11555. //FfH: End Modify
  11556. if (iValue > iMinValue)
  11557. {
  11558. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  11559. {
  11560. // BBAI TODO: Multiple defenders for higher value resources?
  11561. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_BONUS, getGroup()) == 0)
  11562. {
  11563. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  11564. {
  11565. iValue *= 1000;
  11566. iValue /= (iPathTurns + 1);
  11567. if (iValue > iBestValue)
  11568. {
  11569. iBestValue = iValue;
  11570. pBestPlot = getPathEndTurnPlot();
  11571. pBestGuardPlot = pLoopPlot;
  11572. }
  11573. }
  11574. }
  11575. }
  11576. }
  11577. }
  11578. }
  11579. }
  11580. }
  11581. //FfH: Modified by Kael 10/29/2007
  11582. // }
  11583. //FfH: End Modify
  11584. if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
  11585. {
  11586. if (atPlot(pBestGuardPlot))
  11587. {
  11588. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
  11589. return true;
  11590. }
  11591. else
  11592. {
  11593. FAssert(!atPlot(pBestPlot));
  11594. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
  11595. return true;
  11596. }
  11597. }
  11598. return false;
  11599. }
  11600. int CvUnitAI::AI_getPlotDefendersNeeded(CvPlot* pPlot, int iExtra)
  11601. {
  11602. int iNeeded = iExtra;
  11603. BonusTypes eNonObsoleteBonus = pPlot->getNonObsoleteBonusType(getTeam());
  11604. // Super Forts begin *AI_defense*
  11605. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  11606. if (eNonObsoleteBonus != NO_BONUS)
  11607. {
  11608. if (kPlayer.AI_bonusVal(eNonObsoleteBonus, -1) > 10)
  11609. {
  11610. ++iNeeded;
  11611. }
  11612. }
  11613. if (kPlayer.AI_getPlotDanger(pPlot) > 0)
  11614. {
  11615. ++iNeeded;
  11616. if ((kPlayer.AI_getPlotCanalValue(pPlot) > 0)
  11617. || (kPlayer.AI_getPlotChokeValue(pPlot) > 0)
  11618. || (kPlayer.AI_getPlotAirbaseValue(pPlot) > 0))
  11619. {
  11620. ++iNeeded;
  11621. }
  11622. }
  11623. // Super Forts end
  11624. /* Original Code
  11625. if (eNonObsoleteBonus != NO_BONUS)
  11626. {
  11627. iNeeded += (GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus) + 10) / 19;
  11628. }
  11629. int iDefense = pPlot->defenseModifier(getTeam(), true);
  11630. iNeeded += (iDefense + 25) / 50;
  11631. if (iNeeded == 0)
  11632. {
  11633. return 0;
  11634. }
  11635. iNeeded += GET_PLAYER(getOwnerINLINE()).AI_getPlotAirbaseValue(pPlot) / 50;
  11636. int iNumHostiles = 0;
  11637. int iNumPlots = 0;
  11638. int iRange = 2;
  11639. for (int iX = -iRange; iX <= iRange; iX++)
  11640. {
  11641. for (int iY = -iRange; iY <= iRange; iY++)
  11642. {
  11643. CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iX, iY);
  11644. if (pLoopPlot != NULL)
  11645. {
  11646. iNumHostiles += pLoopPlot->getNumVisibleEnemyDefenders(this);
  11647. if ((pLoopPlot->getTeam() != getTeam()) || pLoopPlot->isCoastalLand())
  11648. {
  11649. iNumPlots++;
  11650. if (isEnemy(pLoopPlot->getTeam()))
  11651. {
  11652. iNumPlots += 4;
  11653. }
  11654. }
  11655. }
  11656. }
  11657. }
  11658. if ((iNumHostiles == 0) && (iNumPlots < 4))
  11659. {
  11660. if (iNeeded > 1)
  11661. {
  11662. iNeeded = 1;
  11663. }
  11664. else
  11665. {
  11666. iNeeded = 0;
  11667. }
  11668. } */
  11669. return iNeeded;
  11670. }
  11671. bool CvUnitAI::AI_guardFort(bool bSearch)
  11672. {
  11673. PROFILE_FUNC();
  11674. if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
  11675. {
  11676. return false;
  11677. }
  11678. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  11679. {
  11680. ImprovementTypes eImprovement = plot()->getImprovementType();
  11681. if (eImprovement != NO_IMPROVEMENT)
  11682. {
  11683. if (GC.getImprovementInfo(eImprovement).isActsAsCity())
  11684. {
  11685. // Super Forts begin *AI_defense* - just tweaked a number here (iExtra now 1 instead of 0)
  11686. if (plot()->plotCount(PUF_isCityAIType, -1, -1, getOwnerINLINE()) <= AI_getPlotDefendersNeeded(plot(), 1))
  11687. // Super Forts end
  11688. {
  11689. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, plot());
  11690. return true;
  11691. }
  11692. }
  11693. }
  11694. }
  11695. if (!bSearch)
  11696. {
  11697. return false;
  11698. }
  11699. int iBestValue = 0;
  11700. CvPlot* pBestPlot = NULL;
  11701. CvPlot* pBestGuardPlot = NULL;
  11702. // Tholal note: to be used in the future - try and keep defense units with city defense in cities, and hills defense in hills
  11703. bool bUnitHillsDefense = false;
  11704. bool bUnitCityDefense = false;
  11705. for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  11706. {
  11707. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  11708. if (AI_plotValid(pLoopPlot) && !atPlot(pLoopPlot))
  11709. {
  11710. if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
  11711. {
  11712. ImprovementTypes eImprovement = pLoopPlot->getImprovementType();
  11713. if (eImprovement != NO_IMPROVEMENT)
  11714. {
  11715. if (GC.getImprovementInfo(eImprovement).isActsAsCity())
  11716. {
  11717. // Super Forts begin *AI_defense* - just tweaked a number here (iExtra now 1 instead of 0)
  11718. int iValue = AI_getPlotDefendersNeeded(pLoopPlot, 1);
  11719. // Super Forts end
  11720. if (iValue > 0)
  11721. {
  11722. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  11723. {
  11724. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_BONUS, getGroup()) < iValue)
  11725. {
  11726. int iPathTurns;
  11727. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  11728. {
  11729. iValue *= 1000;
  11730. iValue /= (iPathTurns + 2);
  11731. if (iValue > iBestValue)
  11732. {
  11733. iBestValue = iValue;
  11734. pBestPlot = getPathEndTurnPlot();
  11735. pBestGuardPlot = pLoopPlot;
  11736. }
  11737. }
  11738. }
  11739. }
  11740. }
  11741. }
  11742. }
  11743. }
  11744. }
  11745. }
  11746. if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
  11747. {
  11748. if (atPlot(pBestGuardPlot))
  11749. {
  11750. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
  11751. return true;
  11752. }
  11753. else
  11754. {
  11755. FAssert(!atPlot(pBestPlot));
  11756. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
  11757. return true;
  11758. }
  11759. }
  11760. return false;
  11761. }
  11762. // Super Forts begin *AI_defense* - this is designed to ensure each fort has one defender (or improvements that require a fortified unit to upgrade)
  11763. bool CvUnitAI::AI_guardFortMinDefender(bool bSearch)
  11764. {
  11765. PROFILE_FUNC();
  11766. // LFGR_TODO: Make sure the fort is not about to be conquered
  11767. if(!GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS))
  11768. {
  11769. return false;
  11770. }
  11771. if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
  11772. {
  11773. return false;
  11774. }
  11775. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  11776. {
  11777. ImprovementTypes eImprovement = plot()->getImprovementType();
  11778. if (eImprovement != NO_IMPROVEMENT)
  11779. {
  11780. if (GC.getImprovementInfo(eImprovement).isActsAsCity() || GC.getImprovementInfo(eImprovement).isUpgradeRequiresFortify())
  11781. {
  11782. // lfgr fix 03/2021: Stop non-CityAIType units getting stranded, prefer CityAIType units
  11783. if (plot()->plotCount(PUF_isPreferredDefenderAIType, AI_getUnitAIType(), -1, getOwnerINLINE()) <= 1)
  11784. {
  11785. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, plot());
  11786. return true;
  11787. }
  11788. }
  11789. }
  11790. }
  11791. if (!bSearch)
  11792. {
  11793. return false;
  11794. }
  11795. int iBestValue = 0;
  11796. CvPlot* pBestPlot = NULL;
  11797. CvPlot* pBestGuardPlot = NULL;
  11798. for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  11799. {
  11800. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  11801. if (AI_plotValid(pLoopPlot) && !atPlot(pLoopPlot))
  11802. {
  11803. if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
  11804. {
  11805. ImprovementTypes eImprovement = pLoopPlot->getImprovementType();
  11806. if (eImprovement != NO_IMPROVEMENT)
  11807. {
  11808. if (GC.getImprovementInfo(eImprovement).isActsAsCity() || GC.getImprovementInfo(eImprovement).isUpgradeRequiresFortify())
  11809. {
  11810. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  11811. {
  11812. // lfgr fix 03/2021: Stop non-CityAIType units getting stranded, prefer CityAIType units
  11813. if (pLoopPlot->plotCount(PUF_isPreferredDefenderAIType, AI_getUnitAIType(), -1, getOwnerINLINE()) == 0)
  11814. {
  11815. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_BONUS, getGroup()) == 0)
  11816. {
  11817. int iPathTurns;
  11818. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  11819. {
  11820. int iValue = 1000;
  11821. iValue /= (iPathTurns + 2);
  11822. if (iValue > iBestValue)
  11823. {
  11824. iBestValue = iValue;
  11825. pBestPlot = getPathEndTurnPlot();
  11826. pBestGuardPlot = pLoopPlot;
  11827. }
  11828. }
  11829. }
  11830. }
  11831. }
  11832. }
  11833. }
  11834. }
  11835. }
  11836. }
  11837. if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
  11838. {
  11839. if (atPlot(pBestGuardPlot))
  11840. {
  11841. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
  11842. return true;
  11843. }
  11844. else
  11845. {
  11846. FAssert(!atPlot(pBestPlot));
  11847. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
  11848. return true;
  11849. }
  11850. }
  11851. return false;
  11852. }
  11853. // Super Forts end
  11854. // Returns true if a mission was pushed...
  11855. bool CvUnitAI::AI_guardCitySite()
  11856. {
  11857. PROFILE_FUNC();
  11858. CvPlot* pLoopPlot;
  11859. CvPlot* pBestPlot;
  11860. CvPlot* pBestGuardPlot;
  11861. int iPathTurns;
  11862. int iValue;
  11863. int iBestValue;
  11864. int iI;
  11865. iBestValue = 0;
  11866. pBestPlot = NULL;
  11867. pBestGuardPlot = NULL;
  11868. for (iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
  11869. {
  11870. pLoopPlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
  11871. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_CITY, getGroup()) == 0)
  11872. {
  11873. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  11874. {
  11875. iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
  11876. if (iValue > iBestValue)
  11877. {
  11878. iBestValue = iValue;
  11879. pBestPlot = getPathEndTurnPlot();
  11880. pBestGuardPlot = pLoopPlot;
  11881. }
  11882. }
  11883. }
  11884. }
  11885. if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
  11886. {
  11887. if (atPlot(pBestGuardPlot))
  11888. {
  11889. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
  11890. return true;
  11891. }
  11892. else
  11893. {
  11894. FAssert(!atPlot(pBestPlot));
  11895. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
  11896. return true;
  11897. }
  11898. }
  11899. return false;
  11900. }
  11901. // Returns true if a mission was pushed...
  11902. bool CvUnitAI::AI_guardSpy(int iRandomPercent)
  11903. {
  11904. PROFILE_FUNC();
  11905. CvCity* pLoopCity;
  11906. CvPlot* pBestPlot;
  11907. CvPlot* pBestGuardPlot;
  11908. int iValue;
  11909. int iBestValue;
  11910. int iLoop;
  11911. iBestValue = 0;
  11912. pBestPlot = NULL;
  11913. pBestGuardPlot = NULL;
  11914. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  11915. {
  11916. if (AI_plotValid(pLoopCity->plot()))
  11917. {
  11918. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  11919. {
  11920. /************************************************************************************************/
  11921. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  11922. /* */
  11923. /* Unit AI, Efficiency */
  11924. /************************************************************************************************/
  11925. // BBAI efficiency: check area for land units
  11926. if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
  11927. {
  11928. continue;
  11929. }
  11930. iValue = 0;
  11931. if( GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_SPACE4) )
  11932. {
  11933. if( pLoopCity->isCapital() )
  11934. {
  11935. iValue += 30;
  11936. }
  11937. else if( pLoopCity->isProductionProject() )
  11938. {
  11939. iValue += 5;
  11940. }
  11941. }
  11942. if( GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE3) )
  11943. {
  11944. if( pLoopCity->getCultureLevel() >= (GC.getNumCultureLevelInfos() - 2))
  11945. {
  11946. iValue += 10;
  11947. }
  11948. }
  11949. if (pLoopCity->isProductionUnit())
  11950. {
  11951. if (isLimitedUnitClass((UnitClassTypes)(GC.getUnitInfo(pLoopCity->getProductionUnit()).getUnitClassType())))
  11952. {
  11953. iValue += 4;
  11954. }
  11955. }
  11956. else if (pLoopCity->isProductionBuilding())
  11957. {
  11958. if (isLimitedWonderClass((BuildingClassTypes)(GC.getBuildingInfo(pLoopCity->getProductionBuilding()).getBuildingClassType())))
  11959. {
  11960. iValue += 5;
  11961. }
  11962. }
  11963. else if (pLoopCity->isProductionProject())
  11964. {
  11965. if (isLimitedProject(pLoopCity->getProductionProject()))
  11966. {
  11967. iValue += 6;
  11968. }
  11969. }
  11970. /************************************************************************************************/
  11971. /* BETTER_BTS_AI_MOD END */
  11972. /************************************************************************************************/
  11973. if (iValue > 0)
  11974. {
  11975. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GUARD_SPY, getGroup()) == 0)
  11976. {
  11977. int iPathTurns;
  11978. if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  11979. {
  11980. iValue *= 100 + GC.getGameINLINE().getSorenRandNum(iRandomPercent, "AI Guard Spy");
  11981. //iValue /= 100;
  11982. iValue /= iPathTurns + 1;
  11983. if (iValue > iBestValue)
  11984. {
  11985. iBestValue = iValue;
  11986. pBestPlot = getPathEndTurnPlot();
  11987. pBestGuardPlot = pLoopCity->plot();
  11988. }
  11989. }
  11990. }
  11991. }
  11992. }
  11993. }
  11994. }
  11995. if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
  11996. {
  11997. if (atPlot(pBestGuardPlot))
  11998. {
  11999. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_SPY, pBestGuardPlot);
  12000. return true;
  12001. }
  12002. else
  12003. {
  12004. FAssert(!atPlot(pBestPlot));
  12005. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_SPY, pBestGuardPlot);
  12006. return true;
  12007. }
  12008. }
  12009. return false;
  12010. }
  12011. /************************************************************************************************/
  12012. /* BETTER_BTS_AI_MOD 10/25/09 jdog5000 */
  12013. /* */
  12014. /* Espionage AI */
  12015. /************************************************************************************************/
  12016. /*
  12017. // Never used BTS functions ...
  12018. // Returns true if a mission was pushed...
  12019. bool CvUnitAI::AI_destroySpy()
  12020. {
  12021. PROFILE_FUNC();
  12022. CvCity* pLoopCity;
  12023. CvCity* pBestCity;
  12024. CvPlot* pBestPlot;
  12025. int iValue;
  12026. int iBestValue;
  12027. int iLoop;
  12028. int iI;
  12029. iBestValue = 0;
  12030. pBestPlot = NULL;
  12031. pBestCity = NULL;
  12032. for (iI = 0; iI < MAX_CIV_PLAYERS; iI++)
  12033. {
  12034. if (GET_PLAYER((PlayerTypes)iI).isAlive())
  12035. {
  12036. if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
  12037. {
  12038. if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_ANNOYED)
  12039. {
  12040. for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
  12041. {
  12042. if (AI_plotValid(pLoopCity->plot()))
  12043. {
  12044. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ATTACK_SPY, getGroup()) == 0)
  12045. {
  12046. if (generatePath(pLoopCity->plot(), 0, true))
  12047. {
  12048. iValue = (pLoopCity->getPopulation() * 2);
  12049. iValue += pLoopCity->getYieldRate(YIELD_PRODUCTION);
  12050. if (atPlot(pLoopCity->plot()))
  12051. {
  12052. iValue *= 4;
  12053. iValue /= 3;
  12054. }
  12055. if (iValue > iBestValue)
  12056. {
  12057. iBestValue = iValue;
  12058. pBestPlot = getPathEndTurnPlot();
  12059. pBestCity = pLoopCity;
  12060. }
  12061. }
  12062. }
  12063. }
  12064. }
  12065. }
  12066. }
  12067. }
  12068. }
  12069. if ((pBestPlot != NULL) && (pBestCity != NULL))
  12070. {
  12071. if (atPlot(pBestCity->plot()))
  12072. {
  12073. if (canDestroy(pBestCity->plot()))
  12074. {
  12075. if (pBestCity->getProduction() > ((pBestCity->getProductionNeeded() * 2) / 3))
  12076. {
  12077. if (pBestCity->isProductionUnit())
  12078. {
  12079. if (isLimitedUnitClass((UnitClassTypes)(GC.getUnitInfo(pBestCity->getProductionUnit()).getUnitClassType())))
  12080. {
  12081. getGroup()->pushMission(MISSION_DESTROY);
  12082. return true;
  12083. }
  12084. }
  12085. else if (pBestCity->isProductionBuilding())
  12086. {
  12087. if (isLimitedWonderClass((BuildingClassTypes)(GC.getBuildingInfo(pBestCity->getProductionBuilding()).getBuildingClassType())))
  12088. {
  12089. getGroup()->pushMission(MISSION_DESTROY);
  12090. return true;
  12091. }
  12092. }
  12093. else if (pBestCity->isProductionProject())
  12094. {
  12095. if (isLimitedProject(pBestCity->getProductionProject()))
  12096. {
  12097. getGroup()->pushMission(MISSION_DESTROY);
  12098. return true;
  12099. }
  12100. }
  12101. }
  12102. }
  12103. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY, pBestCity->plot());
  12104. return true;
  12105. }
  12106. else
  12107. {
  12108. FAssert(!atPlot(pBestPlot));
  12109. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestCity->plot());
  12110. return true;
  12111. }
  12112. }
  12113. return false;
  12114. }
  12115. // Returns true if a mission was pushed...
  12116. bool CvUnitAI::AI_sabotageSpy()
  12117. {
  12118. PROFILE_FUNC();
  12119. CvPlot* pLoopPlot;
  12120. CvPlot* pBestPlot;
  12121. CvPlot* pBestSabotagePlot;
  12122. bool abPlayerAngry[MAX_PLAYERS];
  12123. ImprovementTypes eImprovement;
  12124. BonusTypes eNonObsoleteBonus;
  12125. int iValue;
  12126. int iBestValue;
  12127. int iI;
  12128. for (iI = 0; iI < MAX_PLAYERS; iI++)
  12129. {
  12130. abPlayerAngry[iI] = false;
  12131. if (GET_PLAYER((PlayerTypes)iI).isAlive())
  12132. {
  12133. if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
  12134. {
  12135. if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_ANNOYED)
  12136. {
  12137. abPlayerAngry[iI] = true;
  12138. }
  12139. }
  12140. }
  12141. }
  12142. iBestValue = 0;
  12143. pBestPlot = NULL;
  12144. pBestSabotagePlot = NULL;
  12145. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  12146. {
  12147. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  12148. if (AI_plotValid(pLoopPlot))
  12149. {
  12150. if (pLoopPlot->isOwned())
  12151. {
  12152. if (pLoopPlot->getTeam() != getTeam())
  12153. {
  12154. if (abPlayerAngry[pLoopPlot->getOwnerINLINE()])
  12155. {
  12156. eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(pLoopPlot->getTeam());
  12157. if (eNonObsoleteBonus != NO_BONUS)
  12158. {
  12159. eImprovement = pLoopPlot->getImprovementType();
  12160. if ((eImprovement != NO_IMPROVEMENT) && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
  12161. {
  12162. if (canSabotage(pLoopPlot))
  12163. {
  12164. iValue = GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus);
  12165. if (pLoopPlot->isConnectedToCapital() && (pLoopPlot->getPlotGroupConnectedBonus(pLoopPlot->getOwnerINLINE(), eNonObsoleteBonus) == 1))
  12166. {
  12167. iValue *= 3;
  12168. }
  12169. if (iValue > 25)
  12170. {
  12171. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ATTACK_SPY, getGroup()) == 0)
  12172. {
  12173. if (generatePath(pLoopPlot, 0, true))
  12174. {
  12175. if (iValue > iBestValue)
  12176. {
  12177. iBestValue = iValue;
  12178. pBestPlot = getPathEndTurnPlot();
  12179. pBestSabotagePlot = pLoopPlot;
  12180. }
  12181. }
  12182. }
  12183. }
  12184. }
  12185. }
  12186. }
  12187. }
  12188. }
  12189. }
  12190. }
  12191. }
  12192. if ((pBestPlot != NULL) && (pBestSabotagePlot != NULL))
  12193. {
  12194. if (atPlot(pBestSabotagePlot))
  12195. {
  12196. getGroup()->pushMission(MISSION_SABOTAGE);
  12197. return true;
  12198. }
  12199. else
  12200. {
  12201. FAssert(!atPlot(pBestPlot));
  12202. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestSabotagePlot);
  12203. return true;
  12204. }
  12205. }
  12206. return false;
  12207. }
  12208. bool CvUnitAI::AI_pickupTargetSpy()
  12209. {
  12210. PROFILE_FUNC();
  12211. CvCity* pCity;
  12212. CvCity* pLoopCity;
  12213. CvPlot* pBestPlot;
  12214. CvPlot* pBestPickupPlot;
  12215. int iPathTurns;
  12216. int iValue;
  12217. int iBestValue;
  12218. int iLoop;
  12219. pCity = plot()->getPlotCity();
  12220. if (pCity != NULL)
  12221. {
  12222. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  12223. {
  12224. if (pCity->isCoastal(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
  12225. {
  12226. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY, pCity->plot());
  12227. return true;
  12228. }
  12229. }
  12230. }
  12231. iBestValue = MAX_INT;
  12232. pBestPlot = NULL;
  12233. pBestPickupPlot = NULL;
  12234. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  12235. {
  12236. if (AI_plotValid(pLoopCity->plot()))
  12237. {
  12238. if (pLoopCity->isCoastal(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
  12239. {
  12240. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  12241. {
  12242. if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  12243. {
  12244. iValue = iPathTurns;
  12245. if (iValue < iBestValue)
  12246. {
  12247. iBestValue = iValue;
  12248. pBestPlot = getPathEndTurnPlot();
  12249. pBestPickupPlot = pLoopCity->plot();
  12250. FAssert(!atPlot(pBestPlot));
  12251. }
  12252. }
  12253. }
  12254. }
  12255. }
  12256. }
  12257. if ((pBestPlot != NULL) && (pBestPickupPlot != NULL))
  12258. {
  12259. FAssert(!atPlot(pBestPlot));
  12260. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestPickupPlot);
  12261. return true;
  12262. }
  12263. return false;
  12264. }
  12265. */
  12266. /************************************************************************************************/
  12267. /* BETTER_BTS_AI_MOD END */
  12268. /************************************************************************************************/
  12269. // Returns true if a mission was pushed...
  12270. bool CvUnitAI::AI_chokeDefend()
  12271. {
  12272. CvCity* pCity;
  12273. int iPlotDanger;
  12274. //FAssert(AI_isCityAIType());
  12275. // XXX what about amphib invasions?
  12276. pCity = plot()->getPlotCity();
  12277. if (pCity != NULL)
  12278. {
  12279. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  12280. {
  12281. if (pCity->AI_neededDefenders() > 1)
  12282. {
  12283. if (pCity->AI_isDefended(pCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isNotCityAIType)))
  12284. {
  12285. iPlotDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3);
  12286. if (iPlotDanger <= 4)
  12287. {
  12288. if (AI_anyAttack(1, 65, std::max(0, (iPlotDanger - 1))))
  12289. {
  12290. return true;
  12291. }
  12292. }
  12293. }
  12294. }
  12295. }
  12296. }
  12297. return false;
  12298. }
  12299. // Returns true if a mission was pushed...
  12300. bool CvUnitAI::AI_heal(int iDamagePercent, int iMaxPath)
  12301. {
  12302. PROFILE_FUNC();
  12303. CLLNode<IDInfo>* pEntityNode;
  12304. std::vector<CvUnit*> aeDamagedUnits;
  12305. CvSelectionGroup* pGroup;
  12306. CvUnit* pLoopUnit;
  12307. int iTotalDamage;
  12308. int iTotalHitpoints;
  12309. int iHurtUnitCount;
  12310. bool bRetreat;
  12311. if (plot()->getFeatureType() != NO_FEATURE)
  12312. {
  12313. // Mongoose FeatureDamageFix BEGIN
  12314. if (GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() > 0)
  12315. // Mongoose FeatureDamageFix END
  12316. {
  12317. //Pass through
  12318. //(actively seeking a safe spot may result in unit getting stuck)
  12319. return false;
  12320. }
  12321. }
  12322. //FfH: Added by Kael 10/01/2007 (so the AI won't try to sit and heal in areas where they cant heal)
  12323. if (healRate(plot()) == 0)
  12324. {
  12325. return false;
  12326. }
  12327. //FfH: End Add
  12328. pGroup = getGroup();
  12329. if (iDamagePercent == 0)
  12330. {
  12331. iDamagePercent = 10;
  12332. }
  12333. bRetreat = false; // Tholal Note: This variable is never used
  12334. if (getGroup()->getNumUnits() == 1)
  12335. {
  12336. if (getDamage() > 0)
  12337. {
  12338. if (plot()->isCity() || (healTurns(plot()) == 1)
  12339. // Tholal AI (by Red Key) - allow barbarian animals to heal
  12340. || (isBarbarian() && isAnimal())
  12341. || (plot()->defenseModifier(getTeam(), false) > 0)) // units on defensive terrain should also try to heal
  12342. // End Tholal AI
  12343. {
  12344. if (!(isAlwaysHeal()))
  12345. {
  12346. getGroup()->pushMission(MISSION_HEAL);
  12347. return true;
  12348. }
  12349. }
  12350. else
  12351. {
  12352. if (AI_seekDefensiveGround(1, true))
  12353. {
  12354. return true;
  12355. }
  12356. }
  12357. }
  12358. return false;
  12359. }
  12360. iMaxPath = std::min(iMaxPath, 4);
  12361. pEntityNode = getGroup()->headUnitNode();
  12362. iTotalDamage = 0;
  12363. iTotalHitpoints = 0;
  12364. iHurtUnitCount = 0;
  12365. while (pEntityNode != NULL)
  12366. {
  12367. pLoopUnit = ::getUnit(pEntityNode->m_data);
  12368. FAssert(pLoopUnit != NULL);
  12369. pEntityNode = pGroup->nextUnitNode(pEntityNode);
  12370. int iDamageThreshold = (pLoopUnit->maxHitPoints() * iDamagePercent) / 100;
  12371. if (NO_UNIT != getLeaderUnitType())
  12372. {
  12373. iDamageThreshold /= 2;
  12374. }
  12375. if (pLoopUnit->getDamage() > 0)
  12376. {
  12377. iHurtUnitCount++;
  12378. }
  12379. iTotalDamage += pLoopUnit->getDamage();
  12380. iTotalHitpoints += pLoopUnit->maxHitPoints();
  12381. if (pLoopUnit->getDamage() > iDamageThreshold)
  12382. {
  12383. bRetreat = true;
  12384. if (!(pLoopUnit->hasMoved()))
  12385. {
  12386. if (!(pLoopUnit->isAlwaysHeal()))
  12387. {
  12388. if (pLoopUnit->healTurns(pLoopUnit->plot()) <= iMaxPath)
  12389. {
  12390. aeDamagedUnits.push_back(pLoopUnit);
  12391. }
  12392. }
  12393. }
  12394. }
  12395. }
  12396. if (iHurtUnitCount == 0)
  12397. {
  12398. return false;
  12399. }
  12400. bool bPushedMission = false;
  12401. if (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()))
  12402. {
  12403. FAssertMsg(((int) aeDamagedUnits.size()) <= iHurtUnitCount, "damaged units array is larger than our hurt unit count");
  12404. for (unsigned int iI = 0; iI < aeDamagedUnits.size(); iI++)
  12405. {
  12406. CvUnit* pUnitToHeal = aeDamagedUnits[iI];
  12407. if (pGroup->getNumUnits() > 2)
  12408. {
  12409. pUnitToHeal->joinGroup(NULL);
  12410. }
  12411. pUnitToHeal->getGroup()->pushMission(MISSION_HEAL);
  12412. // note, removing the head unit from a group will force the group to be completely split if non-human
  12413. if (pUnitToHeal == this)
  12414. {
  12415. bPushedMission = true;
  12416. }
  12417. iHurtUnitCount--;
  12418. }
  12419. }
  12420. if ((iHurtUnitCount * 2) > pGroup->getNumUnits())
  12421. {
  12422. FAssertMsg(pGroup->getNumUnits() > 0, "group now has zero units");
  12423. if (AI_moveIntoCity(2))
  12424. {
  12425. return true;
  12426. }
  12427. else if (healRate(plot()) > 10)
  12428. {
  12429. pGroup->pushMission(MISSION_HEAL);
  12430. return true;
  12431. }
  12432. }
  12433. return bPushedMission;
  12434. }
  12435. // Returns true if a mission was pushed...
  12436. bool CvUnitAI::AI_afterAttack()
  12437. {
  12438. if (!isMadeAttack())
  12439. {
  12440. return false;
  12441. }
  12442. if (!canFight())
  12443. {
  12444. return false;
  12445. }
  12446. if (isBlitz())
  12447. {
  12448. return false;
  12449. }
  12450. if (getDomainType() == DOMAIN_LAND)
  12451. {
  12452. if (AI_guardCity(false, true, 1))
  12453. {
  12454. return true;
  12455. }
  12456. }
  12457. if (AI_pillageRange(1))
  12458. {
  12459. return true;
  12460. }
  12461. if (AI_retreatToCity(false, false, 1))
  12462. {
  12463. return true;
  12464. }
  12465. if (AI_hide())
  12466. {
  12467. return true;
  12468. }
  12469. if (AI_goody(1))
  12470. {
  12471. return true;
  12472. }
  12473. if (AI_pillageRange(2))
  12474. {
  12475. return true;
  12476. }
  12477. if (AI_defend())
  12478. {
  12479. return true;
  12480. }
  12481. if (AI_safety())
  12482. {
  12483. return true;
  12484. }
  12485. return false;
  12486. }
  12487. // Returns true if a mission was pushed...
  12488. bool CvUnitAI::AI_goldenAge()
  12489. {
  12490. if (canGoldenAge(plot()))
  12491. {
  12492. logBBAI(" %S (%d) starting Golden Age (%d units used)", getName().GetCString(), getID(), GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge());
  12493. getGroup()->pushMission(MISSION_GOLDEN_AGE);
  12494. return true;
  12495. }
  12496. return false;
  12497. }
  12498. // Returns true if a mission was pushed...
  12499. bool CvUnitAI::AI_spreadReligion()
  12500. {
  12501. PROFILE_FUNC();
  12502. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  12503. // CvCity* pLoopCity;
  12504. CvPlot* pBestPlot;
  12505. CvPlot* pBestSpreadPlot;
  12506. ReligionTypes eReligion;
  12507. int iPathTurns;
  12508. int iValue;
  12509. int iBestValue;
  12510. int iPlayerMultiplierPercent;
  12511. int iLoop;
  12512. int iI;
  12513. bool bCultureVictory = kOwner.AI_isDoVictoryStrategy(AI_VICTORY_CULTURE2);
  12514. eReligion = NO_RELIGION;
  12515. if (kOwner.getStateReligion() != NO_RELIGION)
  12516. {
  12517. if (m_pUnitInfo->getReligionSpreads(kOwner.getStateReligion()) > 0)
  12518. {
  12519. eReligion = kOwner.getStateReligion();
  12520. }
  12521. }
  12522. if (eReligion == NO_RELIGION)
  12523. {
  12524. for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
  12525. {
  12526. //if (bCultureVictory || GET_TEAM(getTeam()).hasHolyCity((ReligionTypes)iI))
  12527. {
  12528. if (m_pUnitInfo->getReligionSpreads((ReligionTypes)iI) > 0)
  12529. {
  12530. eReligion = ((ReligionTypes)iI);
  12531. break;
  12532. }
  12533. }
  12534. }
  12535. }
  12536. if (eReligion == NO_RELIGION)
  12537. {
  12538. return false;
  12539. }
  12540. bool bHasHolyCity = GET_TEAM(getTeam()).hasHolyCity(eReligion);
  12541. bool bHasAnyHolyCity = bHasHolyCity;
  12542. if (!bHasAnyHolyCity)
  12543. {
  12544. for (iI = 0; !bHasAnyHolyCity && iI < GC.getNumReligionInfos(); iI++)
  12545. {
  12546. bHasAnyHolyCity = GET_TEAM(getTeam()).hasHolyCity((ReligionTypes)iI);
  12547. }
  12548. }
  12549. iBestValue = 0;
  12550. pBestPlot = NULL;
  12551. pBestSpreadPlot = NULL;
  12552. for (iI = 0; iI < MAX_PLAYERS; iI++)
  12553. {
  12554. const CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
  12555. if (kLoopPlayer.isAlive() && !kLoopPlayer.isBarbarian())
  12556. {
  12557. iPlayerMultiplierPercent = 0;
  12558. if (kLoopPlayer.getTeam() != getTeam() && canEnterTerritory(kLoopPlayer.getTeam()))
  12559. {
  12560. if (bHasHolyCity)
  12561. {
  12562. iPlayerMultiplierPercent = 100;
  12563. if (!bCultureVictory || (eReligion == kOwner.getStateReligion()))
  12564. {
  12565. if (kLoopPlayer.getStateReligion() == NO_RELIGION)
  12566. {
  12567. if (0 == (kLoopPlayer.getNonStateReligionHappiness()))
  12568. {
  12569. iPlayerMultiplierPercent += 600;
  12570. }
  12571. }
  12572. else if (kLoopPlayer.getStateReligion() == eReligion)
  12573. {
  12574. iPlayerMultiplierPercent += 300;
  12575. }
  12576. else
  12577. {
  12578. if (kLoopPlayer.hasHolyCity(kLoopPlayer.getStateReligion()))
  12579. {
  12580. iPlayerMultiplierPercent += 50;
  12581. }
  12582. else
  12583. {
  12584. iPlayerMultiplierPercent += 300;
  12585. }
  12586. }
  12587. int iReligionCount = kLoopPlayer.countTotalHasReligion();
  12588. //int iCityCount = kOwner.getNumCities();
  12589. int iCityCount = kLoopPlayer.getNumCities(); // K-Mod!
  12590. //magic formula to produce normalized adjustment factor based on religious infusion
  12591. int iAdjustment = (100 * (iCityCount + 1));
  12592. iAdjustment /= ((iCityCount + 1) + iReligionCount);
  12593. iAdjustment = (((iAdjustment - 25) * 4) / 3);
  12594. iAdjustment = std::max(10, iAdjustment);
  12595. iPlayerMultiplierPercent *= iAdjustment;
  12596. iPlayerMultiplierPercent /= 100;
  12597. }
  12598. }
  12599. }
  12600. else if (iI == getOwnerINLINE())
  12601. {
  12602. iPlayerMultiplierPercent = 100;
  12603. }
  12604. else if (bHasHolyCity && kLoopPlayer.getTeam() == getTeam())
  12605. {
  12606. iPlayerMultiplierPercent = 80;
  12607. }
  12608. /************************************************************************************************/
  12609. /* BETTER_BTS_AI_MOD END */
  12610. /************************************************************************************************/
  12611. if (iPlayerMultiplierPercent > 0)
  12612. {
  12613. for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kLoopPlayer.nextCity(&iLoop))
  12614. {
  12615. if (AI_plotValid(pLoopCity->plot()) && pLoopCity->area() == area() && (pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam())))
  12616. {
  12617. if (canSpread(pLoopCity->plot(), eReligion))
  12618. {
  12619. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  12620. {
  12621. if (kOwner.AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD, getGroup()) == 0)
  12622. {
  12623. /************************************************************************************************/
  12624. /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
  12625. /* */
  12626. /* Unit AI */
  12627. /************************************************************************************************/
  12628. if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
  12629. /************************************************************************************************/
  12630. /* BETTER_BTS_AI_MOD END */
  12631. /************************************************************************************************/
  12632. {
  12633. iValue = (7 + (pLoopCity->getPopulation() * 4));
  12634. bool bOurCity = false;
  12635. if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
  12636. {
  12637. iValue *= (bCultureVictory ? 16 : 4);
  12638. bOurCity = true;
  12639. }
  12640. else if (pLoopCity->getTeam() == getTeam())
  12641. {
  12642. iValue *= 3;
  12643. bOurCity = true;
  12644. }
  12645. else
  12646. {
  12647. iValue *= iPlayerMultiplierPercent;
  12648. iValue /= 100;
  12649. }
  12650. int iCityReligionCount = pLoopCity->getReligionCount();
  12651. int iReligionCountFactor = iCityReligionCount;
  12652. if (bOurCity)
  12653. {
  12654. // count cities with no religion the same as cities with 2 religions
  12655. // prefer a city with exactly 1 religion already
  12656. iValue *= 2; // Tholal AI - better to spread to our cities first
  12657. if (iCityReligionCount == 0)
  12658. {
  12659. iReligionCountFactor = 2;
  12660. }
  12661. else if (iCityReligionCount == 1)
  12662. {
  12663. iValue *= 2;
  12664. }
  12665. }
  12666. else
  12667. {
  12668. // absolutely prefer cities with zero religions
  12669. if (iCityReligionCount == 0)
  12670. {
  12671. iValue *= 2;
  12672. }
  12673. // not our city, so prefer the lowest number of religions (increment so no divide by zero)
  12674. iReligionCountFactor++;
  12675. }
  12676. iValue /= iReligionCountFactor;
  12677. FAssert(iPathTurns > 0);
  12678. bool bForceMove = false;
  12679. if (isHuman())
  12680. {
  12681. //If human, prefer to spread to the player where automated from.
  12682. if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
  12683. {
  12684. iValue *= 10;
  12685. if (pLoopCity->isRevealed(getTeam(), false))
  12686. {
  12687. bForceMove = true;
  12688. }
  12689. }
  12690. }
  12691. iValue *= 1000;
  12692. iValue /= (iPathTurns + 2);
  12693. if (iValue > iBestValue)
  12694. {
  12695. iBestValue = iValue;
  12696. pBestPlot = bForceMove ? pLoopCity->plot() : getPathEndTurnPlot();
  12697. pBestSpreadPlot = pLoopCity->plot();
  12698. }
  12699. }
  12700. }
  12701. }
  12702. }
  12703. }
  12704. }
  12705. }
  12706. }
  12707. }
  12708. if ((pBestPlot != NULL) && (pBestSpreadPlot != NULL))
  12709. {
  12710. if (atPlot(pBestSpreadPlot))
  12711. {
  12712. getGroup()->pushMission(MISSION_SPREAD, eReligion);
  12713. return true;
  12714. }
  12715. else
  12716. {
  12717. FAssert(!atPlot(pBestPlot));
  12718. /************************************************************************************************/
  12719. /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
  12720. /* */
  12721. /* Unit AI */
  12722. /************************************************************************************************/
  12723. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_SPREAD, pBestSpreadPlot);
  12724. /************************************************************************************************/
  12725. /* BETTER_BTS_AI_MOD END */
  12726. /************************************************************************************************/
  12727. return true;
  12728. }
  12729. }
  12730. return false;
  12731. }
  12732. // Returns true if a mission was pushed...
  12733. bool CvUnitAI::AI_spreadCorporation()
  12734. {
  12735. PROFILE_FUNC();
  12736. CorporationTypes eCorporation = NO_CORPORATION;
  12737. for (int iI = 0; iI < GC.getNumCorporationInfos(); ++iI)
  12738. {
  12739. if (m_pUnitInfo->getCorporationSpreads((CorporationTypes)iI) > 0)
  12740. {
  12741. eCorporation = ((CorporationTypes)iI);
  12742. break;
  12743. }
  12744. }
  12745. if (NO_CORPORATION == eCorporation)
  12746. {
  12747. return false;
  12748. }
  12749. bool bHasHQ = (GET_TEAM(getTeam()).hasHeadquarters((CorporationTypes)iI));
  12750. int iBestValue = 0;
  12751. CvPlot* pBestPlot = NULL;
  12752. CvPlot* pBestSpreadPlot = NULL;
  12753. CvTeam& kTeam = GET_TEAM(getTeam());
  12754. for (int iI = 0; iI < MAX_PLAYERS; iI++)
  12755. {
  12756. CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
  12757. /************************************************************************************************/
  12758. /* BETTER_BTS_AI_MOD 08/21/09 jdog5000 */
  12759. /* */
  12760. /* Unit AI, Efficiency */
  12761. /************************************************************************************************/
  12762. //if (kLoopPlayer.isAlive() && (bHasHQ || (getTeam() == kLoopPlayer.getTeam())))
  12763. if (kLoopPlayer.isAlive() && ((bHasHQ && canEnterTerritory(GET_PLAYER((PlayerTypes)iI).getTeam())) || (getTeam() == kLoopPlayer.getTeam())))
  12764. {
  12765. /************************************************************************************************/
  12766. /* BETTER_BTS_AI_MOD END */
  12767. /************************************************************************************************/
  12768. int iLoopPlayerCorpCount = kLoopPlayer.countCorporations(eCorporation);
  12769. CvTeam& kLoopTeam = GET_TEAM(kLoopPlayer.getTeam());
  12770. int iLoop;
  12771. for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
  12772. {
  12773. if (AI_plotValid(pLoopCity->plot()))
  12774. {
  12775. /************************************************************************************************/
  12776. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  12777. /* */
  12778. /* Unit AI, Efficiency */
  12779. /************************************************************************************************/
  12780. // BBAI efficiency: check same area
  12781. if ( pLoopCity->area() == area() && canSpreadCorporation(pLoopCity->plot(), eCorporation))
  12782. /************************************************************************************************/
  12783. /* BETTER_BTS_AI_MOD END */
  12784. /************************************************************************************************/
  12785. {
  12786. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  12787. {
  12788. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD_CORPORATION, getGroup()) == 0)
  12789. {
  12790. int iPathTurns;
  12791. /************************************************************************************************/
  12792. /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
  12793. /* */
  12794. /* Unit AI */
  12795. /************************************************************************************************/
  12796. if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
  12797. /************************************************************************************************/
  12798. /* BETTER_BTS_AI_MOD END */
  12799. /************************************************************************************************/
  12800. {
  12801. // BBAI TODO: Serious need for more intelligent self spread, keep certain corps from
  12802. // enemies based on their victory pursuits (culture ...)
  12803. int iValue = (10 + pLoopCity->getPopulation() * 2);
  12804. if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
  12805. {
  12806. iValue *= 4;
  12807. }
  12808. else if (kLoopTeam.isVassal(getTeam()))
  12809. {
  12810. iValue *= 3;
  12811. }
  12812. else if (kTeam.isVassal(kLoopTeam.getID()))
  12813. {
  12814. if (iLoopPlayerCorpCount == 0)
  12815. {
  12816. iValue *= 10;
  12817. }
  12818. else
  12819. {
  12820. iValue *= 3;
  12821. iValue /= 2;
  12822. }
  12823. }
  12824. else if (pLoopCity->getTeam() == getTeam())
  12825. {
  12826. iValue *= 2;
  12827. }
  12828. if (iLoopPlayerCorpCount == 0)
  12829. {
  12830. //Generally prefer to heavily target one player
  12831. iValue /= 2;
  12832. }
  12833. bool bForceMove = false;
  12834. if (isHuman())
  12835. {
  12836. //If human, prefer to spread to the player where automated from.
  12837. if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
  12838. {
  12839. iValue *= 10;
  12840. if (pLoopCity->isRevealed(getTeam(), false))
  12841. {
  12842. bForceMove = true;
  12843. }
  12844. }
  12845. }
  12846. FAssert(iPathTurns > 0);
  12847. iValue *= 1000;
  12848. iValue /= (iPathTurns + 1);
  12849. if (iValue > iBestValue)
  12850. {
  12851. iBestValue = iValue;
  12852. pBestPlot = bForceMove ? pLoopCity->plot() : getPathEndTurnPlot();
  12853. pBestSpreadPlot = pLoopCity->plot();
  12854. }
  12855. }
  12856. }
  12857. }
  12858. }
  12859. }
  12860. }
  12861. }
  12862. }
  12863. if ((pBestPlot != NULL) && (pBestSpreadPlot != NULL))
  12864. {
  12865. if (atPlot(pBestSpreadPlot))
  12866. {
  12867. if (canSpreadCorporation(pBestSpreadPlot, eCorporation))
  12868. {
  12869. getGroup()->pushMission(MISSION_SPREAD_CORPORATION, eCorporation);
  12870. }
  12871. else
  12872. {
  12873. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_SPREAD_CORPORATION, pBestSpreadPlot);
  12874. }
  12875. return true;
  12876. }
  12877. else
  12878. {
  12879. FAssert(!atPlot(pBestPlot));
  12880. /************************************************************************************************/
  12881. /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
  12882. /* */
  12883. /* Unit AI */
  12884. /************************************************************************************************/
  12885. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_SPREAD_CORPORATION, pBestSpreadPlot);
  12886. /************************************************************************************************/
  12887. /* BETTER_BTS_AI_MOD END */
  12888. /************************************************************************************************/
  12889. return true;
  12890. }
  12891. }
  12892. return false;
  12893. }
  12894. bool CvUnitAI::AI_spreadReligionAirlift()
  12895. {
  12896. PROFILE_FUNC();
  12897. CvPlot* pBestPlot;
  12898. ReligionTypes eReligion;
  12899. int iValue;
  12900. int iBestValue;
  12901. int iI;
  12902. if (getGroup()->getNumUnits() > 1)
  12903. {
  12904. return false;
  12905. }
  12906. CvCity* pCity = plot()->getPlotCity();
  12907. if (pCity == NULL)
  12908. {
  12909. return false;
  12910. }
  12911. if (pCity->getMaxAirlift() == 0)
  12912. {
  12913. return false;
  12914. }
  12915. //bool bCultureVictory = GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_CULTURE2);
  12916. eReligion = NO_RELIGION;
  12917. if (eReligion == NO_RELIGION)
  12918. {
  12919. if (GET_PLAYER(getOwnerINLINE()).getStateReligion() != NO_RELIGION)
  12920. {
  12921. if (m_pUnitInfo->getReligionSpreads(GET_PLAYER(getOwnerINLINE()).getStateReligion()) > 0)
  12922. {
  12923. eReligion = GET_PLAYER(getOwnerINLINE()).getStateReligion();
  12924. }
  12925. }
  12926. }
  12927. if (eReligion == NO_RELIGION)
  12928. {
  12929. for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
  12930. {
  12931. //if (bCultureVictory || GET_TEAM(getTeam()).hasHolyCity((ReligionTypes)iI))
  12932. {
  12933. if (m_pUnitInfo->getReligionSpreads((ReligionTypes)iI) > 0)
  12934. {
  12935. eReligion = ((ReligionTypes)iI);
  12936. break;
  12937. }
  12938. }
  12939. }
  12940. }
  12941. if (eReligion == NO_RELIGION)
  12942. {
  12943. return false;
  12944. }
  12945. iBestValue = 0;
  12946. pBestPlot = NULL;
  12947. for (int iI = 0; iI < MAX_PLAYERS; iI++)
  12948. {
  12949. CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
  12950. if (kLoopPlayer.isAlive() && (getTeam() == kLoopPlayer.getTeam()))
  12951. {
  12952. int iLoop;
  12953. for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
  12954. {
  12955. if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
  12956. {
  12957. if (canSpread(pLoopCity->plot(), eReligion))
  12958. {
  12959. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD, getGroup()) == 0)
  12960. {
  12961. iValue = (7 + (pLoopCity->getPopulation() * 4));
  12962. int iCityReligionCount = pLoopCity->getReligionCount();
  12963. int iReligionCountFactor = iCityReligionCount;
  12964. // count cities with no religion the same as cities with 2 religions
  12965. // prefer a city with exactly 1 religion already
  12966. if (iCityReligionCount == 0)
  12967. {
  12968. iReligionCountFactor = 2;
  12969. }
  12970. else if (iCityReligionCount == 1)
  12971. {
  12972. iValue *= 2;
  12973. }
  12974. iValue /= iReligionCountFactor;
  12975. if (iValue > iBestValue)
  12976. {
  12977. iBestValue = iValue;
  12978. pBestPlot = pLoopCity->plot();
  12979. }
  12980. }
  12981. }
  12982. }
  12983. }
  12984. }
  12985. }
  12986. if (pBestPlot != NULL)
  12987. {
  12988. getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_SPREAD, pBestPlot);
  12989. return true;
  12990. }
  12991. return false;
  12992. }
  12993. bool CvUnitAI::AI_spreadCorporationAirlift()
  12994. {
  12995. PROFILE_FUNC();
  12996. if (getGroup()->getNumUnits() > 1)
  12997. {
  12998. return false;
  12999. }
  13000. CvCity* pCity = plot()->getPlotCity();
  13001. if (pCity == NULL)
  13002. {
  13003. return false;
  13004. }
  13005. if (pCity->getMaxAirlift() == 0)
  13006. {
  13007. return false;
  13008. }
  13009. CorporationTypes eCorporation = NO_CORPORATION;
  13010. for (int iI = 0; iI < GC.getNumCorporationInfos(); ++iI)
  13011. {
  13012. if (m_pUnitInfo->getCorporationSpreads((CorporationTypes)iI) > 0)
  13013. {
  13014. eCorporation = ((CorporationTypes)iI);
  13015. break;
  13016. }
  13017. }
  13018. if (NO_CORPORATION == eCorporation)
  13019. {
  13020. return false;
  13021. }
  13022. int iBestValue = 0;
  13023. CvPlot* pBestPlot = NULL;
  13024. for (int iI = 0; iI < MAX_PLAYERS; iI++)
  13025. {
  13026. CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
  13027. if (kLoopPlayer.isAlive() && (getTeam() == kLoopPlayer.getTeam()))
  13028. {
  13029. int iLoop;
  13030. for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
  13031. {
  13032. if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
  13033. {
  13034. if (canSpreadCorporation(pLoopCity->plot(), eCorporation))
  13035. {
  13036. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD_CORPORATION, getGroup()) == 0)
  13037. {
  13038. int iValue = (pLoopCity->getPopulation() * 4);
  13039. if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
  13040. {
  13041. iValue *= 4;
  13042. }
  13043. else
  13044. {
  13045. iValue *= 3;
  13046. }
  13047. if (iValue > iBestValue)
  13048. {
  13049. iBestValue = iValue;
  13050. pBestPlot = pLoopCity->plot();
  13051. }
  13052. }
  13053. }
  13054. }
  13055. }
  13056. }
  13057. }
  13058. if (pBestPlot != NULL)
  13059. {
  13060. getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_SPREAD, pBestPlot);
  13061. return true;
  13062. }
  13063. return false;
  13064. }
  13065. // Returns true if a mission was pushed...
  13066. bool CvUnitAI::AI_discover(bool bThisTurnOnly, bool bFirstResearchOnly)
  13067. {
  13068. TechTypes eDiscoverTech;
  13069. bool bIsFirstTech;
  13070. int iPercentWasted = 0;
  13071. int iBonusPoints = 0;
  13072. if (canDiscover(plot()))
  13073. {
  13074. eDiscoverTech = getDiscoveryTech();
  13075. bIsFirstTech = (GC.getGameINLINE().countKnownTechNumTeams(eDiscoverTech) == 0);
  13076. if (bFirstResearchOnly && !bIsFirstTech)
  13077. {
  13078. return false;
  13079. }
  13080. iPercentWasted = (100 - ((getDiscoverResearch(eDiscoverTech) * 100) / getDiscoverResearch(NO_TECH)));
  13081. FAssert(((iPercentWasted >= 0) && (iPercentWasted <= 100)));
  13082. if (bIsFirstTech)
  13083. {
  13084. // techs that give free techs
  13085. if (GC.getTechInfo(eDiscoverTech).getFirstFreeTechs() > 0)
  13086. {
  13087. iBonusPoints +=25;
  13088. }
  13089. // techs that give a free unit (generally a Great Person)
  13090. if (GET_PLAYER(getOwnerINLINE()).getTechFreeUnit(eDiscoverTech) != NO_UNIT)
  13091. {
  13092. iBonusPoints += 25;
  13093. }
  13094. // Religion founding techs
  13095. for (int iReligion = 0; iReligion < GC.getNumReligionInfos(); iReligion++)
  13096. {
  13097. ReligionTypes eReligion = (ReligionTypes)iReligion;
  13098. CvReligionInfo& kReligionInfo = GC.getReligionInfo(eReligion);
  13099. const TechTypes eReligionTech = (TechTypes)GC.getReligionInfo(eReligion).getTechPrereq();
  13100. if (eReligionTech == eDiscoverTech)
  13101. {
  13102. if (!GC.getGameINLINE().isReligionFounded(eReligion))
  13103. {
  13104. if (!GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_RELIGION2))
  13105. {
  13106. iBonusPoints += 25;
  13107. }
  13108. }
  13109. }
  13110. }
  13111. }
  13112. if (getDiscoverResearch(eDiscoverTech) >= GET_TEAM(getTeam()).getResearchLeft(eDiscoverTech))
  13113. {
  13114. if ((iPercentWasted < (45 + iBonusPoints)) && bFirstResearchOnly && bIsFirstTech)
  13115. {
  13116. if( gUnitLogLevel >= 2 )
  13117. {
  13118. logBBAI("Player %d Unit %d (%S's %S) discovering tech (first) %S (%d wasted)\n", getOwnerINLINE(), getID(), GET_PLAYER(getOwnerINLINE()).getName(), getName().GetCString(), GC.getTechInfo(eDiscoverTech).getDescription(), iPercentWasted);
  13119. }
  13120. getGroup()->pushMission(MISSION_DISCOVER);
  13121. return true;
  13122. }
  13123. if (iPercentWasted < ((bIsFirstTech ? 31 : 11) + iBonusPoints))
  13124. {
  13125. if( gUnitLogLevel >= 2 )
  13126. {
  13127. logBBAI("Player %d Unit %d (%S's %S) discovering tech (bonus points) %S (%d wasted)\n", getOwnerINLINE(), getID(), GET_PLAYER(getOwnerINLINE()).getName(), getName().GetCString(), GC.getTechInfo(eDiscoverTech).getDescription(), iPercentWasted);
  13128. }
  13129. getGroup()->pushMission(MISSION_DISCOVER);
  13130. return true;
  13131. }
  13132. }
  13133. else if (bThisTurnOnly)
  13134. {
  13135. return false;
  13136. }
  13137. if (iPercentWasted <= 11)
  13138. {
  13139. if (GET_PLAYER(getOwnerINLINE()).getCurrentResearch() == eDiscoverTech)
  13140. {
  13141. if( gUnitLogLevel >= 2 )
  13142. {
  13143. logBBAI("Player %d Unit %d (%S's %S) discovering tech (current research) %S (%d wasted)\n", getOwnerINLINE(), getID(), GET_PLAYER(getOwnerINLINE()).getName(), getName().GetCString(), GC.getTechInfo(eDiscoverTech).getDescription(), iPercentWasted);
  13144. }
  13145. getGroup()->pushMission(MISSION_DISCOVER);
  13146. return true;
  13147. }
  13148. }
  13149. }
  13150. return false;
  13151. }
  13152. // Returns true if a mission was pushed...
  13153. bool CvUnitAI::AI_lead(std::vector<UnitAITypes>& aeUnitAITypes)
  13154. {
  13155. PROFILE_FUNC();
  13156. FAssertMsg(!isHuman(), "isHuman did not return false as expected");
  13157. FAssertMsg(AI_getUnitAIType() != NO_UNITAI, "AI_getUnitAIType() is not expected to be equal with NO_UNITAI");
  13158. FAssert(NO_PLAYER != getOwnerINLINE());
  13159. CvPlayer& kOwner = GET_PLAYER(getOwnerINLINE());
  13160. bool bNeedLeader = false;
  13161. /************************************************************************************************/
  13162. /* BETTER_BTS_AI_MOD & RevDCM 09/03/10 jdog5000 */
  13163. /* phungus420 */
  13164. /* Great People AI, Unit AI */
  13165. /************************************************************************************************/
  13166. int iLoop;
  13167. bool bBestUnitLegend = false;
  13168. CvUnit* pLoopUnit = NULL;
  13169. CvUnit* pBestUnit = NULL;
  13170. CvPlot* pBestPlot = NULL;
  13171. // AI may use Warlords to create super-medic units
  13172. CvUnit* pBestStrUnit = NULL;
  13173. CvPlot* pBestStrPlot = NULL;
  13174. CvUnit* pBestHealUnit = NULL;
  13175. CvPlot* pBestHealPlot = NULL;
  13176. for (int iI = 0; iI < MAX_CIV_TEAMS; iI++)
  13177. {
  13178. CvTeamAI& kLoopTeam = GET_TEAM((TeamTypes)iI);
  13179. if (isEnemy((TeamTypes)iI))
  13180. {
  13181. if (kLoopTeam.countNumUnitsByArea(area()) > 0)
  13182. {
  13183. bNeedLeader = true;
  13184. break;
  13185. }
  13186. }
  13187. }
  13188. if (bNeedLeader)
  13189. {
  13190. int iBestStrength = 0;
  13191. int iBestHealing = 0;
  13192. int iCombatStrength;
  13193. bool bValid;
  13194. bool bLegend;
  13195. for (pLoopUnit = kOwner.firstUnit(&iLoop); pLoopUnit; pLoopUnit = kOwner.nextUnit(&iLoop))
  13196. {
  13197. if(pLoopUnit != NULL)
  13198. {
  13199. bValid = false;
  13200. bLegend = false;
  13201. if (GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() > 0
  13202. && GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() < 7)
  13203. {
  13204. if (canLead(pLoopUnit->plot(), pLoopUnit->getID()) > 0)
  13205. {
  13206. bValid = true;
  13207. bLegend = true;
  13208. }
  13209. }
  13210. if( !bValid )
  13211. {
  13212. for (uint iI = 0; iI < aeUnitAITypes.size(); iI++)
  13213. {
  13214. if (pLoopUnit->AI_getUnitAIType() == aeUnitAITypes[iI] || NO_UNITAI == aeUnitAITypes[iI])
  13215. {
  13216. if (canLead(pLoopUnit->plot(), pLoopUnit->getID()) > 0)
  13217. {
  13218. bValid = true;
  13219. break;
  13220. }
  13221. }
  13222. }
  13223. }
  13224. if( bValid )
  13225. {
  13226. if (AI_plotValid(pLoopUnit->plot()))
  13227. {
  13228. if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
  13229. {
  13230. if( pLoopUnit->combatLimit() == 100 )
  13231. {
  13232. if (generatePath(pLoopUnit->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true))
  13233. {
  13234. // pick the unit with the highest current strength
  13235. iCombatStrength = pLoopUnit->currCombatStr(NULL, NULL);
  13236. iCombatStrength *= 10 + (pLoopUnit->getExperience() * 2);
  13237. iCombatStrength /= 15;
  13238. if (pLoopUnit->getUnitCombatType() == NO_UNITCOMBAT)
  13239. {
  13240. iCombatStrength /= 10;
  13241. }
  13242. if(bLegend)
  13243. {
  13244. iCombatStrength *= 10 - GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances();
  13245. iCombatStrength /= 3;
  13246. }
  13247. if (iCombatStrength > iBestStrength)
  13248. {
  13249. iBestStrength = iCombatStrength;
  13250. pBestStrUnit = pLoopUnit;
  13251. pBestStrPlot = getPathEndTurnPlot();
  13252. if(bLegend)
  13253. {
  13254. bBestUnitLegend = true;
  13255. }
  13256. else
  13257. {
  13258. bBestUnitLegend = false;
  13259. }
  13260. }
  13261. // or the unit with the best healing ability
  13262. int iHealing = pLoopUnit->getSameTileHeal() + pLoopUnit->getAdjacentTileHeal();
  13263. if (iHealing > iBestHealing)
  13264. {
  13265. iBestHealing = iHealing;
  13266. pBestHealUnit = pLoopUnit;
  13267. pBestHealPlot = getPathEndTurnPlot();
  13268. }
  13269. }
  13270. }
  13271. }
  13272. }
  13273. }
  13274. }
  13275. }
  13276. }
  13277. if( AI_getBirthmark() % 3 == 0 && pBestHealUnit != NULL )
  13278. {
  13279. pBestPlot = pBestHealPlot;
  13280. pBestUnit = pBestHealUnit;
  13281. }
  13282. else
  13283. {
  13284. pBestPlot = pBestStrPlot;
  13285. pBestUnit = pBestStrUnit;
  13286. }
  13287. if (pBestPlot)
  13288. {
  13289. if (atPlot(pBestPlot) && pBestUnit)
  13290. {
  13291. if( gUnitLogLevel > 2 )
  13292. {
  13293. CvWString szString;
  13294. getUnitAIString(szString, pBestUnit->AI_getUnitAIType());
  13295. if(bBestUnitLegend)
  13296. {
  13297. logBBAI(" Great general %d for %S chooses to lead %S (%d) Legend Unit", getID(), GET_PLAYER(getOwner()).getCivilizationDescription(0), pBestUnit->getName(0).GetCString(), pBestUnit->getID());
  13298. }
  13299. else
  13300. {
  13301. logBBAI(" Great general %d for %S chooses to lead %S (%d) with UNITAI %S", getID(), GET_PLAYER(getOwner()).getCivilizationDescription(0), pBestUnit->getName(0).GetCString(), pBestUnit->getID(), szString.GetCString());
  13302. }
  13303. }
  13304. getGroup()->pushMission(MISSION_LEAD, pBestUnit->getID());
  13305. return true;
  13306. }
  13307. else
  13308. {
  13309. FAssert(!atPlot(pBestPlot));
  13310. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
  13311. return true;
  13312. }
  13313. }
  13314. /************************************************************************************************/
  13315. /* BETTER_BTS_AI_MOD END */
  13316. /************************************************************************************************/
  13317. return false;
  13318. }
  13319. // Returns true if a mission was pushed...
  13320. // iMaxCounts = 1 would mean join a city if there's no existing joined GP of that type.
  13321. bool CvUnitAI::AI_join(int iMaxCount)
  13322. {
  13323. PROFILE_FUNC();
  13324. CvCity* pLoopCity;
  13325. CvPlot* pBestPlot;
  13326. SpecialistTypes eBestSpecialist;
  13327. int iValue;
  13328. int iBestValue;
  13329. int iLoop;
  13330. int iI;
  13331. int iCount;
  13332. iBestValue = 0;
  13333. pBestPlot = NULL;
  13334. eBestSpecialist = NO_SPECIALIST;
  13335. iCount = 0;
  13336. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  13337. {
  13338. /************************************************************************************************/
  13339. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  13340. /* */
  13341. /* Unit AI, Efficiency */
  13342. /************************************************************************************************/
  13343. // BBAI efficiency: check same area
  13344. if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
  13345. {
  13346. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  13347. {
  13348. if (generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true) || (plot() == pLoopCity->plot()))
  13349. /************************************************************************************************/
  13350. /* BETTER_BTS_AI_MOD END */
  13351. /************************************************************************************************/
  13352. {
  13353. for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
  13354. {
  13355. bool bDoesJoin = false;
  13356. SpecialistTypes eSpecialist = (SpecialistTypes)iI;
  13357. if (m_pUnitInfo->getGreatPeoples(eSpecialist))
  13358. {
  13359. bDoesJoin = true;
  13360. }
  13361. if (bDoesJoin)
  13362. {
  13363. iCount += pLoopCity->getSpecialistCount(eSpecialist);
  13364. if (iCount >= iMaxCount)
  13365. {
  13366. return false;
  13367. }
  13368. }
  13369. if (canJoin(pLoopCity->plot(), ((SpecialistTypes)iI)))
  13370. {
  13371. /************************************************************************************************/
  13372. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  13373. /* */
  13374. /* Unit AI, Efficiency */
  13375. /************************************************************************************************/
  13376. //if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopCity->plot(), 2) == 0)
  13377. if ( !(GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(pLoopCity->plot(), 2)) )
  13378. /************************************************************************************************/
  13379. /* BETTER_BTS_AI_MOD END */
  13380. /************************************************************************************************/
  13381. {
  13382. iValue = pLoopCity->AI_specialistValue(((SpecialistTypes)iI), pLoopCity->AI_avoidGrowth(), false);
  13383. if (iValue > iBestValue)
  13384. {
  13385. iBestValue = iValue;
  13386. pBestPlot = getPathEndTurnPlot();
  13387. eBestSpecialist = ((SpecialistTypes)iI);
  13388. }
  13389. }
  13390. }
  13391. }
  13392. }
  13393. }
  13394. }
  13395. }
  13396. if ((pBestPlot != NULL) && (eBestSpecialist != NO_SPECIALIST))
  13397. {
  13398. if (atPlot(pBestPlot))
  13399. {
  13400. getGroup()->pushMission(MISSION_JOIN, eBestSpecialist);
  13401. logBBAI(" %S (unit %d - %S) joining city at %d, %d as %S", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription(),pBestPlot->getX(), pBestPlot->getY(), GC.getSpecialistInfo(eBestSpecialist).getDescription());
  13402. return true;
  13403. }
  13404. else
  13405. {
  13406. FAssert(!atPlot(pBestPlot));
  13407. /************************************************************************************************/
  13408. /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
  13409. /* */
  13410. /* Unit AI */
  13411. /************************************************************************************************/
  13412. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY);
  13413. /************************************************************************************************/
  13414. /* BETTER_BTS_AI_MOD END */
  13415. /************************************************************************************************/
  13416. return true;
  13417. }
  13418. }
  13419. return false;
  13420. }
  13421. // Returns true if a mission was pushed...
  13422. // iMaxCount = 1 would mean construct only if there are no existing buildings
  13423. // constructed by this GP type.
  13424. bool CvUnitAI::AI_construct(int iMaxCount, int iMaxSingleBuildingCount, int iThreshold)
  13425. {
  13426. PROFILE_FUNC();
  13427. CvCity* pLoopCity;
  13428. CvPlot* pBestPlot;
  13429. CvPlot* pBestConstructPlot;
  13430. BuildingTypes eBestBuilding;
  13431. int iValue;
  13432. int iBestValue;
  13433. int iLoop;
  13434. int iI;
  13435. int iCount;
  13436. iBestValue = 0;
  13437. pBestPlot = NULL;
  13438. pBestConstructPlot = NULL;
  13439. eBestBuilding = NO_BUILDING;
  13440. iCount = 0;
  13441. CvPlayer &kPlayer = GET_PLAYER(getOwnerINLINE());
  13442. for (pLoopCity = kPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  13443. {
  13444. if (AI_plotValid(pLoopCity->plot()) && pLoopCity->area() == area())
  13445. {
  13446. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  13447. {
  13448. if (kPlayer.AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_CONSTRUCT, getGroup()) == 0)
  13449. {
  13450. /************************************************************************************************/
  13451. /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
  13452. /* */
  13453. /* Unit AI */
  13454. /************************************************************************************************/
  13455. if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true))
  13456. /************************************************************************************************/
  13457. /* BETTER_BTS_AI_MOD END */
  13458. /************************************************************************************************/
  13459. {
  13460. for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
  13461. {
  13462. BuildingTypes eBuilding = (BuildingTypes)GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iI);
  13463. if (NO_BUILDING != eBuilding)
  13464. {
  13465. bool bDoesBuild = false;
  13466. if ((m_pUnitInfo->getForceBuildings(eBuilding))
  13467. || (m_pUnitInfo->getBuildings(eBuilding)))
  13468. {
  13469. bDoesBuild = true;
  13470. }
  13471. if (bDoesBuild && (pLoopCity->getNumBuilding(eBuilding) > 0))
  13472. {
  13473. iCount++;
  13474. if (iCount >= iMaxCount)
  13475. {
  13476. return false;
  13477. }
  13478. }
  13479. if (bDoesBuild && kPlayer.getBuildingClassCount((BuildingClassTypes)GC.getBuildingInfo(eBuilding).getBuildingClassType()) < iMaxSingleBuildingCount)
  13480. {
  13481. if (canConstruct(pLoopCity->plot(), eBuilding))
  13482. {
  13483. iValue = pLoopCity->AI_buildingValue(eBuilding);
  13484. if (plot()->isCity())
  13485. {
  13486. if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0))
  13487. {
  13488. if (baseCombatStr() > 0)
  13489. iValue = 0;
  13490. }
  13491. }
  13492. // Sephi AI (Religion Victory)
  13493. /*
  13494. if (AI_getUnitAIType()==UNITAI_PROPHET)
  13495. {
  13496. if (pLoopCity->isCapital())
  13497. {
  13498. iValue+=10000;
  13499. }
  13500. }
  13501. */
  13502. // End Sephi AI
  13503. // Tholal AI - Holy Shrines
  13504. if (GC.getBuildingInfo(eBuilding).getHolyCity() != NO_RELIGION)
  13505. {
  13506. if (kPlayer.getStateReligion() != NO_RELIGION)
  13507. {
  13508. if (GC.getBuildingInfo(eBuilding).getHolyCity() == kPlayer.getStateReligion())
  13509. {
  13510. iValue+=20001;
  13511. }
  13512. }
  13513. }
  13514. // End Tholal AI
  13515. if ((iValue > iThreshold) && (iValue > iBestValue))
  13516. {
  13517. iBestValue = iValue;
  13518. pBestPlot = getPathEndTurnPlot();
  13519. pBestConstructPlot = pLoopCity->plot();
  13520. eBestBuilding = eBuilding;
  13521. }
  13522. }
  13523. }
  13524. }
  13525. }
  13526. }
  13527. }
  13528. }
  13529. }
  13530. }
  13531. if ((pBestPlot != NULL) && (pBestConstructPlot != NULL) && (eBestBuilding != NO_BUILDING))
  13532. {
  13533. logBBAI(" %S (%d)constructing %S at %d, %d (value: %d)", getName().GetCString(), getID(), GC.getBuildingInfo(eBestBuilding).getText(), pBestPlot->getX(), pBestPlot->getY(), iBestValue);
  13534. if (atPlot(pBestConstructPlot))
  13535. {
  13536. getGroup()->pushMission(MISSION_CONSTRUCT, eBestBuilding);
  13537. return true;
  13538. }
  13539. else
  13540. {
  13541. FAssert(!atPlot(pBestPlot));
  13542. /************************************************************************************************/
  13543. /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
  13544. /* */
  13545. /* Unit AI */
  13546. /************************************************************************************************/
  13547. if (getGroup()->getNumUnits() > 1)
  13548. {
  13549. joinGroup(NULL);
  13550. }
  13551. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_CONSTRUCT, pBestConstructPlot);
  13552. /************************************************************************************************/
  13553. /* BETTER_BTS_AI_MOD END */
  13554. /************************************************************************************************/
  13555. return true;
  13556. }
  13557. }
  13558. return false;
  13559. }
  13560. // Returns true if a mission was pushed...
  13561. bool CvUnitAI::AI_switchHurry()
  13562. {
  13563. CvCity* pCity;
  13564. BuildingTypes eBestBuilding;
  13565. int iValue;
  13566. int iBestValue;
  13567. int iI;
  13568. pCity = plot()->getPlotCity();
  13569. if ((pCity == NULL) || (pCity->getOwnerINLINE() != getOwnerINLINE()))
  13570. {
  13571. return false;
  13572. }
  13573. iBestValue = 0;
  13574. eBestBuilding = NO_BUILDING;
  13575. for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
  13576. {
  13577. if (isWorldWonderClass((BuildingClassTypes)iI))
  13578. {
  13579. BuildingTypes eBuilding = (BuildingTypes)GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iI);
  13580. if (NO_BUILDING != eBuilding)
  13581. {
  13582. if (pCity->canConstruct(eBuilding))
  13583. {
  13584. if (pCity->getBuildingProduction(eBuilding) == 0)
  13585. {
  13586. if (getMaxHurryProduction(pCity) >= pCity->getProductionNeeded(eBuilding))
  13587. {
  13588. iValue = pCity->AI_buildingValue(eBuilding);
  13589. if (iValue > iBestValue)
  13590. {
  13591. iBestValue = iValue;
  13592. eBestBuilding = eBuilding;
  13593. }
  13594. }
  13595. }
  13596. }
  13597. }
  13598. }
  13599. }
  13600. if (eBestBuilding != NO_BUILDING)
  13601. {
  13602. pCity->pushOrder(ORDER_CONSTRUCT, eBestBuilding, -1, false, false, false);
  13603. if (pCity->getProductionBuilding() == eBestBuilding)
  13604. {
  13605. if (canHurry(plot()))
  13606. {
  13607. getGroup()->pushMission(MISSION_HURRY);
  13608. return true;
  13609. }
  13610. }
  13611. FAssert(false);
  13612. }
  13613. return false;
  13614. }
  13615. // Returns true if a mission was pushed...
  13616. bool CvUnitAI::AI_hurry()
  13617. {
  13618. PROFILE_FUNC();
  13619. CvCity* pLoopCity;
  13620. CvPlot* pBestPlot;
  13621. CvPlot* pBestHurryPlot;
  13622. int iPathTurns;
  13623. int iValue;
  13624. int iBestValue;
  13625. int iLoop;
  13626. iBestValue = 0;
  13627. pBestPlot = NULL;
  13628. pBestHurryPlot = NULL;
  13629. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  13630. {
  13631. /************************************************************************************************/
  13632. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  13633. /* */
  13634. /* Unit AI, Efficiency */
  13635. /************************************************************************************************/
  13636. // BBAI efficiency: check same area
  13637. if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
  13638. /************************************************************************************************/
  13639. /* BETTER_BTS_AI_MOD END */
  13640. /************************************************************************************************/
  13641. {
  13642. if (canHurry(pLoopCity->plot()))
  13643. {
  13644. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  13645. {
  13646. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_HURRY, getGroup()) == 0)
  13647. {
  13648. /************************************************************************************************/
  13649. /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
  13650. /* */
  13651. /* Unit AI */
  13652. /************************************************************************************************/
  13653. if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
  13654. /************************************************************************************************/
  13655. /* BETTER_BTS_AI_MOD END */
  13656. /************************************************************************************************/
  13657. {
  13658. if (pLoopCity->isProductionBuilding())
  13659. {
  13660. if (pLoopCity->getProductionTurnsLeft() > iPathTurns)
  13661. {
  13662. iValue = pLoopCity->getProductionNeeded();
  13663. iValue += pLoopCity->getProductionTurnsLeft() * 5;
  13664. // Tholal ToDo - value based on what building we're making
  13665. if (isWorldWonderClass((BuildingClassTypes)GC.getBuildingInfo(pLoopCity->getProductionBuilding()).getBuildingClassType()))
  13666. {
  13667. iValue *= 4;
  13668. }
  13669. else if (isNationalWonderClass((BuildingClassTypes)GC.getBuildingInfo(pLoopCity->getProductionBuilding()).getBuildingClassType()))
  13670. {
  13671. iValue *= 2;
  13672. }
  13673. iValue -= GC.getUnitInfo(getUnitType()).getBaseHurry();
  13674. iValue -= iPathTurns * 2;
  13675. if (iValue > iBestValue)
  13676. {
  13677. iBestValue = iValue;
  13678. pBestPlot = getPathEndTurnPlot();
  13679. pBestHurryPlot = pLoopCity->plot();
  13680. }
  13681. }
  13682. }
  13683. }
  13684. }
  13685. }
  13686. }
  13687. }
  13688. }
  13689. if ((pBestPlot != NULL) && (pBestHurryPlot != NULL))
  13690. {
  13691. int iProdRemaining = (pBestHurryPlot->getPlotCity()->getProductionNeeded() - pBestHurryPlot->getPlotCity()->getProduction());
  13692. if (atPlot(pBestHurryPlot))
  13693. {
  13694. getGroup()->pushMission(MISSION_HURRY);
  13695. logBBAI(" %S (%d) hurrying production of %S in %S (%d prod. left)", getName().GetCString(), getID(), GC.getBuildingInfo((BuildingTypes)pBestHurryPlot->getPlotCity()->getProductionBuilding()).getDescription(), pBestHurryPlot->getPlotCity()->getName().GetCString(), iProdRemaining);
  13696. return true;
  13697. }
  13698. else
  13699. {
  13700. FAssert(!atPlot(pBestPlot));
  13701. /************************************************************************************************/
  13702. /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
  13703. /* */
  13704. /* Unit AI */
  13705. /************************************************************************************************/
  13706. logBBAI(" %S (%d) moving to hurry production of %S in %S (%d prod. left)", getName().GetCString(), getID(), GC.getBuildingInfo((BuildingTypes)pBestHurryPlot->getPlotCity()->getProductionBuilding()).getDescription(), pBestHurryPlot->getPlotCity()->getName().GetCString(), iProdRemaining);
  13707. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_HURRY, pBestHurryPlot);
  13708. /************************************************************************************************/
  13709. /* BETTER_BTS_AI_MOD END */
  13710. /************************************************************************************************/
  13711. return true;
  13712. }
  13713. }
  13714. return false;
  13715. }
  13716. // Returns true if a mission was pushed...
  13717. bool CvUnitAI::AI_greatWork()
  13718. {
  13719. PROFILE_FUNC();
  13720. CvCity* pLoopCity;
  13721. CvPlot* pBestPlot;
  13722. CvPlot* pBestGreatWorkPlot;
  13723. int iValue;
  13724. int iBestValue;
  13725. int iLoop;
  13726. iBestValue = 0;
  13727. pBestPlot = NULL;
  13728. pBestGreatWorkPlot = NULL;
  13729. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  13730. {
  13731. /************************************************************************************************/
  13732. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  13733. /* */
  13734. /* Unit AI, Efficiency */
  13735. /************************************************************************************************/
  13736. // BBAI efficiency: check same area
  13737. if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
  13738. /************************************************************************************************/
  13739. /* BETTER_BTS_AI_MOD END */
  13740. /************************************************************************************************/
  13741. {
  13742. if (canGreatWork(pLoopCity->plot()))
  13743. {
  13744. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  13745. {
  13746. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GREAT_WORK, getGroup()) == 0)
  13747. {
  13748. /************************************************************************************************/
  13749. /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
  13750. /* */
  13751. /* Unit AI */
  13752. /************************************************************************************************/
  13753. if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true))
  13754. /************************************************************************************************/
  13755. /* BETTER_BTS_AI_MOD END */
  13756. /************************************************************************************************/
  13757. {
  13758. iValue = pLoopCity->AI_calculateCulturePressure(true);
  13759. iValue -= ((100 * pLoopCity->getCulture(pLoopCity->getOwnerINLINE())) / std::max(1, getGreatWorkCulture(pLoopCity->plot())));
  13760. if (iValue > 0)
  13761. {
  13762. if (iValue > iBestValue)
  13763. {
  13764. iBestValue = iValue;
  13765. pBestPlot = getPathEndTurnPlot();
  13766. pBestGreatWorkPlot = pLoopCity->plot();
  13767. }
  13768. }
  13769. }
  13770. }
  13771. }
  13772. }
  13773. }
  13774. }
  13775. if ((pBestPlot != NULL) && (pBestGreatWorkPlot != NULL))
  13776. {
  13777. if (atPlot(pBestGreatWorkPlot))
  13778. {
  13779. getGroup()->pushMission(MISSION_GREAT_WORK);
  13780. return true;
  13781. }
  13782. else
  13783. {
  13784. FAssert(!atPlot(pBestPlot));
  13785. /************************************************************************************************/
  13786. /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
  13787. /* */
  13788. /* Unit AI */
  13789. /************************************************************************************************/
  13790. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_GREAT_WORK, pBestGreatWorkPlot);
  13791. /************************************************************************************************/
  13792. /* BETTER_BTS_AI_MOD END */
  13793. /************************************************************************************************/
  13794. return true;
  13795. }
  13796. }
  13797. return false;
  13798. }
  13799. // Returns true if a mission was pushed...
  13800. bool CvUnitAI::AI_offensiveAirlift()
  13801. {
  13802. PROFILE_FUNC();
  13803. CvCity* pCity;
  13804. CvCity* pTargetCity;
  13805. CvCity* pLoopCity;
  13806. CvPlot* pBestPlot;
  13807. int iValue;
  13808. int iBestValue;
  13809. int iLoop;
  13810. if (getGroup()->getNumUnits() > 1)
  13811. {
  13812. return false;
  13813. }
  13814. if (area()->getTargetCity(getOwnerINLINE()) != NULL)
  13815. {
  13816. return false;
  13817. }
  13818. pCity = plot()->getPlotCity();
  13819. if (pCity == NULL)
  13820. {
  13821. return false;
  13822. }
  13823. if (pCity->getMaxAirlift() == 0)
  13824. {
  13825. return false;
  13826. }
  13827. iBestValue = 0;
  13828. pBestPlot = NULL;
  13829. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  13830. {
  13831. if (pLoopCity->area() != pCity->area())
  13832. {
  13833. if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
  13834. {
  13835. pTargetCity = pLoopCity->area()->getTargetCity(getOwnerINLINE());
  13836. if (pTargetCity != NULL)
  13837. {
  13838. /* AreaAITypes eAreaAIType = pTargetCity->area()->getAreaAIType(getTeam());
  13839. if (((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING))
  13840. || pTargetCity->AI_isDanger()) */
  13841. if (GET_PLAYER(getOwnerINLINE()).AI_isLandWar(pTargetCity->area()) || pTargetCity->AI_isDanger()) // K-Mod
  13842. {
  13843. iValue = 10000;
  13844. iValue *= (GET_PLAYER(getOwnerINLINE()).AI_militaryWeight(pLoopCity->area()) + 10);
  13845. iValue /= (GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), AI_getUnitAIType()) + 10);
  13846. iValue += std::max(1, ((GC.getMapINLINE().maxStepDistance() * 2) - GC.getMapINLINE().calculatePathDistance(pLoopCity->plot(), pTargetCity->plot())));
  13847. if (AI_getUnitAIType() == UNITAI_PARADROP)
  13848. {
  13849. CvCity* pNearestEnemyCity = GC.getMapINLINE().findCity(pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), NO_PLAYER, NO_TEAM, false, false, getTeam());
  13850. if (pNearestEnemyCity != NULL)
  13851. {
  13852. int iDistance = plotDistance(pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), pNearestEnemyCity->getX_INLINE(), pNearestEnemyCity->getY_INLINE());
  13853. if (iDistance <= getDropRange())
  13854. {
  13855. iValue *= 5;
  13856. }
  13857. }
  13858. }
  13859. if (iValue > iBestValue)
  13860. {
  13861. iBestValue = iValue;
  13862. pBestPlot = pLoopCity->plot();
  13863. FAssert(pLoopCity != pCity);
  13864. }
  13865. }
  13866. }
  13867. }
  13868. }
  13869. }
  13870. if (pBestPlot != NULL)
  13871. {
  13872. getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  13873. return true;
  13874. }
  13875. return false;
  13876. }
  13877. // Returns true if a mission was pushed...
  13878. bool CvUnitAI::AI_paradrop(int iRange)
  13879. {
  13880. PROFILE_FUNC();
  13881. if (getGroup()->getNumUnits() > 1)
  13882. {
  13883. return false;
  13884. }
  13885. int iParatrooperCount = plot()->plotCount(PUF_isUnitAIType, UNITAI_PARADROP, -1, getOwnerINLINE());
  13886. FAssert(iParatrooperCount > 0);
  13887. CvPlot* pPlot = plot();
  13888. if (!canParadrop(pPlot))
  13889. {
  13890. return false;
  13891. }
  13892. int iBestValue = 0;
  13893. CvPlot* pBestPlot = NULL;
  13894. int iSearchRange = AI_searchRange(iRange);
  13895. for (int iDX = -iSearchRange; iDX <= iSearchRange; ++iDX)
  13896. {
  13897. for (int iDY = -iSearchRange; iDY <= iSearchRange; ++iDY)
  13898. {
  13899. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  13900. if (pLoopPlot != NULL)
  13901. {
  13902. if (isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
  13903. {
  13904. if (canParadropAt(pPlot, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
  13905. {
  13906. int iValue = 0;
  13907. PlayerTypes eTargetPlayer = pLoopPlot->getOwnerINLINE();
  13908. FAssert(NO_PLAYER != eTargetPlayer);
  13909. /************************************************************************************************/
  13910. /* UNOFFICIAL_PATCH 08/01/08 jdog5000 */
  13911. /* */
  13912. /* Bugfix */
  13913. /************************************************************************************************/
  13914. /* original BTS code
  13915. if (NO_BONUS != pLoopPlot->getBonusType())
  13916. {
  13917. iValue += GET_PLAYER(eTargetPlayer).AI_bonusVal(pLoopPlot->getBonusType()) - 10;
  13918. }
  13919. */
  13920. // Bonus values for bonuses the AI has are less than 10 for non-strategic resources... since this is
  13921. // in the AI territory they probably have it
  13922. if (NO_BONUS != pLoopPlot->getNonObsoleteBonusType(getTeam()))
  13923. {
  13924. iValue += std::max(1,GET_PLAYER(eTargetPlayer).AI_bonusVal(pLoopPlot->getBonusType()) - 10);
  13925. }
  13926. /************************************************************************************************/
  13927. /* UNOFFICIAL_PATCH END */
  13928. /************************************************************************************************/
  13929. for (int i = -1; i <= 1; ++i)
  13930. {
  13931. for (int j = -1; j <= 1; ++j)
  13932. {
  13933. CvPlot* pAdjacentPlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), i, j);
  13934. if (NULL != pAdjacentPlot)
  13935. {
  13936. CvCity* pAdjacentCity = pAdjacentPlot->getPlotCity();
  13937. if (NULL != pAdjacentCity)
  13938. {
  13939. if (pAdjacentCity->getOwnerINLINE() == eTargetPlayer)
  13940. {
  13941. int iAttackerCount = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pAdjacentPlot, true);
  13942. int iDefenderCount = pAdjacentPlot->getNumVisibleEnemyDefenders(this);
  13943. iValue += 20 * (AI_attackOdds(pAdjacentPlot, true) - ((50 * iDefenderCount) / (iParatrooperCount + iAttackerCount)));
  13944. }
  13945. }
  13946. }
  13947. }
  13948. }
  13949. if (iValue > 0)
  13950. {
  13951. iValue += pLoopPlot->defenseModifier(getTeam(), ignoreBuildingDefense());
  13952. CvUnit* pInterceptor = bestInterceptor(pLoopPlot);
  13953. if (NULL != pInterceptor)
  13954. {
  13955. int iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
  13956. iInterceptProb *= std::max(0, (100 - evasionProbability()));
  13957. iInterceptProb /= 100;
  13958. iValue *= std::max(0, 100 - iInterceptProb / 2);
  13959. iValue /= 100;
  13960. }
  13961. }
  13962. if (iValue > iBestValue)
  13963. {
  13964. iBestValue = iValue;
  13965. pBestPlot = pLoopPlot;
  13966. FAssert(pBestPlot != pPlot);
  13967. }
  13968. }
  13969. }
  13970. }
  13971. }
  13972. }
  13973. if (pBestPlot != NULL)
  13974. {
  13975. getGroup()->pushMission(MISSION_PARADROP, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  13976. return true;
  13977. }
  13978. return false;
  13979. }
  13980. /************************************************************************************************/
  13981. /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
  13982. /* */
  13983. /* Unit AI, Efficiency */
  13984. /************************************************************************************************/
  13985. // Returns true if a mission was pushed...
  13986. bool CvUnitAI::AI_protect(int iOddsThreshold, int iMaxPathTurns)
  13987. {
  13988. PROFILE_FUNC();
  13989. CvPlot* pLoopPlot;
  13990. CvPlot* pBestPlot;
  13991. int iValue;
  13992. int iBestValue;
  13993. int iI;
  13994. iBestValue = 0;
  13995. pBestPlot = NULL;
  13996. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  13997. {
  13998. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  13999. if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
  14000. {
  14001. if (AI_plotValid(pLoopPlot))
  14002. {
  14003. if (pLoopPlot->isVisibleEnemyUnit(this))
  14004. {
  14005. if (!atPlot(pLoopPlot))
  14006. {
  14007. // BBAI efficiency: Check area for land units
  14008. if( (getDomainType() != DOMAIN_LAND) || (pLoopPlot->area() == area()) || getGroup()->canMoveAllTerrain() )
  14009. {
  14010. // BBAI efficiency: Most of the time, path will exist and odds will be checked anyway. When path doesn't exist, checking path
  14011. // takes longer. Therefore, check odds first.
  14012. iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
  14013. if ((iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold)) && (iValue*50 > iBestValue))
  14014. {
  14015. int iPathTurns;
  14016. if( generatePath(pLoopPlot, 0, true, &iPathTurns) )
  14017. {
  14018. // BBAI TODO: Other units targeting this already (if path turns > 1 or 0)?
  14019. if( iPathTurns <= iMaxPathTurns )
  14020. {
  14021. iValue *= 100;
  14022. iValue /= (2 + iPathTurns);
  14023. if (iValue > iBestValue)
  14024. {
  14025. iBestValue = iValue;
  14026. pBestPlot = getPathEndTurnPlot();
  14027. FAssert(!atPlot(pBestPlot));
  14028. }
  14029. }
  14030. }
  14031. }
  14032. }
  14033. }
  14034. }
  14035. }
  14036. }
  14037. }
  14038. if (pBestPlot != NULL)
  14039. {
  14040. FAssert(!atPlot(pBestPlot));
  14041. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  14042. return true;
  14043. }
  14044. return false;
  14045. }
  14046. /************************************************************************************************/
  14047. /* BETTER_BTS_AI_MOD END */
  14048. /************************************************************************************************/
  14049. // Returns true if a mission was pushed...
  14050. bool CvUnitAI::AI_patrol()
  14051. {
  14052. PROFILE_FUNC();
  14053. CvPlot* pAdjacentPlot;
  14054. CvPlot* pBestPlot;
  14055. int iValue;
  14056. int iBestValue;
  14057. int iI;
  14058. iBestValue = 0;
  14059. pBestPlot = NULL;
  14060. for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  14061. {
  14062. pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
  14063. if (pAdjacentPlot != NULL)
  14064. {
  14065. if (AI_plotValid(pAdjacentPlot))
  14066. {
  14067. if (!(pAdjacentPlot->isVisibleEnemyUnit(this)))
  14068. {
  14069. if (generatePath(pAdjacentPlot, 0, true))
  14070. {
  14071. iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Patrol"));
  14072. if (isBarbarian())
  14073. {
  14074. if (isAnimal() || AI_getUnitAIType() == UNITAI_ANIMAL) // keep animals out of owned territory
  14075. {
  14076. if (!(pAdjacentPlot->isOwned()))
  14077. {
  14078. iValue += 20000;
  14079. }
  14080. if (!(pAdjacentPlot->isAdjacentOwned()))
  14081. {
  14082. iValue += 10000;
  14083. }
  14084. }
  14085. }
  14086. else
  14087. {
  14088. if (pAdjacentPlot->isRevealedGoody(getTeam()))
  14089. {
  14090. iValue += 100000;
  14091. }
  14092. if (pAdjacentPlot->getOwnerINLINE() == getOwnerINLINE())
  14093. {
  14094. iValue += 10000;
  14095. }
  14096. }
  14097. if (iValue > iBestValue)
  14098. {
  14099. iBestValue = iValue;
  14100. //pBestPlot = getPathEndTurnPlot();
  14101. pBestPlot = pAdjacentPlot;
  14102. FAssert(!atPlot(pBestPlot));
  14103. }
  14104. }
  14105. }
  14106. }
  14107. }
  14108. }
  14109. if (pBestPlot != NULL)
  14110. {
  14111. FAssert(!atPlot(pBestPlot));
  14112. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  14113. return true;
  14114. }
  14115. return false;
  14116. }
  14117. // Returns true if a mission was pushed...
  14118. bool CvUnitAI::AI_defend()
  14119. {
  14120. PROFILE_FUNC();
  14121. CvPlot* pLoopPlot;
  14122. CvPlot* pBestPlot;
  14123. int iSearchRange;
  14124. int iPathTurns;
  14125. int iValue;
  14126. int iBestValue;
  14127. int iDX, iDY;
  14128. if (AI_defendPlot(plot()))
  14129. {
  14130. getGroup()->pushMission(MISSION_SKIP);
  14131. return true;
  14132. }
  14133. iSearchRange = AI_searchRange(1);
  14134. iBestValue = 0;
  14135. pBestPlot = NULL;
  14136. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  14137. {
  14138. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  14139. {
  14140. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  14141. if (pLoopPlot != NULL)
  14142. {
  14143. if (AI_plotValid(pLoopPlot))
  14144. {
  14145. if (AI_defendPlot(pLoopPlot))
  14146. {
  14147. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  14148. {
  14149. if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, 0, true, &iPathTurns))
  14150. {
  14151. if (iPathTurns <= 1)
  14152. {
  14153. iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Defend"));
  14154. if (iValue > iBestValue)
  14155. {
  14156. iBestValue = iValue;
  14157. pBestPlot = pLoopPlot;
  14158. }
  14159. }
  14160. }
  14161. }
  14162. }
  14163. }
  14164. }
  14165. }
  14166. }
  14167. if (pBestPlot != NULL)
  14168. {
  14169. /************************************************************************************************/
  14170. /* BETTER_BTS_AI_MOD 12/06/08 jdog5000 */
  14171. /* */
  14172. /* Unit AI */
  14173. /************************************************************************************************/
  14174. if( !(pBestPlot->isCity()) && (getGroup()->getNumUnits() > 1) )
  14175. {
  14176. //getGroup()->AI_makeForceSeparate();
  14177. joinGroup(0); // K-Mod. (AI_makeForceSeparate is a complete waste of time here.)
  14178. }
  14179. /************************************************************************************************/
  14180. /* BETTER_BTS_AI_MOD END */
  14181. /************************************************************************************************/
  14182. FAssert(!atPlot(pBestPlot));
  14183. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  14184. return true;
  14185. }
  14186. return false;
  14187. }
  14188. // Returns true if a mission was pushed...
  14189. bool CvUnitAI::AI_safety()
  14190. {
  14191. PROFILE_FUNC();
  14192. CLLNode<IDInfo>* pUnitNode;
  14193. CvUnit* pLoopUnit;
  14194. CvUnit* pHeadUnit;
  14195. CvPlot* pLoopPlot;
  14196. CvPlot* pBestPlot;
  14197. int iSearchRange;
  14198. int iPathTurns;
  14199. int iValue;
  14200. int iBestValue;
  14201. int iCount;
  14202. int iPass;
  14203. int iDX, iDY;
  14204. iSearchRange = AI_searchRange(1);
  14205. iBestValue = 0;
  14206. pBestPlot = NULL;
  14207. for (iPass = 0; iPass < 2; iPass++)
  14208. {
  14209. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  14210. {
  14211. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  14212. {
  14213. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  14214. if (pLoopPlot != NULL)
  14215. {
  14216. if (AI_plotValid(pLoopPlot))
  14217. {
  14218. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  14219. {
  14220. if (generatePath(pLoopPlot, ((iPass > 0) ? MOVE_IGNORE_DANGER : 0), true, &iPathTurns))
  14221. {
  14222. if (iPathTurns <= 1)
  14223. {
  14224. iCount = 0;
  14225. pUnitNode = pLoopPlot->headUnitNode();
  14226. while (pUnitNode != NULL)
  14227. {
  14228. pLoopUnit = ::getUnit(pUnitNode->m_data);
  14229. pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
  14230. if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
  14231. {
  14232. if (pLoopUnit->canDefend())
  14233. {
  14234. pHeadUnit = pLoopUnit->getGroup()->getHeadUnit();
  14235. FAssert(pHeadUnit != NULL);
  14236. FAssert(getGroup()->getHeadUnit() == this);
  14237. if (pHeadUnit != this)
  14238. {
  14239. if (pHeadUnit->isWaiting() || !(pHeadUnit->canMove()))
  14240. {
  14241. FAssert(pLoopUnit != this);
  14242. FAssert(pHeadUnit != getGroup()->getHeadUnit());
  14243. iCount++;
  14244. }
  14245. }
  14246. }
  14247. }
  14248. }
  14249. iValue = (iCount * 100);
  14250. iValue += pLoopPlot->defenseModifier(getTeam(), false);
  14251. if (atPlot(pLoopPlot))
  14252. {
  14253. iValue += 50;
  14254. }
  14255. else
  14256. {
  14257. iValue += GC.getGameINLINE().getSorenRandNum(50, "AI Safety");
  14258. }
  14259. if (iValue > iBestValue)
  14260. {
  14261. iBestValue = iValue;
  14262. pBestPlot = pLoopPlot;
  14263. }
  14264. }
  14265. }
  14266. }
  14267. }
  14268. }
  14269. }
  14270. }
  14271. }
  14272. if (pBestPlot != NULL)
  14273. {
  14274. if (atPlot(pBestPlot))
  14275. {
  14276. getGroup()->pushMission(MISSION_SKIP);
  14277. return true;
  14278. }
  14279. else
  14280. {
  14281. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((iPass > 0) ? MOVE_IGNORE_DANGER : 0));
  14282. return true;
  14283. }
  14284. }
  14285. return false;
  14286. }
  14287. // Returns true if a mission was pushed...
  14288. bool CvUnitAI::AI_hide()
  14289. {
  14290. PROFILE_FUNC();
  14291. CLLNode<IDInfo>* pUnitNode;
  14292. CvUnit* pLoopUnit;
  14293. CvUnit* pHeadUnit;
  14294. CvPlot* pLoopPlot;
  14295. CvPlot* pBestPlot;
  14296. bool bValid;
  14297. int iSearchRange;
  14298. int iPathTurns;
  14299. int iValue;
  14300. int iBestValue;
  14301. int iCount;
  14302. int iDX, iDY;
  14303. int iI;
  14304. if (getInvisibleType() == NO_INVISIBLE)
  14305. {
  14306. return false;
  14307. }
  14308. iSearchRange = AI_searchRange(1);
  14309. iBestValue = 0;
  14310. pBestPlot = NULL;
  14311. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  14312. {
  14313. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  14314. {
  14315. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  14316. if (pLoopPlot != NULL)
  14317. {
  14318. if (AI_plotValid(pLoopPlot))
  14319. {
  14320. bValid = true;
  14321. for (iI = 0; iI < MAX_TEAMS; iI++)
  14322. {
  14323. if (GET_TEAM((TeamTypes)iI).isAlive())
  14324. {
  14325. if (pLoopPlot->isInvisibleVisible(((TeamTypes)iI), getInvisibleType()))
  14326. {
  14327. bValid = false;
  14328. break;
  14329. }
  14330. }
  14331. }
  14332. if (bValid)
  14333. {
  14334. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  14335. {
  14336. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  14337. {
  14338. if (iPathTurns <= 1)
  14339. {
  14340. iCount = 1;
  14341. pUnitNode = pLoopPlot->headUnitNode();
  14342. while (pUnitNode != NULL)
  14343. {
  14344. pLoopUnit = ::getUnit(pUnitNode->m_data);
  14345. pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
  14346. if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
  14347. {
  14348. if (pLoopUnit->canDefend())
  14349. {
  14350. pHeadUnit = pLoopUnit->getGroup()->getHeadUnit();
  14351. FAssert(pHeadUnit != NULL);
  14352. FAssert(getGroup()->getHeadUnit() == this);
  14353. if (pHeadUnit != this)
  14354. {
  14355. if (pHeadUnit->isWaiting() || !(pHeadUnit->canMove()))
  14356. {
  14357. FAssert(pLoopUnit != this);
  14358. FAssert(pHeadUnit != getGroup()->getHeadUnit());
  14359. iCount++;
  14360. }
  14361. }
  14362. }
  14363. }
  14364. }
  14365. iValue = (iCount * 100);
  14366. iValue += pLoopPlot->defenseModifier(getTeam(), false);
  14367. if (atPlot(pLoopPlot))
  14368. {
  14369. iValue += 50;
  14370. }
  14371. else
  14372. {
  14373. iValue += GC.getGameINLINE().getSorenRandNum(50, "AI Hide");
  14374. }
  14375. if (iValue > iBestValue)
  14376. {
  14377. iBestValue = iValue;
  14378. pBestPlot = pLoopPlot;
  14379. }
  14380. }
  14381. }
  14382. }
  14383. }
  14384. }
  14385. }
  14386. }
  14387. }
  14388. if (pBestPlot != NULL)
  14389. {
  14390. if (atPlot(pBestPlot))
  14391. {
  14392. getGroup()->pushMission(MISSION_SKIP);
  14393. return true;
  14394. }
  14395. else
  14396. {
  14397. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  14398. return true;
  14399. }
  14400. }
  14401. return false;
  14402. }
  14403. // Returns true if a mission was pushed...
  14404. bool CvUnitAI::AI_goody(int iRange)
  14405. {
  14406. PROFILE_FUNC();
  14407. CvPlot* pLoopPlot;
  14408. // CvPlot* pAdjacentPlot;
  14409. CvPlot* pBestPlot;
  14410. int iSearchRange;
  14411. int iPathTurns;
  14412. int iValue;
  14413. int iBestValue;
  14414. int iDX, iDY;
  14415. // int iI;
  14416. if (isBarbarian())
  14417. {
  14418. return false;
  14419. }
  14420. iSearchRange = AI_searchRange(iRange);
  14421. iBestValue = 0;
  14422. pBestPlot = NULL;
  14423. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  14424. {
  14425. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  14426. {
  14427. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  14428. if (pLoopPlot != NULL)
  14429. {
  14430. if (AI_plotValid(pLoopPlot))
  14431. {
  14432. if (pLoopPlot->isRevealedGoody(getTeam()))
  14433. {
  14434. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  14435. {
  14436. if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, 0, true, &iPathTurns))
  14437. {
  14438. if (iPathTurns <= iRange)
  14439. {
  14440. iValue = (10 + GC.getGameINLINE().getSorenRandNum(10000, "AI Goody"));
  14441. iValue /= (iPathTurns + 1);
  14442. if (iValue > iBestValue)
  14443. {
  14444. iBestValue = iValue;
  14445. //pBestPlot = getPathEndTurnPlot();
  14446. pBestPlot = pLoopPlot;
  14447. }
  14448. }
  14449. }
  14450. }
  14451. }
  14452. }
  14453. }
  14454. }
  14455. }
  14456. if (pBestPlot != NULL)
  14457. {
  14458. FAssert(!atPlot(pBestPlot));
  14459. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  14460. return true;
  14461. }
  14462. return false;
  14463. }
  14464. // Returns true if a mission was pushed...
  14465. bool CvUnitAI::AI_explore()
  14466. {
  14467. PROFILE_FUNC();
  14468. CvPlot* pLoopPlot;
  14469. CvPlot* pAdjacentPlot;
  14470. CvPlot* pBestPlot;
  14471. CvPlot* pBestExplorePlot;
  14472. int iPathTurns;
  14473. int iValue;
  14474. int iBestValue;
  14475. int iI, iJ;
  14476. iBestValue = 0;
  14477. pBestPlot = NULL;
  14478. pBestExplorePlot = NULL;
  14479. bool bNoContact = (GC.getGameINLINE().countCivTeamsAlive() > GET_TEAM(getTeam()).getHasMetCivCount(true));
  14480. if (getDomainType() == DOMAIN_AIR)
  14481. {
  14482. if (canRecon(plot()))
  14483. {
  14484. if (AI_exploreAir())
  14485. {
  14486. return true;
  14487. }
  14488. else
  14489. {
  14490. getGroup()->pushMission(MISSION_SKIP);
  14491. return true;
  14492. }
  14493. }
  14494. }
  14495. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  14496. {
  14497. PROFILE("AI_explore 1");
  14498. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  14499. if (AI_plotValid(pLoopPlot))
  14500. {
  14501. iValue = 0;
  14502. if (pLoopPlot->isRevealedGoody(getTeam()))
  14503. {
  14504. iValue += 100000;
  14505. }
  14506. if (iValue > 0 || GC.getGameINLINE().getSorenRandNum(4, "AI make explore faster ;)") == 0)
  14507. {
  14508. if (!(pLoopPlot->isRevealed(getTeam(), false)))
  14509. {
  14510. iValue += 10000;
  14511. }
  14512. // XXX is this too slow?
  14513. for (iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
  14514. {
  14515. PROFILE("AI_explore 2");
  14516. pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iJ));
  14517. if (pAdjacentPlot != NULL)
  14518. {
  14519. if (!(pAdjacentPlot->isRevealed(getTeam(), false)))
  14520. {
  14521. iValue += 1000;
  14522. }
  14523. else if (bNoContact)
  14524. {
  14525. if (pAdjacentPlot->getRevealedTeam(getTeam(), false) != pAdjacentPlot->getTeam())
  14526. {
  14527. iValue += 100;
  14528. }
  14529. }
  14530. }
  14531. }
  14532. if (iValue > 0)
  14533. {
  14534. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  14535. {
  14536. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_EXPLORE, getGroup(), 3) == 0)
  14537. {
  14538. if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
  14539. {
  14540. iValue += GC.getGameINLINE().getSorenRandNum(250 * abs(xDistance(getX_INLINE(), pLoopPlot->getX_INLINE())) + abs(yDistance(getY_INLINE(), pLoopPlot->getY_INLINE())), "AI explore");
  14541. if (pLoopPlot->isAdjacentToLand())
  14542. {
  14543. iValue += 10000;
  14544. }
  14545. if (pLoopPlot->isOwned())
  14546. {
  14547. iValue += 5000;
  14548. }
  14549. iValue /= 3 + std::max(1, iPathTurns);
  14550. if (iValue > iBestValue)
  14551. {
  14552. iBestValue = iValue;
  14553. pBestPlot = pLoopPlot->isRevealedGoody(getTeam()) ? getPathEndTurnPlot() : pLoopPlot;
  14554. pBestExplorePlot = pLoopPlot;
  14555. }
  14556. }
  14557. }
  14558. }
  14559. }
  14560. }
  14561. }
  14562. }
  14563. if ((pBestPlot != NULL) && (pBestExplorePlot != NULL))
  14564. {
  14565. FAssert(!atPlot(pBestPlot));
  14566. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_EXPLORE, pBestExplorePlot);
  14567. return true;
  14568. }
  14569. return false;
  14570. }
  14571. // Returns true if a mission was pushed...
  14572. bool CvUnitAI::AI_exploreRange(int iRange)
  14573. {
  14574. PROFILE_FUNC();
  14575. CvPlot* pLoopPlot;
  14576. CvPlot* pAdjacentPlot;
  14577. CvPlot* pBestPlot;
  14578. CvPlot* pBestExplorePlot;
  14579. int iSearchRange;
  14580. int iPathTurns;
  14581. int iValue;
  14582. int iBestValue;
  14583. int iDX, iDY;
  14584. int iI;
  14585. iSearchRange = AI_searchRange(iRange);
  14586. iBestValue = 0;
  14587. pBestPlot = NULL;
  14588. pBestExplorePlot = NULL;
  14589. int iImpassableCount = GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(getUnitType());
  14590. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  14591. {
  14592. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  14593. {
  14594. PROFILE("AI_exploreRange 1");
  14595. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  14596. if (pLoopPlot != NULL)
  14597. {
  14598. if (AI_plotValid(pLoopPlot))
  14599. {
  14600. iValue = 0;
  14601. if (pLoopPlot->isRevealedGoody(getTeam()))
  14602. {
  14603. iValue += 100000;
  14604. }
  14605. if (!(pLoopPlot->isRevealed(getTeam(), false)))
  14606. {
  14607. iValue += 10000;
  14608. }
  14609. for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  14610. {
  14611. PROFILE("AI_exploreRange 2");
  14612. pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));
  14613. if (pAdjacentPlot != NULL)
  14614. {
  14615. if (!(pAdjacentPlot->isRevealed(getTeam(), false)))
  14616. {
  14617. iValue += 1000;
  14618. }
  14619. }
  14620. }
  14621. if (iValue > 0)
  14622. {
  14623. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  14624. {
  14625. PROFILE("AI_exploreRange 3");
  14626. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_EXPLORE, getGroup(), 3) == 0)
  14627. {
  14628. PROFILE("AI_exploreRange 4");
  14629. if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
  14630. {
  14631. if (iPathTurns <= iRange)
  14632. {
  14633. iValue += GC.getGameINLINE().getSorenRandNum(10000, "AI Explore");
  14634. if (pLoopPlot->isAdjacentToLand())
  14635. {
  14636. iValue += 10000;
  14637. }
  14638. if (pLoopPlot->isOwned())
  14639. {
  14640. iValue += 5000;
  14641. }
  14642. if (!isHuman())
  14643. {
  14644. int iDirectionModifier = 100;
  14645. if (AI_getUnitAIType() == UNITAI_EXPLORE_SEA && iImpassableCount == 0)
  14646. {
  14647. iDirectionModifier += (50 * (abs(iDX) + abs(iDY))) / iSearchRange;
  14648. if (GC.getGame().circumnavigationAvailable())
  14649. {
  14650. if (GC.getMap().isWrapX())
  14651. {
  14652. if ((iDX * ((AI_getBirthmark() % 2 == 0) ? 1 : -1)) > 0)
  14653. {
  14654. iDirectionModifier *= 150 + ((iDX * 100) / iSearchRange);
  14655. }
  14656. else
  14657. {
  14658. iDirectionModifier /= 2;
  14659. }
  14660. }
  14661. if (GC.getMap().isWrapY())
  14662. {
  14663. if ((iDY * (((AI_getBirthmark() >> 1) % 2 == 0) ? 1 : -1)) > 0)
  14664. {
  14665. iDirectionModifier *= 150 + ((iDY * 100) / iSearchRange);
  14666. }
  14667. else
  14668. {
  14669. iDirectionModifier /= 2;
  14670. }
  14671. }
  14672. }
  14673. iValue *= iDirectionModifier;
  14674. iValue /= 100;
  14675. }
  14676. }
  14677. if (iValue > iBestValue)
  14678. {
  14679. iBestValue = iValue;
  14680. if (getDomainType() == DOMAIN_LAND)
  14681. {
  14682. pBestPlot = getPathEndTurnPlot();
  14683. }
  14684. else
  14685. {
  14686. pBestPlot = pLoopPlot;
  14687. }
  14688. pBestExplorePlot = pLoopPlot;
  14689. }
  14690. }
  14691. }
  14692. }
  14693. }
  14694. }
  14695. }
  14696. }
  14697. }
  14698. }
  14699. if ((pBestPlot != NULL) && (pBestExplorePlot != NULL))
  14700. {
  14701. PROFILE("AI_exploreRange 5");
  14702. FAssert(!atPlot(pBestPlot));
  14703. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_EXPLORE, pBestExplorePlot);
  14704. return true;
  14705. }
  14706. return false;
  14707. }
  14708. /************************************************************************************************/
  14709. /* BETTER_BTS_AI_MOD 03/29/10 jdog5000 */
  14710. /* */
  14711. /* War tactics AI, Efficiency */
  14712. /************************************************************************************************/
  14713. // Returns target city
  14714. CvCity* CvUnitAI::AI_pickTargetCity(int iFlags, int iMaxPathTurns, bool bHuntBarbs )
  14715. {
  14716. PROFILE_FUNC();
  14717. CvCity* pTargetCity;
  14718. CvCity* pLoopCity;
  14719. CvCity* pBestCity;
  14720. int iPathTurns;
  14721. int iValue;
  14722. int iBestValue;
  14723. int iLoop;
  14724. int iI;
  14725. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  14726. iBestValue = 0;
  14727. pBestCity = NULL;
  14728. if( gUnitLogLevel > 3 )
  14729. {
  14730. logBBAI(" Starting Pick Target City:");
  14731. }
  14732. pTargetCity = area()->getTargetCity(getOwnerINLINE());
  14733. // Don't always go after area target ... don't know how far away it is
  14734. /*
  14735. if (pTargetCity != NULL)
  14736. {
  14737. if (AI_potentialEnemy(pTargetCity->getTeam(), pTargetCity->plot()))
  14738. {
  14739. if (!atPlot(pTargetCity->plot()) && generatePath(pTargetCity->plot(), iFlags, true))
  14740. {
  14741. pBestCity = pTargetCity;
  14742. }
  14743. }
  14744. }
  14745. */
  14746. if (pBestCity == NULL)
  14747. {
  14748. //for (iI = 0; iI < (bHuntBarbs ? MAX_PLAYERS : MAX_CIV_PLAYERS); iI++)
  14749. for (iI = 0; iI < MAX_PLAYERS; iI++)
  14750. {
  14751. if (GET_PLAYER((PlayerTypes)iI).isAlive() && ::isPotentialEnemy(getTeam(), GET_PLAYER((PlayerTypes)iI).getTeam()))
  14752. {
  14753. for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
  14754. {
  14755. // BBAI efficiency: check area for land units before generating path
  14756. //if (pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam()))
  14757. if (kOwner.AI_deduceCitySite(pLoopCity))
  14758. {
  14759. if (AI_plotValid(pLoopCity->plot()) && (pLoopCity->area() == area()) || (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL")))
  14760. {
  14761. if (AI_potentialEnemy(GET_PLAYER((PlayerTypes)iI).getTeam(), pLoopCity->plot()))
  14762. {
  14763. if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), iFlags, true, &iPathTurns))
  14764. {
  14765. if( iPathTurns <= iMaxPathTurns )
  14766. {
  14767. // If city is visible and our force already in position is dominantly powerful or we have a huge force
  14768. // already on the way, pick a different target
  14769. if( iPathTurns > 2 && pLoopCity->isVisible(getTeam(), false) )
  14770. {
  14771. /*
  14772. int iOurOffense = GET_TEAM(getTeam()).AI_getOurPlotStrength(pLoopCity->plot(),2,false,false,true);
  14773. int iEnemyDefense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pLoopCity->plot(),1,true,false);
  14774. if( 100*iOurOffense >= GC.getBBAI_SKIP_BOMBARD_BASE_STACK_RATIO()*iEnemyDefense )
  14775. {
  14776. continue;
  14777. }
  14778. */
  14779. if( kOwner.AI_cityTargetUnitsByPath(pLoopCity, getGroup(), iPathTurns) > std::max( 6, 3 * pLoopCity->plot()->getNumVisibleEnemyDefenders(this) ) )
  14780. {
  14781. continue;
  14782. }
  14783. }
  14784. iValue = 0;
  14785. if (AI_getUnitAIType() == (UNITAI_ATTACK_CITY | UNITAI_ASSAULT_SEA)) //lemming?
  14786. {
  14787. iValue = kOwner.AI_targetCityValue(pLoopCity, false, false);
  14788. }
  14789. else
  14790. {
  14791. iValue = kOwner.AI_targetCityValue(pLoopCity, true, true);
  14792. }
  14793. if (isBarbarian())
  14794. {
  14795. iValue += GC.getGameINLINE().getSorenRandNum(100, "AI Barbarian Modifier");
  14796. }
  14797. if( gUnitLogLevel > 3 )
  14798. {
  14799. logBBAI(" ...valuing city %S (initial value: %d)", pLoopCity->getName().GetCString(), iValue);
  14800. }
  14801. if( pLoopCity == pTargetCity)
  14802. {
  14803. iValue *= 2;
  14804. }
  14805. if ((area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE))
  14806. {
  14807. iValue *= 50 + pLoopCity->calculateCulturePercent(getOwnerINLINE());
  14808. iValue /= 50;
  14809. }
  14810. iValue *= 1000;
  14811. // If city is minor civ, less interesting
  14812. if( GET_PLAYER(pLoopCity->getOwnerINLINE()).isMinorCiv() )
  14813. {
  14814. iValue /= 2;
  14815. }
  14816. if (GET_PLAYER(pLoopCity->getOwnerINLINE()).isBarbarian())// && !bHuntBarbs)
  14817. {
  14818. if (!bHuntBarbs)
  14819. {
  14820. iValue /= 2;
  14821. }
  14822. if (pLoopCity->getCultureLevel() > 0)
  14823. {
  14824. iValue /= 10;
  14825. }
  14826. }
  14827. if (!(pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam())))
  14828. {
  14829. iValue /= 4;
  14830. }
  14831. if (pLoopCity->isRevealed(getTeam(), false) && pLoopCity->plot()->getNumDefenders(pLoopCity->getOwner()) == 0)
  14832. {
  14833. iValue *= 4;
  14834. }
  14835. // If stack has poor bombard, direct towards lower defense cities
  14836. iPathTurns += std::min(12, getGroup()->getBombardTurns(pLoopCity)/4);
  14837. iValue /= (4 + iPathTurns*iPathTurns);
  14838. // dont start new wars unless we have a seemingly overwhelming force
  14839. if (!GET_TEAM(getTeam()).isAtWar(pLoopCity->getTeam()))
  14840. {
  14841. int iModifier = 2;
  14842. if (!pLoopCity->plot()->isVisible(getTeam(),false))
  14843. {
  14844. iModifier++;
  14845. }
  14846. // if we don't already have a warplan for this foe, make sure we overwhelm them
  14847. if (GET_TEAM(getTeam()).AI_getWarPlan(pLoopCity->getTeam()) == NO_WARPLAN)
  14848. {
  14849. iModifier = 5;
  14850. }
  14851. // if we're already at war - need to be really powerful to start a new one
  14852. if (GET_TEAM(getTeam()).getAtWarCount(true) > 0)
  14853. {
  14854. iModifier *= 2;
  14855. }
  14856. int iGroupSize = 0;
  14857. if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL"))
  14858. {
  14859. iGroupSize = getGroup()->getCargo();
  14860. }
  14861. else
  14862. {
  14863. iGroupSize = getGroup()->getNumUnits();
  14864. }
  14865. if (iGroupSize <= (iModifier * pLoopCity->plot()->getNumDefenders(pLoopCity->getOwner())))
  14866. {
  14867. if( gUnitLogLevel > 3 )
  14868. {
  14869. logBBAI(" ...zeroing out city value due to small group size(modifier %d - groupsize %d)", iModifier, iGroupSize);
  14870. }
  14871. iValue = 0;
  14872. }
  14873. }
  14874. if (iValue > iBestValue)
  14875. {
  14876. iBestValue = iValue;
  14877. pBestCity = pLoopCity;
  14878. }
  14879. }
  14880. }
  14881. }
  14882. }
  14883. }
  14884. }
  14885. }
  14886. }
  14887. }
  14888. if (pBestCity != NULL)
  14889. {
  14890. if( gUnitLogLevel >= 2 )
  14891. {
  14892. logBBAI(" ...targeting city %S (final value: %d) \n", pBestCity->getName().GetCString(), iBestValue);
  14893. }
  14894. }
  14895. return pBestCity;
  14896. }
  14897. // Returns true if a mission was pushed...
  14898. bool CvUnitAI::AI_goToTargetCity(int iFlags, int iMaxPathTurns, CvCity* pTargetCity )
  14899. {
  14900. PROFILE_FUNC();
  14901. CvPlot* pAdjacentPlot;
  14902. CvPlot* pBestPlot;
  14903. int iPathTurns;
  14904. int iValue;
  14905. int iBestValue;
  14906. int iI;
  14907. if( pTargetCity == NULL )
  14908. {
  14909. pTargetCity = AI_pickTargetCity(iFlags, iMaxPathTurns);
  14910. }
  14911. if (pTargetCity != NULL)
  14912. {
  14913. PROFILE("CvUnitAI::AI_targetCity plot attack");
  14914. iBestValue = 0;
  14915. pBestPlot = NULL;
  14916. if (0 == (iFlags & MOVE_THROUGH_ENEMY))
  14917. {
  14918. for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  14919. {
  14920. pAdjacentPlot = plotDirection(pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), ((DirectionTypes)iI));
  14921. if (pAdjacentPlot != NULL)
  14922. {
  14923. if (getGroup()->canMoveThrough(pAdjacentPlot) && (pAdjacentPlot->isRevealed(getTeam(), false) || pAdjacentPlot->isAdjacentRevealed(getTeam())))
  14924. {
  14925. if (AI_plotValid(pAdjacentPlot))
  14926. {
  14927. if (!(pAdjacentPlot->isVisibleEnemyUnit(this)))
  14928. {
  14929. if (generatePath(pAdjacentPlot, iFlags, true, &iPathTurns))
  14930. {
  14931. if( iPathTurns <= iMaxPathTurns )
  14932. {
  14933. if ((getDuration() != 1) || // either we're not a temp unit about to expire
  14934. ((bombardRate() <= 0) || // or we cant bombard
  14935. (plotDistance(plot()->getX_INLINE(), plot()->getY_INLINE(), pAdjacentPlot->getX_INLINE(), pAdjacentPlot->getY_INLINE()) < baseMoves()) // or we can get to destination plot with moves still left
  14936. ))
  14937. {
  14938. iValue = std::max(0, (pAdjacentPlot->defenseModifier(getTeam(), false) + 100));
  14939. if (!(pAdjacentPlot->isRiverCrossing(directionXY(pAdjacentPlot, pTargetCity->plot()))))
  14940. {
  14941. iValue += (12 * -(GC.getRIVER_ATTACK_MODIFIER()));
  14942. }
  14943. if (!isEnemy(pAdjacentPlot->getTeam(), pAdjacentPlot))
  14944. {
  14945. iValue += 100;
  14946. }
  14947. if( atPlot(pAdjacentPlot) )
  14948. {
  14949. iValue += 50;
  14950. }
  14951. iValue = std::max(1, iValue);
  14952. iValue *= 1000;
  14953. iValue /= (iPathTurns + 1);
  14954. if (iValue > iBestValue)
  14955. {
  14956. iBestValue = iValue;
  14957. pBestPlot = getPathEndTurnPlot();
  14958. }
  14959. }
  14960. }
  14961. }
  14962. }
  14963. }
  14964. }
  14965. }
  14966. }
  14967. }
  14968. else
  14969. {
  14970. pBestPlot = pTargetCity->plot();
  14971. }
  14972. if (pBestPlot != NULL)
  14973. {
  14974. FAssert(!(pTargetCity->at(pBestPlot)) || 0 != (iFlags & MOVE_THROUGH_ENEMY)); // no suicide missions...
  14975. if (!atPlot(pBestPlot))
  14976. {
  14977. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), iFlags);
  14978. return true;
  14979. }
  14980. }
  14981. }
  14982. return false;
  14983. }
  14984. // Returns true if a mission was pushed...
  14985. bool CvUnitAI::AI_goToTargetBarbCity(int iMaxPathTurns)
  14986. {
  14987. PROFILE_FUNC();
  14988. CvCity* pLoopCity;
  14989. CvCity* pBestCity;
  14990. CvPlot* pAdjacentPlot;
  14991. CvPlot* pBestPlot;
  14992. int iPathTurns;
  14993. int iValue;
  14994. int iBestValue;
  14995. int iLoop;
  14996. int iI;
  14997. if (isBarbarian() || GET_TEAM(getTeam()).isBarbarianAlly())
  14998. {
  14999. return false;
  15000. }
  15001. iBestValue = 0;
  15002. pBestCity = NULL;
  15003. for (pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).nextCity(&iLoop))
  15004. {
  15005. if (AI_plotValid(pLoopCity->plot()))
  15006. {
  15007. // BBAI efficiency: check area for land units before generating path
  15008. if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
  15009. {
  15010. continue;
  15011. }
  15012. if (pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam()))
  15013. {
  15014. if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  15015. {
  15016. if (iPathTurns < iMaxPathTurns)
  15017. {
  15018. iValue = GET_PLAYER(getOwnerINLINE()).AI_targetCityValue(pLoopCity, false);
  15019. iValue *= 1000;
  15020. iValue /= (iPathTurns + 1);
  15021. iValue /= (1 + pLoopCity->plot()->getNumVisiblePotentialEnemyDefenders(this));
  15022. if (iValue > iBestValue)
  15023. {
  15024. iBestValue = iValue;
  15025. pBestCity = pLoopCity;
  15026. }
  15027. }
  15028. }
  15029. }
  15030. }
  15031. }
  15032. if (pBestCity != NULL)
  15033. {
  15034. if( gUnitLogLevel >= 2 )
  15035. {
  15036. logBBAI(" %S (unit %d) (groupsize: %d) targeting Barb city %S \n", getName().GetCString(), getID(), getGroup()->getNumUnits(), pBestCity->getName().GetCString());
  15037. }
  15038. iBestValue = 0;
  15039. pBestPlot = NULL;
  15040. for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  15041. {
  15042. pAdjacentPlot = plotDirection(pBestCity->getX_INLINE(), pBestCity->getY_INLINE(), ((DirectionTypes)iI));
  15043. if (pAdjacentPlot != NULL)
  15044. {
  15045. if (AI_plotValid(pAdjacentPlot))
  15046. {
  15047. if (!(pAdjacentPlot->isVisibleEnemyUnit(this)))
  15048. {
  15049. if (generatePath(pAdjacentPlot, 0, true, &iPathTurns))
  15050. {
  15051. if( iPathTurns <= iMaxPathTurns )
  15052. {
  15053. iValue = std::max(0, (pAdjacentPlot->defenseModifier(getTeam(), false) + 100));
  15054. if (!(pAdjacentPlot->isRiverCrossing(directionXY(pAdjacentPlot, pBestCity->plot()))))
  15055. {
  15056. iValue += (10 * -(GC.getRIVER_ATTACK_MODIFIER()));
  15057. }
  15058. iValue = std::max(1, iValue);
  15059. iValue *= 1000;
  15060. iValue /= (iPathTurns + 1);
  15061. if (iValue > iBestValue)
  15062. {
  15063. iBestValue = iValue;
  15064. pBestPlot = getPathEndTurnPlot();
  15065. }
  15066. }
  15067. }
  15068. }
  15069. }
  15070. }
  15071. }
  15072. if (pBestPlot != NULL)
  15073. {
  15074. FAssert(!(pBestCity->at(pBestPlot))); // no suicide missions...
  15075. if (atPlot(pBestPlot))
  15076. {
  15077. getGroup()->pushMission(MISSION_SKIP);
  15078. return true;
  15079. }
  15080. else
  15081. {
  15082. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  15083. return true;
  15084. }
  15085. }
  15086. }
  15087. return false;
  15088. }
  15089. bool CvUnitAI::AI_pillageAroundCity(CvCity* pTargetCity, int iBonusValueThreshold, int iMaxPathTurns )
  15090. {
  15091. PROFILE_FUNC();
  15092. CvPlot* pLoopPlot;
  15093. CvPlot* pBestPlot;
  15094. CvPlot* pBestPillagePlot;
  15095. int iPathTurns;
  15096. int iValue;
  15097. int iBestValue;
  15098. iBestValue = 0;
  15099. pBestPlot = NULL;
  15100. pBestPillagePlot = NULL;
  15101. //>>>>Unofficial Bug Fix: Modified by Denev 2010/04/04
  15102. // for( int iI = 0; iI < NUM_CITY_PLOTS; iI++ )
  15103. for (int iI = 0; iI < pTargetCity->getNumCityPlots(); iI++)
  15104. //<<<<Unofficial Bug Fix: End Modify
  15105. {
  15106. pLoopPlot = pTargetCity->getCityIndexPlot(iI);
  15107. if (pLoopPlot != NULL)
  15108. {
  15109. if (AI_plotValid(pLoopPlot) && !(pLoopPlot->isBarbarian()))
  15110. {
  15111. if (potentialWarAction(pLoopPlot) && (pLoopPlot->getTeam() == pTargetCity->getTeam()))
  15112. {
  15113. if (getGroup()->canPillage(pLoopPlot))
  15114. {
  15115. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  15116. {
  15117. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup()) == 0)
  15118. {
  15119. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  15120. {
  15121. if (getPathLastNode()->m_iData1 == 0)
  15122. {
  15123. iPathTurns++;
  15124. }
  15125. if ( iPathTurns <= iMaxPathTurns )
  15126. {
  15127. iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);
  15128. iValue *= 1000 + 30*(pLoopPlot->defenseModifier(getTeam(),false));
  15129. iValue /= (iPathTurns + 1);
  15130. // if not at war with this plot owner, then devalue plot if we already inside this owner's borders
  15131. // (because declaring war will pop us some unknown distance away)
  15132. if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
  15133. {
  15134. iValue /= 10;
  15135. }
  15136. if (iValue > iBestValue)
  15137. {
  15138. iBestValue = iValue;
  15139. pBestPlot = getPathEndTurnPlot();
  15140. pBestPillagePlot = pLoopPlot;
  15141. }
  15142. }
  15143. }
  15144. }
  15145. }
  15146. }
  15147. }
  15148. }
  15149. }
  15150. }
  15151. if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
  15152. {
  15153. if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
  15154. {
  15155. //getGroup()->groupDeclareWar(pBestPillagePlot, true);
  15156. // rather than declare war, just find something else to do, since we may already be deep in enemy territory
  15157. return false;
  15158. }
  15159. if (atPlot(pBestPillagePlot))
  15160. {
  15161. if (isEnemy(pBestPillagePlot->getTeam()))
  15162. {
  15163. getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
  15164. return true;
  15165. }
  15166. }
  15167. else
  15168. {
  15169. FAssert(!atPlot(pBestPlot));
  15170. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
  15171. return true;
  15172. }
  15173. }
  15174. return false;
  15175. }
  15176. // Returns true if a mission was pushed...
  15177. bool CvUnitAI::AI_bombardCity()
  15178. {
  15179. PROFILE_FUNC();
  15180. CvCity* pBombardCity;
  15181. bool bGroupCanBombard = false;
  15182. CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
  15183. while (pUnitNode != NULL)
  15184. {
  15185. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  15186. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  15187. {
  15188. if (pLoopUnit->canBombard(plot()))
  15189. {
  15190. bGroupCanBombard = true;
  15191. break;
  15192. }
  15193. }
  15194. }
  15195. if (bGroupCanBombard)
  15196. {
  15197. pBombardCity = bombardTarget(plot());
  15198. // Super Forts begin *bombard* (if statement contains original code for cities, else statement is new code for improvements)
  15199. //FAssertMsg(pBombardCity != NULL, "BombardCity is not assigned a valid value"); //Removed for Super Forts
  15200. if(pBombardCity != NULL)
  15201. {
  15202. // do not bombard cities with no defenders
  15203. int iDefenderStrength = pBombardCity->plot()->AI_sumStrength(NO_PLAYER, getOwnerINLINE(), DOMAIN_LAND, /*bDefensiveBonuses*/ true, /*bTestAtWar*/ true, false);
  15204. if (iDefenderStrength == 0)
  15205. {
  15206. return false;
  15207. }
  15208. // do not bombard cities if we have overwelming odds
  15209. int iAttackOdds = getGroup()->AI_attackOdds(pBombardCity->plot(), /*bPotentialEnemy*/ true);
  15210. if ( (iAttackOdds > 95) )
  15211. {
  15212. return false;
  15213. }
  15214. // If we have reasonable odds, check for attacking without waiting for bombards
  15215. if( (iAttackOdds >= GC.getDefineINT("BBAI_SKIP_BOMBARD_BEST_ATTACK_ODDS")) )
  15216. {
  15217. int iBase = std::max(150, GC.getDefineINT("BBAI_SKIP_BOMBARD_BASE_STACK_RATIO"));
  15218. int iComparison = getGroup()->AI_compareStacks(pBombardCity->plot(), /*bPotentialEnemy*/ true, /*bCheckCanAttack*/ true, /*bCheckCanMove*/ true);
  15219. // Big troop advantage plus pretty good starting odds, don't wait to allow reinforcements
  15220. /*
  15221. if( iComparison > (iBase - 4*iAttackOdds) )
  15222. {
  15223. if( gUnitLogLevel > 2 ) logBBAI(" Stack skipping bombard of %S with compare %d and starting odds %d", pBombardCity->getName().GetCString(), iComparison, iAttackOdds);
  15224. return false;
  15225. }
  15226. */
  15227. int iMin = std::max(100, GC.getDefineINT("BBAI_SKIP_BOMBARD_MIN_STACK_RATIO"));
  15228. bool bHasWaited = false;
  15229. CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
  15230. while (pUnitNode != NULL)
  15231. {
  15232. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  15233. if( pLoopUnit->getFortifyTurns() > 0 )
  15234. {
  15235. bHasWaited = true;
  15236. break;
  15237. }
  15238. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  15239. }
  15240. // Bombard at least one turn to allow bombers/ships to get some shots in too
  15241. if( bHasWaited && (pBombardCity->getDefenseDamage() > 0) )
  15242. {
  15243. int iBombardTurns = getGroup()->getBombardTurns(pBombardCity);
  15244. if( iComparison > std::max(iMin, iBase - 3*iAttackOdds - 3*iBombardTurns) )
  15245. {
  15246. if( gUnitLogLevel > 2 ) logBBAI(" Stack skipping bombard of %S with compare %d, starting odds %d, and bombard turns %d", pBombardCity->getName().GetCString(), iComparison, iAttackOdds, iBombardTurns);
  15247. return false;
  15248. }
  15249. }
  15250. }
  15251. //getGroup()->pushMission(MISSION_PILLAGE);
  15252. getGroup()->pushMission(MISSION_BOMBARD);
  15253. return true;
  15254. }
  15255. else
  15256. {
  15257. CvPlot* pTargetPlot = bombardImprovementTarget(plot());
  15258. // do not bombard cities with no defenders
  15259. int iDefenderStrength = pTargetPlot->AI_sumStrength(NO_PLAYER, getOwnerINLINE(), DOMAIN_LAND, /*bDefensiveBonuses*/ true, /*bTestAtWar*/ true, false);
  15260. if (iDefenderStrength == 0)
  15261. {
  15262. return false;
  15263. }
  15264. // do not bombard cities if we have overwelming odds
  15265. int iAttackOdds = getGroup()->AI_attackOdds(pTargetPlot, /*bPotentialEnemy*/ true);
  15266. if (iAttackOdds > 95)
  15267. {
  15268. return false;
  15269. }
  15270. // could also do a compare stacks call here if we wanted, the downside of that is that we may just have a lot more units
  15271. // we may not want to suffer high casualties just to save a turn
  15272. //getGroup()->AI_compareStacks(pBombardCity->plot(), /*bPotentialEnemy*/ true, /*bCheckCanAttack*/ true, /*bCheckCanMove*/ true);
  15273. //int iOurStrength = pBombardCity->plot()->AI_sumStrength(getOwnerINLINE(), NO_PLAYER, DOMAIN_LAND, false, false, false)
  15274. if(pTargetPlot->getDefenseDamage() < ((GC.getImprovementInfo(pTargetPlot->getImprovementType()).getDefenseModifier() * 3) / 4))
  15275. {
  15276. getGroup()->pushMission(MISSION_BOMBARD);
  15277. return true;
  15278. }
  15279. }
  15280. // Super Forts end
  15281. }
  15282. return false;
  15283. }
  15284. /************************************************************************************************/
  15285. /* BETTER_BTS_AI_MOD END */
  15286. /************************************************************************************************/
  15287. // Returns true if a mission was pushed...
  15288. bool CvUnitAI::AI_cityAttack(int iRange, int iOddsThreshold, bool bFollow)
  15289. {
  15290. PROFILE_FUNC();
  15291. CvPlot* pLoopPlot;
  15292. CvPlot* pBestPlot;
  15293. int iSearchRange;
  15294. int iPathTurns;
  15295. int iValue;
  15296. int iBestValue;
  15297. int iDX, iDY;
  15298. FAssert(canMove());
  15299. if (bFollow)
  15300. {
  15301. iSearchRange = 1;
  15302. }
  15303. else
  15304. {
  15305. iSearchRange = AI_searchRange(iRange);
  15306. }
  15307. iBestValue = 0;
  15308. pBestPlot = NULL;
  15309. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  15310. {
  15311. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  15312. {
  15313. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  15314. if (pLoopPlot != NULL)
  15315. {
  15316. if (AI_plotValid(pLoopPlot))
  15317. {
  15318. // Super Forts begin *AI_offense* - modified if statement so forts will be attacked too
  15319. if (pLoopPlot->isCity(GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)))
  15320. //if (pLoopPlot->isCity() || (pLoopPlot->isCity(true, getTeam()) && pLoopPlot->isVisibleEnemyUnit(this))) - Original Code
  15321. // Super Forts end
  15322. {
  15323. if (AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
  15324. {
  15325. if (!atPlot(pLoopPlot) && ((bFollow) ? canMoveInto(pLoopPlot, true) : (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= iRange))))
  15326. {
  15327. iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
  15328. if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
  15329. {
  15330. if (iValue > iBestValue)
  15331. {
  15332. iBestValue = iValue;
  15333. pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
  15334. FAssert(!atPlot(pBestPlot));
  15335. }
  15336. }
  15337. }
  15338. }
  15339. }
  15340. }
  15341. }
  15342. }
  15343. }
  15344. if (pBestPlot != NULL)
  15345. {
  15346. FAssert(!atPlot(pBestPlot));
  15347. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
  15348. return true;
  15349. }
  15350. return false;
  15351. }
  15352. /************************************************************************************************/
  15353. /* BETTER_BTS_AI_MOD 04/01/10 jdog5000 */
  15354. /* */
  15355. /* War tactics AI, Efficiency */
  15356. /************************************************************************************************/
  15357. // Returns true if a mission was pushed...
  15358. bool CvUnitAI::AI_anyAttack(int iRange, int iOddsThreshold, int iMinStack, bool bAllowCities, bool bFollow)
  15359. {
  15360. PROFILE_FUNC();
  15361. CvPlot* pLoopPlot;
  15362. CvPlot* pBestPlot;
  15363. int iSearchRange;
  15364. int iPathTurns;
  15365. int iValue;
  15366. int iBestValue;
  15367. int iDX, iDY;
  15368. FAssert(canMove());
  15369. if (AI_rangeAttack(iRange))
  15370. {
  15371. return true;
  15372. }
  15373. if (bFollow)
  15374. {
  15375. iSearchRange = 1;
  15376. }
  15377. else
  15378. {
  15379. iSearchRange = AI_searchRange(iRange);
  15380. }
  15381. iBestValue = 0;
  15382. pBestPlot = NULL;
  15383. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  15384. {
  15385. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  15386. {
  15387. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  15388. if (pLoopPlot != NULL)
  15389. {
  15390. if (AI_plotValid(pLoopPlot))
  15391. {
  15392. if( (bAllowCities) || !(pLoopPlot->isCity(false)) )
  15393. {
  15394. if (pLoopPlot->isVisibleEnemyUnit(this))
  15395. {
  15396. if (pLoopPlot->getNumVisibleEnemyDefenders(this) >= iMinStack)
  15397. {
  15398. if (!atPlot(pLoopPlot) && ((bFollow) ? canMoveInto(pLoopPlot, true) : (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= iRange))))
  15399. {
  15400. // Sephi AI - Allows the Function to Check for Summoned Units
  15401. bool bOnlySummons=true;
  15402. CLLNode<IDInfo>* pUnitNode;
  15403. CvUnit* pLoopUnit;
  15404. pUnitNode = pLoopPlot->headUnitNode();
  15405. while (pUnitNode != NULL)
  15406. {
  15407. pLoopUnit = ::getUnit(pUnitNode->m_data);
  15408. pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
  15409. if (pLoopUnit->getDuration()==0 || pLoopUnit->isPermanentSummon())
  15410. {
  15411. bOnlySummons=false;
  15412. break;
  15413. }
  15414. }
  15415. if (!bOnlySummons)
  15416. {
  15417. iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
  15418. if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
  15419. {
  15420. if (iValue > iBestValue)
  15421. {
  15422. iBestValue = iValue;
  15423. pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
  15424. FAssert(!atPlot(pBestPlot));
  15425. }
  15426. }
  15427. }
  15428. // End Sephi AI
  15429. }
  15430. }
  15431. }
  15432. }
  15433. }
  15434. }
  15435. }
  15436. }
  15437. if (pBestPlot != NULL)
  15438. {
  15439. FAssert(!atPlot(pBestPlot));
  15440. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
  15441. if( gUnitLogLevel >= 2 )
  15442. {
  15443. logBBAI( " Stack %d (led by %S (%d), size %d) attacking plot %d|%d", getGroup()->getID(), getName().GetCString(), getID(),
  15444. getGroup()->getNumUnits(), pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE() );
  15445. }
  15446. return true;
  15447. }
  15448. return false;
  15449. }
  15450. /************************************************************************************************/
  15451. /* BETTER_BTS_AI_MOD END */
  15452. /************************************************************************************************/
  15453. // Returns true if a mission was pushed...
  15454. bool CvUnitAI::AI_rangeAttack(int iRange)
  15455. {
  15456. PROFILE_FUNC();
  15457. FAssert(canMove());
  15458. if (!canRangeStrike())
  15459. {
  15460. return false;
  15461. }
  15462. int iSearchRange = AI_searchRange(iRange);
  15463. int iBestValue = 0;
  15464. CvPlot* pBestPlot = NULL;
  15465. for (int iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  15466. {
  15467. for (int iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  15468. {
  15469. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  15470. if (pLoopPlot != NULL)
  15471. {
  15472. // Super Forts begin *AI_offense* - modified if statement so forts will be attacked too
  15473. if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity(GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)) && AI_potentialEnemy(pLoopPlot->getTeam())))
  15474. //if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam()))) - Original Code
  15475. // Super Forts end
  15476. {
  15477. if (!atPlot(pLoopPlot) && canRangeStrikeAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
  15478. {
  15479. int iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
  15480. if (iValue > iBestValue)
  15481. {
  15482. iBestValue = iValue;
  15483. pBestPlot = pLoopPlot;
  15484. }
  15485. }
  15486. }
  15487. }
  15488. }
  15489. }
  15490. if (pBestPlot != NULL)
  15491. {
  15492. FAssert(!atPlot(pBestPlot));
  15493. getGroup()->pushMission(MISSION_RANGE_ATTACK, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0);
  15494. return true;
  15495. }
  15496. return false;
  15497. }
  15498. bool CvUnitAI::AI_leaveAttack(int iRange, int iOddsThreshold, int iStrengthThreshold)
  15499. {
  15500. CvPlot* pLoopPlot;
  15501. CvPlot* pBestPlot;
  15502. CvCity* pCity;
  15503. int iSearchRange;
  15504. int iPathTurns;
  15505. int iValue;
  15506. int iBestValue;
  15507. int iDX, iDY;
  15508. FAssert(canMove());
  15509. iSearchRange = iRange;
  15510. iBestValue = 0;
  15511. pBestPlot = NULL;
  15512. pCity = plot()->getPlotCity();
  15513. if ((pCity != NULL) && (pCity->getOwnerINLINE() == getOwnerINLINE()))
  15514. {
  15515. int iOurStrength = GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(), 0, false, false);
  15516. int iEnemyStrength = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(), 2, false, false);
  15517. if (iEnemyStrength > 0)
  15518. {
  15519. if (((iOurStrength * 100) / iEnemyStrength) < iStrengthThreshold)
  15520. {
  15521. return false;
  15522. }
  15523. if (plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE()) <= getGroup()->getNumUnits())
  15524. {
  15525. return false;
  15526. }
  15527. }
  15528. }
  15529. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  15530. {
  15531. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  15532. {
  15533. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  15534. if (pLoopPlot != NULL)
  15535. {
  15536. if (AI_plotValid(pLoopPlot))
  15537. {
  15538. // Super Forts begin *AI_offense* - modified if statement so forts will be attacked too
  15539. if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity(GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)) && AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot)))
  15540. //if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot))) - Original code
  15541. // Super Forts end
  15542. {
  15543. if (pLoopPlot->getNumVisibleEnemyDefenders(this) > 0)
  15544. {
  15545. /************************************************************************************************/
  15546. /* BETTER_BTS_AI_MOD 06/27/10 jdog5000 */
  15547. /* */
  15548. /* Bugfix */
  15549. /************************************************************************************************/
  15550. if (!atPlot(pLoopPlot) && (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= iRange)))
  15551. {
  15552. /************************************************************************************************/
  15553. /* BETTER_BTS_AI_MOD END */
  15554. /************************************************************************************************/
  15555. iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
  15556. if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
  15557. {
  15558. if (iValue > iBestValue)
  15559. {
  15560. iBestValue = iValue;
  15561. pBestPlot = getPathEndTurnPlot();
  15562. FAssert(!atPlot(pBestPlot));
  15563. }
  15564. }
  15565. }
  15566. }
  15567. }
  15568. }
  15569. }
  15570. }
  15571. }
  15572. if (pBestPlot != NULL)
  15573. {
  15574. FAssert(!atPlot(pBestPlot));
  15575. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0);
  15576. return true;
  15577. }
  15578. return false;
  15579. }
  15580. // Returns true if a mission was pushed...
  15581. bool CvUnitAI::AI_blockade()
  15582. {
  15583. PROFILE_FUNC();
  15584. CvCity* pCity;
  15585. CvPlot* pLoopPlot;
  15586. CvPlot* pBestPlot;
  15587. CvPlot* pBestBlockadePlot;
  15588. int iPathTurns;
  15589. int iValue;
  15590. int iBestValue;
  15591. int iI;
  15592. iBestValue = 0;
  15593. pBestPlot = NULL;
  15594. pBestBlockadePlot = NULL;
  15595. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  15596. {
  15597. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  15598. if (AI_plotValid(pLoopPlot))
  15599. {
  15600. if (potentialWarAction(pLoopPlot))
  15601. {
  15602. pCity = pLoopPlot->getWorkingCity();
  15603. if (pCity != NULL)
  15604. {
  15605. if (pCity->isCoastal(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
  15606. {
  15607. if (!(pCity->isBarbarian()))
  15608. {
  15609. FAssert(isEnemy(pCity->getTeam()) || GET_TEAM(getTeam()).AI_getWarPlan(pCity->getTeam()) != NO_WARPLAN);
  15610. if (!(pLoopPlot->isVisibleEnemyUnit(this)) && canPlunder(pLoopPlot))
  15611. {
  15612. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BLOCKADE, getGroup(), 2) == 0)
  15613. {
  15614. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  15615. {
  15616. iValue = 1;
  15617. iValue += std::min(pCity->getPopulation(), pCity->countNumWaterPlots());
  15618. iValue += GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pCity->plot());
  15619. iValue += (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCity->plot(), MISSIONAI_ASSAULT, getGroup(), 2) * 3);
  15620. if (canBombard(pLoopPlot))
  15621. {
  15622. iValue *= 2;
  15623. }
  15624. iValue *= 1000;
  15625. iValue /= (iPathTurns + 1);
  15626. if (iPathTurns == 1)
  15627. {
  15628. //Prefer to have movement remaining to Bombard + Plunder
  15629. iValue *= 1 + std::min(2, getPathLastNode()->m_iData1);
  15630. }
  15631. // if not at war with this plot owner, then devalue plot if we already inside this owner's borders
  15632. // (because declaring war will pop us some unknown distance away)
  15633. if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
  15634. {
  15635. iValue /= 10;
  15636. }
  15637. if (iValue > iBestValue)
  15638. {
  15639. iBestValue = iValue;
  15640. pBestPlot = getPathEndTurnPlot();
  15641. pBestBlockadePlot = pLoopPlot;
  15642. }
  15643. }
  15644. }
  15645. }
  15646. }
  15647. }
  15648. }
  15649. }
  15650. }
  15651. }
  15652. if ((pBestPlot != NULL) && (pBestBlockadePlot != NULL))
  15653. {
  15654. FAssert(canPlunder(pBestBlockadePlot));
  15655. if (atPlot(pBestBlockadePlot) && !isEnemy(pBestBlockadePlot->getTeam(), pBestBlockadePlot))
  15656. {
  15657. getGroup()->groupDeclareWar(pBestBlockadePlot, true);
  15658. }
  15659. if (atPlot(pBestBlockadePlot))
  15660. {
  15661. if (canBombard(plot()))
  15662. {
  15663. getGroup()->pushMission(MISSION_BOMBARD, -1, -1, 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
  15664. }
  15665. getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
  15666. return true;
  15667. }
  15668. else
  15669. {
  15670. FAssert(!atPlot(pBestPlot));
  15671. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
  15672. return true;
  15673. }
  15674. }
  15675. return false;
  15676. }
  15677. // Returns true if a mission was pushed...
  15678. bool CvUnitAI::AI_pirateBlockade()
  15679. {
  15680. PROFILE_FUNC();
  15681. int iPathTurns;
  15682. int iValue;
  15683. int iI;
  15684. std::vector<int> aiDeathZone(GC.getMapINLINE().numPlotsINLINE(), 0);
  15685. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  15686. {
  15687. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  15688. if (AI_plotValid(pLoopPlot) || (pLoopPlot->isCity() && pLoopPlot->isAdjacentToArea(area())))
  15689. {
  15690. if (pLoopPlot->isOwned() && (pLoopPlot->getTeam() != getTeam()))
  15691. {
  15692. int iBestHostileMoves = 0;
  15693. CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
  15694. while (pUnitNode != NULL)
  15695. {
  15696. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  15697. pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
  15698. if (isEnemy(pLoopUnit->getTeam(), pLoopUnit->plot()))
  15699. {
  15700. if (pLoopUnit->getDomainType() == DOMAIN_SEA && !pLoopUnit->isInvisible(getTeam(), false))
  15701. {
  15702. if (pLoopUnit->canAttack())
  15703. {
  15704. if (pLoopUnit->currEffectiveStr(NULL, NULL, NULL) > currEffectiveStr(pLoopPlot, pLoopUnit, NULL))
  15705. {
  15706. iBestHostileMoves = std::max(iBestHostileMoves, pLoopUnit->getMoves());
  15707. }
  15708. }
  15709. }
  15710. }
  15711. }
  15712. if (iBestHostileMoves > 0)
  15713. {
  15714. for (int iX = -iBestHostileMoves; iX <= iBestHostileMoves; iX++)
  15715. {
  15716. for (int iY = -iBestHostileMoves; iY <= iBestHostileMoves; iY++)
  15717. {
  15718. CvPlot * pRangePlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iX, iY);
  15719. if (pRangePlot != NULL)
  15720. {
  15721. aiDeathZone[GC.getMap().plotNumINLINE(pRangePlot->getX_INLINE(), pRangePlot->getY_INLINE())]++;
  15722. }
  15723. }
  15724. }
  15725. }
  15726. }
  15727. }
  15728. }
  15729. bool bIsInDanger = aiDeathZone[GC.getMap().plotNumINLINE(getX_INLINE(), getY_INLINE())] > 0;
  15730. if (!bIsInDanger)
  15731. {
  15732. if (getDamage() > 0)
  15733. {
  15734. if (!plot()->isOwned() && !plot()->isAdjacentOwned())
  15735. {
  15736. if (AI_retreatToCity(false, false, 1 + getDamage() / 20))
  15737. {
  15738. return true;
  15739. }
  15740. getGroup()->pushMission(MISSION_SKIP);
  15741. return true;
  15742. }
  15743. }
  15744. }
  15745. int iBestValue = 0;
  15746. CvPlot* pBestPlot = NULL;
  15747. CvPlot* pBestBlockadePlot = NULL;
  15748. bool bBestIsForceMove = false;
  15749. bool bBestIsMove = false;
  15750. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  15751. {
  15752. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  15753. if (AI_plotValid(pLoopPlot))
  15754. {
  15755. if (!(pLoopPlot->isVisibleEnemyUnit(this)) && canPlunder(pLoopPlot))
  15756. {
  15757. if (GC.getGame().getSorenRandNum(4, "AI Pirate Blockade") == 0)
  15758. {
  15759. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BLOCKADE, getGroup(), 3) == 0)
  15760. {
  15761. /************************************************************************************************/
  15762. /* BETTER_BTS_AI_MOD 01/17/09 jdog5000 */
  15763. /* */
  15764. /* Pirate AI */
  15765. /************************************************************************************************/
  15766. /* original bts code
  15767. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  15768. */
  15769. if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
  15770. /************************************************************************************************/
  15771. /* BETTER_BTS_AI_MOD END */
  15772. /************************************************************************************************/
  15773. {
  15774. int iBlockadedCount = 0;
  15775. int iPopulationValue = 0;
  15776. int iRange = GC.getDefineINT("SHIP_BLOCKADE_RANGE") - 1;
  15777. for (int iX = -iRange; iX <= iRange; iX++)
  15778. {
  15779. for (int iY = -iRange; iY <= iRange; iY++)
  15780. {
  15781. CvPlot* pRangePlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iX, iY);
  15782. if (pRangePlot != NULL)
  15783. {
  15784. bool bPlotBlockaded = false;
  15785. if (pRangePlot->isWater() && pRangePlot->isOwned() && isEnemy(pRangePlot->getTeam(), pLoopPlot))
  15786. {
  15787. bPlotBlockaded = true;
  15788. iBlockadedCount += pRangePlot->getBlockadedCount(pRangePlot->getTeam());
  15789. }
  15790. if (!bPlotBlockaded)
  15791. {
  15792. CvCity* pPlotCity = pRangePlot->getPlotCity();
  15793. if (pPlotCity != NULL)
  15794. {
  15795. if (isEnemy(pPlotCity->getTeam(), pLoopPlot))
  15796. {
  15797. int iCityValue = 3 + pPlotCity->getPopulation();
  15798. iCityValue *= (atWar(getTeam(), pPlotCity->getTeam()) ? 1 : 3);
  15799. if (GET_PLAYER(pPlotCity->getOwnerINLINE()).isNoForeignTrade())
  15800. {
  15801. iCityValue /= 2;
  15802. }
  15803. iPopulationValue += iCityValue;
  15804. }
  15805. }
  15806. }
  15807. }
  15808. }
  15809. }
  15810. iValue = iPopulationValue;
  15811. iValue *= 1000;
  15812. iValue /= 16 + iBlockadedCount;
  15813. bool bMove = ((getPathLastNode()->m_iData2 == 1) && getPathLastNode()->m_iData1 > 0);
  15814. if (atPlot(pLoopPlot))
  15815. {
  15816. iValue *= 3;
  15817. }
  15818. else if (bMove)
  15819. {
  15820. iValue *= 2;
  15821. }
  15822. int iDeath = aiDeathZone[GC.getMap().plotNumINLINE(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE())];
  15823. bool bForceMove = false;
  15824. if (iDeath)
  15825. {
  15826. iValue /= 10;
  15827. }
  15828. else if (bIsInDanger && (iPathTurns <= 2) && (0 == iPopulationValue))
  15829. {
  15830. if (getPathLastNode()->m_iData1 == 0)
  15831. {
  15832. if (!pLoopPlot->isAdjacentOwned())
  15833. {
  15834. int iRand = GC.getGame().getSorenRandNum(2500, "AI Pirate Retreat");
  15835. iValue += iRand;
  15836. if (iRand > 1000)
  15837. {
  15838. iValue += GC.getGame().getSorenRandNum(2500, "AI Pirate Retreat");
  15839. bForceMove = true;
  15840. }
  15841. }
  15842. }
  15843. }
  15844. if (!bForceMove)
  15845. {
  15846. iValue /= iPathTurns + 1;
  15847. }
  15848. if (iValue > iBestValue)
  15849. {
  15850. iBestValue = iValue;
  15851. pBestPlot = bForceMove ? pLoopPlot : getPathEndTurnPlot();
  15852. pBestBlockadePlot = pLoopPlot;
  15853. bBestIsForceMove = bForceMove;
  15854. bBestIsMove = bMove;
  15855. }
  15856. }
  15857. }
  15858. }
  15859. }
  15860. }
  15861. }
  15862. if ((pBestPlot != NULL) && (pBestBlockadePlot != NULL))
  15863. {
  15864. FAssert(canPlunder(pBestBlockadePlot));
  15865. if (atPlot(pBestBlockadePlot))
  15866. {
  15867. getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
  15868. return true;
  15869. }
  15870. else
  15871. {
  15872. FAssert(!atPlot(pBestPlot));
  15873. if (bBestIsForceMove)
  15874. {
  15875. /************************************************************************************************/
  15876. /* BETTER_BTS_AI_MOD 01/01/09 jdog5000 */
  15877. /* */
  15878. /* Pirate AI */
  15879. /************************************************************************************************/
  15880. /* original bts code
  15881. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  15882. */
  15883. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
  15884. /************************************************************************************************/
  15885. /* BETTER_BTS_AI_MOD END */
  15886. /************************************************************************************************/
  15887. return true;
  15888. }
  15889. else
  15890. {
  15891. /************************************************************************************************/
  15892. /* BETTER_BTS_AI_MOD 01/01/09 jdog5000 */
  15893. /* */
  15894. /* Pirate AI */
  15895. /************************************************************************************************/
  15896. /* original bts code
  15897. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
  15898. */
  15899. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
  15900. /************************************************************************************************/
  15901. /* BETTER_BTS_AI_MOD END */
  15902. /************************************************************************************************/
  15903. if (bBestIsMove)
  15904. {
  15905. getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
  15906. }
  15907. return true;
  15908. }
  15909. }
  15910. }
  15911. return false;
  15912. }
  15913. // Returns true if a mission was pushed...
  15914. bool CvUnitAI::AI_seaBombardRange(int iMaxRange)
  15915. {
  15916. PROFILE_FUNC();
  15917. // cached values
  15918. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  15919. CvPlot* pPlot = plot();
  15920. CvSelectionGroup* pGroup = getGroup();
  15921. // can any unit in this group bombard?
  15922. bool bHasBombardUnit = false;
  15923. bool bBombardUnitCanBombardNow = false;
  15924. CLLNode<IDInfo>* pUnitNode = pGroup->headUnitNode();
  15925. while (pUnitNode != NULL && !bBombardUnitCanBombardNow)
  15926. {
  15927. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  15928. pUnitNode = pGroup->nextUnitNode(pUnitNode);
  15929. if (pLoopUnit->bombardRate() > 0)
  15930. {
  15931. bHasBombardUnit = true;
  15932. if (pLoopUnit->canMove() && !pLoopUnit->isMadeAttack())
  15933. {
  15934. bBombardUnitCanBombardNow = true;
  15935. }
  15936. }
  15937. }
  15938. if (!bHasBombardUnit)
  15939. {
  15940. return false;
  15941. }
  15942. // best match
  15943. CvPlot* pBestPlot = NULL;
  15944. CvPlot* pBestBombardPlot = NULL;
  15945. int iBestValue = 0;
  15946. // iterate over plots at each range
  15947. for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
  15948. {
  15949. for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
  15950. {
  15951. CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
  15952. if (pLoopPlot != NULL && AI_plotValid(pLoopPlot))
  15953. {
  15954. CvCity* pBombardCity = bombardTarget(pLoopPlot);
  15955. if (pBombardCity != NULL && isEnemy(pBombardCity->getTeam(), pLoopPlot) && pBombardCity->getDefenseDamage() < GC.getMAX_CITY_DEFENSE_DAMAGE())
  15956. {
  15957. int iPathTurns;
  15958. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  15959. {
  15960. /********************************************************************************/
  15961. /* BETTER_BTS_AI_MOD 6/24/08 jdog5000 */
  15962. /* */
  15963. /* Naval AI */
  15964. /********************************************************************************/
  15965. // Loop construction doesn't guarantee we can get there anytime soon, could be on other side of narrow continent
  15966. if( iPathTurns <= (1 + iMaxRange/std::max(1, baseMoves())) )
  15967. {
  15968. // Check only for supporting our own ground troops first, if none will look for another target
  15969. int iValue = (kPlayer.AI_plotTargetMissionAIs(pBombardCity->plot(), MISSIONAI_ASSAULT, NULL, 2) * 3);
  15970. iValue += (kPlayer.AI_adjacentPotentialAttackers(pBombardCity->plot(), true));
  15971. if (iValue > 0)
  15972. {
  15973. iValue *= 1000;
  15974. iValue /= (iPathTurns + 1);
  15975. if (iPathTurns == 1)
  15976. {
  15977. //Prefer to have movement remaining to Bombard + Plunder
  15978. iValue *= 1 + std::min(2, getPathLastNode()->m_iData1);
  15979. }
  15980. if (iValue > iBestValue)
  15981. {
  15982. iBestValue = iValue;
  15983. pBestPlot = getPathEndTurnPlot();
  15984. pBestBombardPlot = pLoopPlot;
  15985. }
  15986. }
  15987. }
  15988. /********************************************************************************/
  15989. /* BETTER_BTS_AI_MOD END */
  15990. /********************************************************************************/
  15991. }
  15992. }
  15993. }
  15994. }
  15995. }
  15996. /********************************************************************************/
  15997. /* BETTER_BTS_AI_MOD 6/24/08 jdog5000 */
  15998. /* */
  15999. /* Naval AI */
  16000. /********************************************************************************/
  16001. // If no troops of ours to support, check for other bombard targets
  16002. if( (pBestPlot == NULL) && (pBestBombardPlot == NULL) )
  16003. {
  16004. if( (AI_getUnitAIType() != UNITAI_ASSAULT_SEA) )
  16005. {
  16006. for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
  16007. {
  16008. for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
  16009. {
  16010. CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
  16011. if (pLoopPlot != NULL && AI_plotValid(pLoopPlot))
  16012. {
  16013. CvCity* pBombardCity = bombardTarget(pLoopPlot);
  16014. // Consider city even if fully bombarded, causes ship to camp outside blockading instead of twitching between
  16015. // cities after bombarding to 0
  16016. if (pBombardCity != NULL && isEnemy(pBombardCity->getTeam(), pLoopPlot) && pBombardCity->getTotalDefense(false) > 0)
  16017. {
  16018. int iPathTurns;
  16019. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  16020. {
  16021. // Loop construction doesn't guarantee we can get there anytime soon, could be on other side of narrow continent
  16022. if( iPathTurns <= 1 + iMaxRange/std::max(1, baseMoves()) )
  16023. {
  16024. int iValue = std::min(20,pBombardCity->getDefenseModifier(false)/2);
  16025. // Inclination to support attacks by others
  16026. /************************************************************************************************/
  16027. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  16028. /* */
  16029. /* Unit AI, Efficiency */
  16030. /************************************************************************************************/
  16031. //if( GET_PLAYER(pBombardCity->getOwnerINLINE()).AI_getPlotDanger(pBombardCity->plot(), 2, false) > 0 )
  16032. if( GET_PLAYER(pBombardCity->getOwnerINLINE()).AI_getAnyPlotDanger(pBombardCity->plot(), 2, false) )
  16033. {
  16034. iValue += 60;
  16035. }
  16036. /************************************************************************************************/
  16037. /* BETTER_BTS_AI_MOD END */
  16038. /************************************************************************************************/
  16039. // Inclination to bombard a different nearby city to extend the reach of blockade
  16040. if( GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pBombardCity->plot(), MISSIONAI_BLOCKADE, getGroup(), 3) == 0 )
  16041. {
  16042. iValue += 35 + pBombardCity->getPopulation();
  16043. }
  16044. // Small inclination to bombard area target, not too large so as not to tip our hand
  16045. if( pBombardCity == pBombardCity->area()->getTargetCity(getOwnerINLINE()) )
  16046. {
  16047. iValue += 10;
  16048. }
  16049. if (iValue > 0)
  16050. {
  16051. iValue *= 1000;
  16052. iValue /= (iPathTurns + 1);
  16053. if (iPathTurns == 1)
  16054. {
  16055. //Prefer to have movement remaining to Bombard + Plunder
  16056. iValue *= 1 + std::min(2, getPathLastNode()->m_iData1);
  16057. }
  16058. if (iValue > iBestValue)
  16059. {
  16060. iBestValue = iValue;
  16061. pBestPlot = getPathEndTurnPlot();
  16062. pBestBombardPlot = pLoopPlot;
  16063. }
  16064. }
  16065. }
  16066. }
  16067. }
  16068. }
  16069. }
  16070. }
  16071. }
  16072. }
  16073. /********************************************************************************/
  16074. /* BETTER_BTS_AI_MOD END */
  16075. /********************************************************************************/
  16076. if ((pBestPlot != NULL) && (pBestBombardPlot != NULL))
  16077. {
  16078. if (atPlot(pBestBombardPlot))
  16079. {
  16080. // if we are at the plot from which to bombard, and we have a unit that can bombard this turn, do it
  16081. if (bBombardUnitCanBombardNow && pGroup->canBombard(pBestBombardPlot))
  16082. {
  16083. getGroup()->pushMission(MISSION_BOMBARD, -1, -1, 0, false, false, MISSIONAI_BLOCKADE, pBestBombardPlot);
  16084. // if city bombarded enough, wake up any units that were waiting to bombard this city
  16085. CvCity* pBombardCity = bombardTarget(pBestBombardPlot); // is NULL if city cannot be bombarded any more
  16086. if (pBombardCity == NULL || pBombardCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE()*5)/6))
  16087. {
  16088. kPlayer.AI_wakePlotTargetMissionAIs(pBestBombardPlot, MISSIONAI_BLOCKADE, getGroup());
  16089. }
  16090. }
  16091. // otherwise, skip until next turn, when we will surely bombard
  16092. else if (canPlunder(pBestBombardPlot))
  16093. {
  16094. getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, false, false, MISSIONAI_BLOCKADE, pBestBombardPlot);
  16095. }
  16096. else
  16097. {
  16098. getGroup()->pushMission(MISSION_SKIP);
  16099. }
  16100. return true;
  16101. }
  16102. else
  16103. {
  16104. FAssert(!atPlot(pBestPlot));
  16105. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBombardPlot);
  16106. return true;
  16107. }
  16108. }
  16109. return false;
  16110. }
  16111. // Returns true if a mission was pushed...
  16112. bool CvUnitAI::AI_pillage(int iBonusValueThreshold)
  16113. {
  16114. PROFILE_FUNC();
  16115. CvPlot* pLoopPlot;
  16116. CvPlot* pBestPlot;
  16117. CvPlot* pBestPillagePlot;
  16118. int iPathTurns;
  16119. int iValue;
  16120. int iBestValue;
  16121. int iI;
  16122. iBestValue = 0;
  16123. pBestPlot = NULL;
  16124. pBestPillagePlot = NULL;
  16125. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  16126. {
  16127. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  16128. if (AI_plotValid(pLoopPlot) && !(pLoopPlot->isBarbarian()))
  16129. {
  16130. /************************************************************************************************/
  16131. /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
  16132. /* */
  16133. /* Unit AI, Efficiency */
  16134. /************************************************************************************************/
  16135. //if (potentialWarAction(pLoopPlot))
  16136. if( pLoopPlot->isOwned() && isEnemy(pLoopPlot->getTeam(),pLoopPlot) )
  16137. {
  16138. CvCity * pWorkingCity = pLoopPlot->getWorkingCity();
  16139. if (pWorkingCity != NULL)
  16140. {
  16141. if (!(pWorkingCity == area()->getTargetCity(getOwnerINLINE())) && canPillage(pLoopPlot))
  16142. {
  16143. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  16144. {
  16145. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup(), 1) == 0)
  16146. {
  16147. iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);
  16148. iValue *= 1000;
  16149. // if not at war with this plot owner, then devalue plot if we already inside this owner's borders
  16150. // (because declaring war will pop us some unknown distance away)
  16151. if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
  16152. {
  16153. iValue /= 10;
  16154. }
  16155. if( iValue > iBestValue )
  16156. {
  16157. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  16158. {
  16159. iValue /= (iPathTurns + 1);
  16160. if (iValue > iBestValue)
  16161. {
  16162. iBestValue = iValue;
  16163. pBestPlot = getPathEndTurnPlot();
  16164. pBestPillagePlot = pLoopPlot;
  16165. }
  16166. }
  16167. }
  16168. }
  16169. }
  16170. }
  16171. }
  16172. }
  16173. }
  16174. /************************************************************************************************/
  16175. /* BETTER_BTS_AI_MOD END */
  16176. /************************************************************************************************/
  16177. }
  16178. if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
  16179. {
  16180. if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
  16181. {
  16182. //getGroup()->groupDeclareWar(pBestPillagePlot, true);
  16183. // rather than declare war, just find something else to do, since we may already be deep in enemy territory
  16184. return false;
  16185. }
  16186. if (atPlot(pBestPillagePlot))
  16187. {
  16188. if (isEnemy(pBestPillagePlot->getTeam()))
  16189. {
  16190. getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
  16191. return true;
  16192. }
  16193. }
  16194. else
  16195. {
  16196. FAssert(!atPlot(pBestPlot));
  16197. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
  16198. return true;
  16199. }
  16200. }
  16201. return false;
  16202. }
  16203. bool CvUnitAI::AI_canPillage(CvPlot& kPlot) const
  16204. {
  16205. if (isEnemy(kPlot.getTeam(), &kPlot))
  16206. {
  16207. return true;
  16208. }
  16209. if (!kPlot.isOwned())
  16210. {
  16211. bool bPillageUnowned = true;
  16212. for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS && bPillageUnowned; ++iPlayer)
  16213. {
  16214. int iIndx;
  16215. CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iPlayer);
  16216. if (!isEnemy(kLoopPlayer.getTeam(), &kPlot))
  16217. {
  16218. for (CvCity* pCity = kLoopPlayer.firstCity(&iIndx); NULL != pCity; pCity = kLoopPlayer.nextCity(&iIndx))
  16219. {
  16220. if (kPlot.getPlotGroup((PlayerTypes)iPlayer) == pCity->plot()->getPlotGroup((PlayerTypes)iPlayer))
  16221. {
  16222. bPillageUnowned = false;
  16223. break;
  16224. }
  16225. }
  16226. }
  16227. }
  16228. if (bPillageUnowned)
  16229. {
  16230. return true;
  16231. }
  16232. }
  16233. return false;
  16234. }
  16235. // Returns true if a mission was pushed...
  16236. bool CvUnitAI::AI_pillageRange(int iRange, int iBonusValueThreshold)
  16237. {
  16238. PROFILE_FUNC();
  16239. CvPlot* pLoopPlot;
  16240. CvPlot* pBestPlot;
  16241. CvPlot* pBestPillagePlot;
  16242. int iSearchRange;
  16243. int iPathTurns;
  16244. int iValue;
  16245. int iBestValue;
  16246. int iDX, iDY;
  16247. iSearchRange = AI_searchRange(iRange);
  16248. iBestValue = 0;
  16249. pBestPlot = NULL;
  16250. pBestPillagePlot = NULL;
  16251. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  16252. {
  16253. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  16254. {
  16255. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  16256. if (pLoopPlot != NULL)
  16257. {
  16258. if (AI_plotValid(pLoopPlot) && !(pLoopPlot->isBarbarian()))
  16259. {
  16260. if (potentialWarAction(pLoopPlot))
  16261. {
  16262. CvCity * pWorkingCity = pLoopPlot->getWorkingCity();
  16263. if (pWorkingCity != NULL)
  16264. {
  16265. if (!(pWorkingCity == area()->getTargetCity(getOwnerINLINE())) && getGroup()->canPillage(pLoopPlot))
  16266. {
  16267. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  16268. {
  16269. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup()) == 0)
  16270. {
  16271. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  16272. {
  16273. if (getPathLastNode()->m_iData1 == 0)
  16274. {
  16275. iPathTurns++;
  16276. }
  16277. if (iPathTurns <= iRange)
  16278. {
  16279. iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);
  16280. iValue *= 1000;
  16281. iValue /= (iPathTurns + 1);
  16282. // if not at war with this plot owner, then devalue plot if we already inside this owner's borders
  16283. // (because declaring war will pop us some unknown distance away)
  16284. if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
  16285. {
  16286. iValue /= 10;
  16287. }
  16288. if (iValue > iBestValue)
  16289. {
  16290. iBestValue = iValue;
  16291. //pBestPlot = getPathEndTurnPlot();
  16292. pBestPlot = pLoopPlot;
  16293. pBestPillagePlot = pLoopPlot;
  16294. }
  16295. }
  16296. }
  16297. }
  16298. }
  16299. }
  16300. }
  16301. }
  16302. }
  16303. }
  16304. }
  16305. }
  16306. if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
  16307. {
  16308. if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
  16309. {
  16310. //getGroup()->groupDeclareWar(pBestPillagePlot, true);
  16311. // rather than declare war, just find something else to do, since we may already be deep in enemy territory
  16312. return false;
  16313. }
  16314. if (atPlot(pBestPillagePlot))
  16315. {
  16316. if (isEnemy(pBestPillagePlot->getTeam()))
  16317. {
  16318. getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
  16319. return true;
  16320. }
  16321. }
  16322. else
  16323. {
  16324. FAssert(!atPlot(pBestPlot));
  16325. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
  16326. return true;
  16327. }
  16328. }
  16329. return false;
  16330. }
  16331. // Returns true if a mission was pushed...
  16332. bool CvUnitAI::AI_found()
  16333. {
  16334. PROFILE_FUNC();
  16335. //
  16336. // CvPlot* pLoopPlot;
  16337. // CvPlot* pBestPlot;
  16338. // CvPlot* pBestFoundPlot;
  16339. // int iPathTurns;
  16340. // int iValue;
  16341. // int iBestValue;
  16342. // int iI;
  16343. //
  16344. // iBestValue = 0;
  16345. // pBestPlot = NULL;
  16346. // pBestFoundPlot = NULL;
  16347. //
  16348. // for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  16349. // {
  16350. // pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  16351. //
  16352. // if (AI_plotValid(pLoopPlot) && (pLoopPlot != plot() || GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopPlot, 1) <= pLoopPlot->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE())))
  16353. // {
  16354. // if (canFound(pLoopPlot))
  16355. // {
  16356. // iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
  16357. //
  16358. // if (iValue > 0)
  16359. // {
  16360. // if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  16361. // {
  16362. // if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_FOUND, getGroup(), 3) == 0)
  16363. // {
  16364. // if (generatePath(pLoopPlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
  16365. // {
  16366. // iValue *= 1000;
  16367. //
  16368. // iValue /= (iPathTurns + 1);
  16369. //
  16370. // if (iValue > iBestValue)
  16371. // {
  16372. // iBestValue = iValue;
  16373. // pBestPlot = getPathEndTurnPlot();
  16374. // pBestFoundPlot = pLoopPlot;
  16375. // }
  16376. // }
  16377. // }
  16378. // }
  16379. // }
  16380. // }
  16381. // }
  16382. // }
  16383. int iPathTurns;
  16384. int iValue;
  16385. int iBestFoundValue = 0;
  16386. CvPlot* pBestPlot = NULL;
  16387. CvPlot* pBestFoundPlot = NULL;
  16388. for (int iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
  16389. {
  16390. CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
  16391. /************************************************************************************************/
  16392. /* BETTER_BTS_AI_MOD 10/23/09 jdog5000 */
  16393. /* */
  16394. /* Settler AI */
  16395. /************************************************************************************************/
  16396. /* orginal BTS code
  16397. if (pCitySitePlot->getArea() == getArea())
  16398. */
  16399. if (pCitySitePlot->getArea() == getArea() || canMoveAllTerrain())
  16400. /************************************************************************************************/
  16401. /* BETTER_BTS_AI_MOD END */
  16402. /************************************************************************************************/
  16403. {
  16404. if (canFound(pCitySitePlot))
  16405. {
  16406. if (!(pCitySitePlot->isVisibleEnemyUnit(this)))
  16407. {
  16408. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_FOUND, getGroup()) == 0)
  16409. {
  16410. if (getGroup()->canDefend() || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_GUARD_CITY) > 0)
  16411. {
  16412. if (generatePath(pCitySitePlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
  16413. {
  16414. iValue = pCitySitePlot->getFoundValue(getOwnerINLINE());
  16415. iValue *= 1000;
  16416. iValue /= (iPathTurns + 1);
  16417. if (iValue > iBestFoundValue)
  16418. {
  16419. iBestFoundValue = iValue;
  16420. pBestPlot = getPathEndTurnPlot();
  16421. pBestFoundPlot = pCitySitePlot;
  16422. }
  16423. }
  16424. }
  16425. }
  16426. }
  16427. }
  16428. }
  16429. }
  16430. if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
  16431. {
  16432. if (atPlot(pBestFoundPlot))
  16433. {
  16434. if( gUnitLogLevel >= 2 )
  16435. {
  16436. logBBAI(" Settler founding at best found plot %d, %d", pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE());
  16437. }
  16438. getGroup()->pushMission(MISSION_FOUND, -1, -1, 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
  16439. return true;
  16440. }
  16441. else
  16442. {
  16443. if( gUnitLogLevel >= 2 )
  16444. {
  16445. logBBAI(" Settler heading for best found plot %d, %d", pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE());
  16446. }
  16447. FAssert(!atPlot(pBestPlot));
  16448. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_FOUND, pBestFoundPlot);
  16449. return true;
  16450. }
  16451. }
  16452. return false;
  16453. }
  16454. // Returns true if a mission was pushed...
  16455. bool CvUnitAI::AI_foundRange(int iRange, bool bFollow)
  16456. {
  16457. PROFILE_FUNC();
  16458. CvPlot* pLoopPlot;
  16459. CvPlot* pBestPlot;
  16460. CvPlot* pBestFoundPlot;
  16461. int iSearchRange;
  16462. int iPathTurns;
  16463. int iValue;
  16464. int iBestValue;
  16465. int iDX, iDY;
  16466. iSearchRange = AI_searchRange(iRange);
  16467. iBestValue = 0;
  16468. pBestPlot = NULL;
  16469. pBestFoundPlot = NULL;
  16470. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  16471. {
  16472. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  16473. {
  16474. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  16475. if (pLoopPlot != NULL)
  16476. {
  16477. if (AI_plotValid(pLoopPlot) && (pLoopPlot != plot() || GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopPlot, 1) <= pLoopPlot->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE())))
  16478. {
  16479. if (canFound(pLoopPlot))
  16480. {
  16481. iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
  16482. if (iValue > iBestValue)
  16483. {
  16484. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  16485. {
  16486. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_FOUND, getGroup(), 3) == 0)
  16487. {
  16488. if (generatePath(pLoopPlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
  16489. {
  16490. if (iPathTurns <= iRange)
  16491. {
  16492. iBestValue = iValue;
  16493. pBestPlot = getPathEndTurnPlot();
  16494. pBestFoundPlot = pLoopPlot;
  16495. }
  16496. }
  16497. }
  16498. }
  16499. }
  16500. }
  16501. }
  16502. }
  16503. }
  16504. }
  16505. if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
  16506. {
  16507. if (atPlot(pBestFoundPlot))
  16508. {
  16509. getGroup()->pushMission(MISSION_FOUND, -1, -1, 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
  16510. return true;
  16511. }
  16512. else if (!bFollow)
  16513. {
  16514. FAssert(!atPlot(pBestPlot));
  16515. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_FOUND, pBestFoundPlot);
  16516. return true;
  16517. }
  16518. }
  16519. return false;
  16520. }
  16521. // Returns true if a mission was pushed...
  16522. bool CvUnitAI::AI_assaultSeaTransport(bool bBarbarian)
  16523. {
  16524. PROFILE_FUNC();
  16525. if( gUnitLogLevel >= 2 )
  16526. {
  16527. logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_assaultSeaTransport", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  16528. }
  16529. bool bIsAttackCity = (getUnitAICargo(UNITAI_ATTACK_CITY) > 0);
  16530. FAssert(getGroup()->hasCargo());
  16531. //FAssert(bIsAttackCity || getGroup()->getUnitAICargo(UNITAI_ATTACK) > 0);
  16532. if (!canCargoAllMove())
  16533. {
  16534. if( gUnitLogLevel >= 4 ) logBBAI(" ...CANT MOVE!");
  16535. return false;
  16536. }
  16537. if (getGroup()->AI_getMissionAIType() == MISSIONAI_ASSAULT)
  16538. {
  16539. if (getPathLastNode() != NULL)
  16540. {
  16541. if( gUnitLogLevel >= 4 ) logBBAI(" ...continuing mission to plot %d, %d", getPathEndTurnPlot()->getX(), getPathEndTurnPlot()->getY());
  16542. getGroup()->pushMission(MISSION_MOVE_TO, getPathEndTurnPlot()->getX(), getPathEndTurnPlot()->getY(), MOVE_AVOID_ENEMY_WEIGHT_3);
  16543. }
  16544. else
  16545. {
  16546. if( gUnitLogLevel >= 4 ) logBBAI(" ...continuing mission to assault plot %d, %d", getGroup()->AI_getMissionAIPlot()->getX(), getGroup()->AI_getMissionAIPlot()->getY());
  16547. getGroup()->pushMission(MISSION_MOVE_TO, getGroup()->AI_getMissionAIPlot()->getX(), getGroup()->AI_getMissionAIPlot()->getY(), MOVE_AVOID_ENEMY_WEIGHT_3);
  16548. }
  16549. return true;
  16550. }
  16551. std::vector<CvUnit*> aGroupCargo;
  16552. CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode();
  16553. while (pUnitNode != NULL)
  16554. {
  16555. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  16556. pUnitNode = plot()->nextUnitNode(pUnitNode);
  16557. CvUnit* pTransport = pLoopUnit->getTransportUnit();
  16558. if (pTransport != NULL && pTransport->getGroup() == getGroup())
  16559. {
  16560. aGroupCargo.push_back(pLoopUnit);
  16561. }
  16562. }
  16563. int iCargo = getGroup()->getCargo();
  16564. int iBestValue = 0;
  16565. CvPlot* pBestPlot = NULL;
  16566. CvPlot* pBestAssaultPlot = NULL;
  16567. for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  16568. {
  16569. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  16570. if (pLoopPlot->isRevealed(getTeam(), false) && pLoopPlot->isCoastalLand()) // K-Mod
  16571. {
  16572. if (pLoopPlot->isOwned())
  16573. {
  16574. //if (((bBarbarian || !pLoopPlot->isBarbarian())) || GET_PLAYER(getOwnerINLINE()).isMinorCiv())
  16575. //if (!(bBarbarian && pLoopPlot->isBarbarian()))
  16576. {
  16577. if (isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
  16578. {
  16579. int iTargetCities = pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE());
  16580. if (iTargetCities > 0)
  16581. {
  16582. bool bCanCargoAllUnload = true;
  16583. int iVisibleEnemyDefenders = pLoopPlot->getNumVisibleEnemyDefenders(this);
  16584. /************************************************************************************************/
  16585. /* BETTER_BTS_AI_MOD 11/30/08 jdog5000 */
  16586. /* */
  16587. /* Naval AI */
  16588. /************************************************************************************************/
  16589. if (iVisibleEnemyDefenders > 0 || pLoopPlot->isCity())
  16590. {
  16591. for (uint i = 0; i < aGroupCargo.size(); ++i)
  16592. {
  16593. CvUnit* pAttacker = aGroupCargo[i];
  16594. if( iVisibleEnemyDefenders > 0 )
  16595. {
  16596. CvUnit* pDefender = pLoopPlot->getBestDefender(NO_PLAYER, pAttacker->getOwnerINLINE(), pAttacker, true);
  16597. if (pDefender == NULL || !pAttacker->canAttack(*pDefender) || !pAttacker->isAmphib())
  16598. {
  16599. bCanCargoAllUnload = false;
  16600. break;
  16601. }
  16602. }
  16603. else if( pLoopPlot->isCity() && !(pLoopPlot->isVisible(getTeam(),false)) )
  16604. {
  16605. // Assume city is defended, artillery can't naval invade
  16606. if(( pAttacker->combatLimit() < 100 ) || !pAttacker->isAmphib())
  16607. {
  16608. bCanCargoAllUnload = false;
  16609. break;
  16610. }
  16611. }
  16612. }
  16613. }
  16614. /************************************************************************************************/
  16615. /* BETTER_BTS_AI_MOD END */
  16616. /************************************************************************************************/
  16617. if (bCanCargoAllUnload)
  16618. {
  16619. int iPathTurns;
  16620. /************************************************************************************************/
  16621. /* BETTER_BTS_AI_MOD 01/17/09 jdog5000 */
  16622. /* */
  16623. /* War tactics AI */
  16624. /************************************************************************************************/
  16625. /* original bts code
  16626. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  16627. */
  16628. if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
  16629. /************************************************************************************************/
  16630. /* BETTER_BTS_AI_MOD END */
  16631. /************************************************************************************************/
  16632. {
  16633. int iValue = 1;
  16634. if (!bIsAttackCity)
  16635. {
  16636. iValue += (AI_pillageValue(pLoopPlot, 15) * 10);
  16637. }
  16638. int iAssaultsHere = GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ASSAULT, getGroup());
  16639. iValue += (iAssaultsHere * 100);
  16640. CvCity* pCity = pLoopPlot->getPlotCity();
  16641. if (pCity == NULL)
  16642. {
  16643. for (int iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
  16644. {
  16645. CvPlot* pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iJ));
  16646. if (pAdjacentPlot != NULL)
  16647. {
  16648. pCity = pAdjacentPlot->getPlotCity();
  16649. if (pCity != NULL)
  16650. {
  16651. if (pCity->getOwnerINLINE() == pLoopPlot->getOwnerINLINE())
  16652. {
  16653. break;
  16654. }
  16655. else
  16656. {
  16657. pCity = NULL;
  16658. }
  16659. }
  16660. }
  16661. }
  16662. }
  16663. if (pCity != NULL)
  16664. {
  16665. FAssert(isPotentialEnemy(pCity->getTeam(), pLoopPlot));
  16666. if (!(pLoopPlot->isRiverCrossing(directionXY(pLoopPlot, pCity->plot()))))
  16667. {
  16668. iValue += (50 * -(GC.getRIVER_ATTACK_MODIFIER()));
  16669. }
  16670. iValue += 15 * (pLoopPlot->defenseModifier(getTeam(), false));
  16671. iValue += 1000;
  16672. iValue += (GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pCity->plot()) * 200);
  16673. /************************************************************************************************/
  16674. /* BETTER_BTS_AI_MOD 01/26/09 jdog5000 */
  16675. /* */
  16676. /* Naval AI */
  16677. /************************************************************************************************/
  16678. // Continue attacking in area we have already captured cities
  16679. if( pCity->area()->getCitiesPerPlayer(getOwnerINLINE()) > 0 )
  16680. {
  16681. if( pCity->AI_playerCloseness(getOwnerINLINE()) > 5 )
  16682. {
  16683. iValue *= 3;
  16684. iValue /= 2;
  16685. }
  16686. }
  16687. /************************************************************************************************/
  16688. /* BETTER_BTS_AI_MOD END */
  16689. /************************************************************************************************/
  16690. if (iPathTurns == 1)
  16691. {
  16692. iValue += GC.getGameINLINE().getSorenRandNum(50, "AI Assault");
  16693. }
  16694. }
  16695. FAssert(iPathTurns > 0);
  16696. if (iPathTurns == 1)
  16697. {
  16698. if (pCity != NULL)
  16699. {
  16700. if (pCity->area()->getNumCities() > 1)
  16701. {
  16702. iValue *= 2;
  16703. }
  16704. }
  16705. }
  16706. iValue *= 1000;
  16707. if (iTargetCities <= iAssaultsHere)
  16708. {
  16709. iValue /= 2;
  16710. }
  16711. if (iTargetCities == 1)
  16712. {
  16713. if (iCargo > 7)
  16714. {
  16715. iValue *= 3;
  16716. iValue /= iCargo - 4;
  16717. }
  16718. }
  16719. if (pLoopPlot->isCity())
  16720. {
  16721. if (iVisibleEnemyDefenders * 3 > iCargo)
  16722. {
  16723. iValue /= 10;
  16724. }
  16725. else
  16726. {
  16727. /************************************************************************************************/
  16728. /* BETTER_BTS_AI_MOD 11/30/08 jdog5000 */
  16729. /* */
  16730. /* Naval AI */
  16731. /************************************************************************************************/
  16732. /*
  16733. // original bts code
  16734. iValue *= iCargo;
  16735. iValue /= std::max(1, (iVisibleEnemyDefenders * 3));
  16736. */
  16737. // Assume non-visible city is properly defended
  16738. iValue *= (iCargo / 2);
  16739. iValue /= std::max(pLoopPlot->getPlotCity()->AI_neededDefenders(), (iVisibleEnemyDefenders * 3));
  16740. /************************************************************************************************/
  16741. /* BETTER_BTS_AI_MOD END */
  16742. /************************************************************************************************/
  16743. }
  16744. }
  16745. else
  16746. {
  16747. if (0 == iVisibleEnemyDefenders)
  16748. {
  16749. iValue *= 4;
  16750. iValue /= 3;
  16751. }
  16752. else
  16753. {
  16754. iValue /= iVisibleEnemyDefenders;
  16755. }
  16756. }
  16757. // if more than 3 turns to get there, then put some randomness into our preference of distance
  16758. // +/- 33%
  16759. if (iPathTurns > 3)
  16760. {
  16761. int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");
  16762. iPathTurns *= 66 + iPathAdjustment;
  16763. iPathTurns /= 100;
  16764. }
  16765. iValue /= (iPathTurns + 1);
  16766. if (iValue > iBestValue)
  16767. {
  16768. iBestValue = iValue;
  16769. pBestPlot = getPathEndTurnPlot();
  16770. pBestAssaultPlot = pLoopPlot;
  16771. }
  16772. }
  16773. }
  16774. }
  16775. }
  16776. }
  16777. }
  16778. }
  16779. }
  16780. if ((pBestPlot != NULL) && (pBestAssaultPlot != NULL))
  16781. {
  16782. FAssert(!(pBestPlot->isImpassable()));
  16783. // BETTER_BTS_AI_MOD - War tactics AI
  16784. // Cancel missions of all those coming to join departing transport
  16785. CvSelectionGroup* pLoopGroup = NULL;
  16786. int iLoop = 0;
  16787. CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
  16788. for(pLoopGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = kPlayer.nextSelectionGroup(&iLoop))
  16789. {
  16790. if( pLoopGroup != getGroup() )
  16791. {
  16792. if( pLoopGroup->AI_getMissionAIType() == MISSIONAI_GROUP && pLoopGroup->getHeadUnitAI() == AI_getUnitAIType() )
  16793. {
  16794. CvUnit* pMissionUnit = pLoopGroup->AI_getMissionAIUnit();
  16795. if( pMissionUnit != NULL && pMissionUnit->getGroup() == getGroup() )
  16796. {
  16797. pLoopGroup->clearMissionQueue();
  16798. }
  16799. }
  16800. }
  16801. }
  16802. // BETTER_BTS_AI_MOD END
  16803. //if ((pBestPlot == pBestAssaultPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE()) == 1))
  16804. if (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE()) == 1)
  16805. {
  16806. if (atPlot(pBestAssaultPlot))
  16807. {
  16808. logBBAI(" ...unloading at %d, %d", pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE());
  16809. getGroup()->unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
  16810. return true;
  16811. }
  16812. else
  16813. {
  16814. // BETTER_BTS_AI_MOD - War tactics AI
  16815. /* original bts code
  16816. getGroup()->pushMission(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), 0, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
  16817. */
  16818. if( gUnitLogLevel >= 4 ) logBBAI(" ...moving to assault %d, %d", pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE());
  16819. getGroup()->pushMission(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
  16820. // BETTER_BTS_AI_MOD END
  16821. return true;
  16822. }
  16823. }
  16824. else
  16825. {
  16826. FAssert(!atPlot(pBestPlot));
  16827. // BETTER_BTS_AI_MOD - War tactics AI
  16828. /* original bts code
  16829. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
  16830. */
  16831. //getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
  16832. getGroup()->pushMission(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
  16833. // BETTER_BTS_AI_MOD END
  16834. return true;
  16835. }
  16836. }
  16837. if( gUnitLogLevel >= 4 ) logBBAI(" ...failing assault sea transport check");
  16838. return false;
  16839. }
  16840. /************************************************************************************************/
  16841. /* BETTER_BTS_AI_MOD 02/07/10 jdog5000 */
  16842. /* */
  16843. /* Naval AI, Efficiency */
  16844. /************************************************************************************************/
  16845. // Returns true if a mission was pushed...
  16846. bool CvUnitAI::AI_assaultSeaReinforce(bool bBarbarian)
  16847. {
  16848. PROFILE_FUNC();
  16849. bool bIsAttackCity = (getUnitAICargo(UNITAI_ATTACK_CITY) > 0);
  16850. FAssert(getGroup()->hasCargo());
  16851. if (!canCargoAllMove())
  16852. {
  16853. return false;
  16854. }
  16855. if( !(getGroup()->canAllMove()) )
  16856. {
  16857. return false;
  16858. }
  16859. std::vector<CvUnit*> aGroupCargo;
  16860. CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode();
  16861. while (pUnitNode != NULL)
  16862. {
  16863. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  16864. pUnitNode = plot()->nextUnitNode(pUnitNode);
  16865. CvUnit* pTransport = pLoopUnit->getTransportUnit();
  16866. if (pTransport != NULL && pTransport->getGroup() == getGroup())
  16867. {
  16868. aGroupCargo.push_back(pLoopUnit);
  16869. }
  16870. }
  16871. int iCargo = getGroup()->getCargo();
  16872. int iBestValue = 0;
  16873. CvPlot* pBestPlot = NULL;
  16874. CvPlot* pBestAssaultPlot = NULL;
  16875. CvArea* pWaterArea = plot()->waterArea();
  16876. bool bCity = plot()->isCity(true,getTeam());
  16877. bool bCanMoveAllTerrain = getGroup()->canMoveAllTerrain();
  16878. int iTargetCities;
  16879. int iOurFightersHere;
  16880. int iPathTurns;
  16881. int iValue;
  16882. if( gUnitLogLevel >= 2 )
  16883. {
  16884. logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_assaultSeaReinforce", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  16885. }
  16886. // Loop over nearby plots for groups in enemy territory to reinforce
  16887. int iRange = 2*baseMoves();
  16888. int iDX, iDY;
  16889. for (iDX = -(iRange); iDX <= iRange; iDX++)
  16890. {
  16891. for (iDY = -(iRange); iDY <= iRange; iDY++)
  16892. {
  16893. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  16894. if( pLoopPlot != NULL )
  16895. {
  16896. if (pLoopPlot->isOwned())
  16897. {
  16898. if (isEnemy(pLoopPlot->getTeam(), pLoopPlot))
  16899. {
  16900. if ( bCanMoveAllTerrain || (pWaterArea != NULL && pLoopPlot->isAdjacentToArea(pWaterArea)) )
  16901. {
  16902. iTargetCities = pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE());
  16903. if (iTargetCities > 0)
  16904. {
  16905. iOurFightersHere = pLoopPlot->getNumDefenders(getOwnerINLINE());
  16906. if( iOurFightersHere > 2 )
  16907. {
  16908. iPathTurns;
  16909. if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
  16910. {
  16911. if( iPathTurns <= 2 )
  16912. {
  16913. CvPlot* pEndTurnPlot = getPathEndTurnPlot();
  16914. iValue = 10*iTargetCities;
  16915. iValue += 8*iOurFightersHere;
  16916. iValue += 3*GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);
  16917. iValue *= 100;
  16918. iValue /= (iPathTurns + 1);
  16919. if (iValue > iBestValue)
  16920. {
  16921. iBestValue = iValue;
  16922. pBestPlot = pEndTurnPlot;
  16923. pBestAssaultPlot = pLoopPlot;
  16924. }
  16925. }
  16926. }
  16927. }
  16928. }
  16929. }
  16930. }
  16931. }
  16932. }
  16933. }
  16934. }
  16935. // Loop over other transport groups, looking for synchronized landing
  16936. if ((pBestPlot == NULL) && (pBestAssaultPlot == NULL))
  16937. {
  16938. int iLoop;
  16939. for(CvSelectionGroup* pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).firstSelectionGroup(&iLoop); pLoopSelectionGroup; pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).nextSelectionGroup(&iLoop))
  16940. {
  16941. if (pLoopSelectionGroup != getGroup())
  16942. {
  16943. if (pLoopSelectionGroup->AI_getMissionAIType() == MISSIONAI_ASSAULT)
  16944. {
  16945. CvPlot* pLoopPlot = pLoopSelectionGroup->AI_getMissionAIPlot();
  16946. if( pLoopPlot != NULL )
  16947. {
  16948. if (pLoopPlot->isOwned())
  16949. {
  16950. if (isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
  16951. {
  16952. if ( bCanMoveAllTerrain || (pWaterArea != NULL && pLoopPlot->isAdjacentToArea(pWaterArea)) )
  16953. {
  16954. iTargetCities = pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE());
  16955. if (iTargetCities > 0)
  16956. {
  16957. int iAssaultsHere = pLoopSelectionGroup->getCargo();
  16958. if( iAssaultsHere > 2 )
  16959. {
  16960. iPathTurns;
  16961. if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
  16962. {
  16963. CvPlot* pEndTurnPlot = getPathEndTurnPlot();
  16964. int iOtherPathTurns = MAX_INT;
  16965. if (pLoopSelectionGroup->generatePath(pLoopSelectionGroup->plot(), pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iOtherPathTurns))
  16966. {
  16967. // We need to get there the turn after they do, +1 required whether
  16968. // they move first or we do
  16969. iOtherPathTurns += 1;
  16970. }
  16971. else
  16972. {
  16973. // Should never happen ...
  16974. continue;
  16975. }
  16976. if( (iPathTurns >= iOtherPathTurns) && (iPathTurns < iOtherPathTurns + 5) )
  16977. {
  16978. bool bCanCargoAllUnload = true;
  16979. int iVisibleEnemyDefenders = pLoopPlot->getNumVisibleEnemyDefenders(this);
  16980. if (iVisibleEnemyDefenders > 0 || pLoopPlot->isCity())
  16981. {
  16982. for (uint i = 0; i < aGroupCargo.size(); ++i)
  16983. {
  16984. CvUnit* pAttacker = aGroupCargo[i];
  16985. CvUnit* pDefender = pLoopPlot->getBestDefender(NO_PLAYER, pAttacker->getOwnerINLINE(), pAttacker, true);
  16986. if (pDefender == NULL || !pAttacker->canAttack(*pDefender))
  16987. {
  16988. bCanCargoAllUnload = false;
  16989. break;
  16990. }
  16991. else if( pLoopPlot->isCity() && !(pLoopPlot->isVisible(getTeam(),false)) )
  16992. {
  16993. // Artillery can't naval invade, so don't try
  16994. if( pAttacker->combatLimit() < 100 )
  16995. {
  16996. bCanCargoAllUnload = false;
  16997. break;
  16998. }
  16999. }
  17000. }
  17001. }
  17002. iValue = (iAssaultsHere * 5);
  17003. iValue += iTargetCities*10;
  17004. iValue *= 100;
  17005. // if more than 3 turns to get there, then put some randomness into our preference of distance
  17006. // +/- 33%
  17007. if (iPathTurns > 3)
  17008. {
  17009. int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");
  17010. iPathTurns *= 66 + iPathAdjustment;
  17011. iPathTurns /= 100;
  17012. }
  17013. iValue /= (iPathTurns + 1);
  17014. if (iValue > iBestValue)
  17015. {
  17016. iBestValue = iValue;
  17017. pBestPlot = pEndTurnPlot;
  17018. pBestAssaultPlot = pLoopPlot;
  17019. }
  17020. }
  17021. }
  17022. }
  17023. }
  17024. }
  17025. }
  17026. }
  17027. }
  17028. }
  17029. }
  17030. }
  17031. }
  17032. // Reinforce our cities in need
  17033. if ((pBestPlot == NULL) && (pBestAssaultPlot == NULL))
  17034. {
  17035. int iLoop;
  17036. CvCity* pLoopCity;
  17037. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  17038. {
  17039. if( bCanMoveAllTerrain || (pWaterArea != NULL && (pLoopCity->waterArea(true) == pWaterArea || pLoopCity->secondWaterArea() == pWaterArea)) )
  17040. {
  17041. iValue = 0;
  17042. if(pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE)
  17043. {
  17044. iValue = 3;
  17045. }
  17046. else if(pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
  17047. {
  17048. iValue = 2;
  17049. }
  17050. else if(pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_MASSING)
  17051. {
  17052. iValue = 1;
  17053. }
  17054. else if( bBarbarian && (pLoopCity->area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0) )
  17055. {
  17056. iValue = 1;
  17057. }
  17058. if( iValue > 0 )
  17059. {
  17060. bool bCityDanger = pLoopCity->AI_isDanger();
  17061. if( (bCity && pLoopCity->area() != area()) || bCityDanger || ((GC.getGameINLINE().getGameTurn() - pLoopCity->getGameTurnAcquired()) < 10 && pLoopCity->getPreviousOwner() != NO_PLAYER) )
  17062. {
  17063. int iOurPower = std::max(1, pLoopCity->area()->getPower(getOwnerINLINE()));
  17064. // Enemy power includes barb power
  17065. int iEnemyPower = GET_TEAM(getTeam()).countEnemyPowerByArea(pLoopCity->area());
  17066. // Don't send troops to areas we are dominating already
  17067. // Don't require presence of enemy cities, just a dangerous force
  17068. if( iOurPower < (3*iEnemyPower) )
  17069. {
  17070. iPathTurns;
  17071. if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
  17072. {
  17073. iValue *= 10*pLoopCity->AI_cityThreat();
  17074. iValue += 20 * GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ASSAULT, getGroup());
  17075. iValue *= std::min(iEnemyPower, 3*iOurPower);
  17076. iValue /= iOurPower;
  17077. iValue *= 100;
  17078. // if more than 3 turns to get there, then put some randomness into our preference of distance
  17079. // +/- 33%
  17080. if (iPathTurns > 3)
  17081. {
  17082. int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");
  17083. iPathTurns *= 66 + iPathAdjustment;
  17084. iPathTurns /= 100;
  17085. }
  17086. iValue /= (iPathTurns + 6);
  17087. if (iValue > iBestValue)
  17088. {
  17089. iBestValue = iValue;
  17090. pBestPlot = (bCityDanger ? getPathEndTurnPlot() : pLoopCity->plot());
  17091. pBestAssaultPlot = pLoopCity->plot();
  17092. }
  17093. }
  17094. }
  17095. }
  17096. }
  17097. }
  17098. }
  17099. }
  17100. if ((pBestPlot == NULL) && (pBestAssaultPlot == NULL))
  17101. {
  17102. if( bCity )
  17103. {
  17104. if( GET_TEAM(getTeam()).isAVassal() )
  17105. {
  17106. TeamTypes eMasterTeam = NO_TEAM;
  17107. for( int iI = 0; iI < MAX_CIV_TEAMS; iI++ )
  17108. {
  17109. if( GET_TEAM(getTeam()).isVassal((TeamTypes)iI) )
  17110. {
  17111. eMasterTeam = (TeamTypes)iI;
  17112. }
  17113. }
  17114. if( (eMasterTeam != NO_TEAM) && GET_TEAM(getTeam()).isOpenBorders(eMasterTeam) )
  17115. {
  17116. for( int iI = 0; iI < MAX_CIV_PLAYERS; iI++ )
  17117. {
  17118. if( GET_PLAYER((PlayerTypes)iI).getTeam() == eMasterTeam )
  17119. {
  17120. int iLoop;
  17121. CvCity* pLoopCity;
  17122. for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
  17123. {
  17124. if( pLoopCity->area() != area() )
  17125. {
  17126. iValue = 0;
  17127. if(pLoopCity->area()->getAreaAIType(eMasterTeam) == AREAAI_OFFENSIVE)
  17128. {
  17129. iValue = 2;
  17130. }
  17131. else if(pLoopCity->area()->getAreaAIType(eMasterTeam) == AREAAI_MASSING)
  17132. {
  17133. iValue = 1;
  17134. }
  17135. if( iValue > 0 )
  17136. {
  17137. if( bCanMoveAllTerrain || (pWaterArea != NULL && (pLoopCity->waterArea(true) == pWaterArea || pLoopCity->secondWaterArea() == pWaterArea)) )
  17138. {
  17139. int iOurPower = std::max(1, pLoopCity->area()->getPower(getOwnerINLINE()));
  17140. iOurPower += GET_TEAM(eMasterTeam).countPowerByArea(pLoopCity->area());
  17141. // Enemy power includes barb power
  17142. int iEnemyPower = GET_TEAM(eMasterTeam).countEnemyPowerByArea(pLoopCity->area());
  17143. // Don't send troops to areas we are dominating already
  17144. // Don't require presence of enemy cities, just a dangerous force
  17145. if( iOurPower < (2*iEnemyPower) )
  17146. {
  17147. int iPathTurns;
  17148. if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
  17149. {
  17150. iValue *= pLoopCity->AI_cityThreat();
  17151. iValue += 10 * GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ASSAULT, getGroup());
  17152. iValue *= std::min(iEnemyPower, 3*iOurPower);
  17153. iValue /= iOurPower;
  17154. iValue *= 100;
  17155. // if more than 3 turns to get there, then put some randomness into our preference of distance
  17156. // +/- 33%
  17157. if (iPathTurns > 3)
  17158. {
  17159. int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");
  17160. iPathTurns *= 66 + iPathAdjustment;
  17161. iPathTurns /= 100;
  17162. }
  17163. iValue /= (iPathTurns + 1);
  17164. if (iValue > iBestValue)
  17165. {
  17166. iBestValue = iValue;
  17167. pBestPlot = getPathEndTurnPlot();
  17168. pBestAssaultPlot = pLoopCity->plot();
  17169. }
  17170. }
  17171. }
  17172. }
  17173. }
  17174. }
  17175. }
  17176. }
  17177. }
  17178. }
  17179. }
  17180. }
  17181. }
  17182. if ((pBestPlot != NULL) && (pBestAssaultPlot != NULL))
  17183. {
  17184. FAssert(!(pBestPlot->isImpassable()));
  17185. // Cancel missions of all those coming to join departing transport
  17186. CvSelectionGroup* pLoopGroup = NULL;
  17187. int iLoop = 0;
  17188. CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
  17189. for(pLoopGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = kPlayer.nextSelectionGroup(&iLoop))
  17190. {
  17191. if( pLoopGroup != getGroup() )
  17192. {
  17193. if( pLoopGroup->AI_getMissionAIType() == MISSIONAI_GROUP && pLoopGroup->getHeadUnitAI() == AI_getUnitAIType() )
  17194. {
  17195. CvUnit* pMissionUnit = pLoopGroup->AI_getMissionAIUnit();
  17196. if( pMissionUnit != NULL && pMissionUnit->getGroup() == getGroup() )
  17197. {
  17198. pLoopGroup->clearMissionQueue();
  17199. }
  17200. }
  17201. }
  17202. }
  17203. if ((pBestPlot == pBestAssaultPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE()) == 1))
  17204. {
  17205. if (atPlot(pBestAssaultPlot))
  17206. {
  17207. getGroup()->unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
  17208. return true;
  17209. }
  17210. else
  17211. {
  17212. getGroup()->pushMission(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
  17213. return true;
  17214. }
  17215. }
  17216. else
  17217. {
  17218. FAssert(!atPlot(pBestPlot));
  17219. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
  17220. return true;
  17221. }
  17222. }
  17223. return false;
  17224. }
  17225. /************************************************************************************************/
  17226. /* BETTER_BTS_AI_MOD END */
  17227. /************************************************************************************************/
  17228. // Returns true if a mission was pushed...
  17229. bool CvUnitAI::AI_settlerSeaTransport()
  17230. {
  17231. PROFILE_FUNC();
  17232. CLLNode<IDInfo>* pUnitNode;
  17233. CvUnit* pLoopUnit;
  17234. CvPlot* pLoopPlot;
  17235. CvPlot* pPlot;
  17236. CvPlot* pBestPlot;
  17237. CvPlot* pBestFoundPlot;
  17238. CvArea* pWaterArea;
  17239. bool bValid;
  17240. int iValue;
  17241. int iBestValue;
  17242. int iI;
  17243. FAssert(getCargo() > 0);
  17244. FAssert(getUnitAICargo(UNITAI_SETTLE) > 0);
  17245. if (!canCargoAllMove())
  17246. {
  17247. return false;
  17248. }
  17249. if (gUnitLogLevel >= 2)
  17250. {
  17251. logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_settlerSeaTransport", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  17252. }
  17253. //New logic should allow some new tricks like
  17254. //unloading settlers when a better site opens up locally
  17255. //and delivering settlers
  17256. //to inland sites
  17257. pWaterArea = plot()->waterArea();
  17258. FAssertMsg(pWaterArea != NULL, "Ship out of water?");
  17259. CvUnit* pSettlerUnit = NULL;
  17260. pPlot = plot();
  17261. pUnitNode = pPlot->headUnitNode();
  17262. while (pUnitNode != NULL)
  17263. {
  17264. pLoopUnit = ::getUnit(pUnitNode->m_data);
  17265. pUnitNode = pPlot->nextUnitNode(pUnitNode);
  17266. if (pLoopUnit->getTransportUnit() == this)
  17267. {
  17268. if (pLoopUnit->AI_getUnitAIType() == UNITAI_SETTLE)
  17269. {
  17270. pSettlerUnit = pLoopUnit;
  17271. break;
  17272. }
  17273. }
  17274. }
  17275. FAssert(pSettlerUnit != NULL);
  17276. int iAreaBestFoundValue = 0;
  17277. CvPlot* pAreaBestPlot = NULL;
  17278. int iOtherAreaBestFoundValue = 0;
  17279. CvPlot* pOtherAreaBestPlot = NULL;
  17280. for (iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
  17281. {
  17282. CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
  17283. int iPathTurns;
  17284. if (generatePath(pCitySitePlot, 0, true, &iPathTurns))
  17285. {
  17286. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_FOUND, getGroup()) == 0)
  17287. {
  17288. iValue = pCitySitePlot->getFoundValue(getOwnerINLINE());
  17289. if( gUnitLogLevel >= 4 ) logBBAI("...city plot %d, %d valued at %d", pCitySitePlot->getX(), pCitySitePlot->getY(), iValue);
  17290. /*************************************************************************************************/
  17291. /** BETTER_BTS_AI_MOD merged Sephi 0.41k 01/13/09 jdog5000 */
  17292. /** */
  17293. /** Settler AI */
  17294. /*************************************************************************************************/
  17295. // if (pCitySitePlot->getArea() == getArea())
  17296. // {
  17297. // if (iValue > iAreaBestFoundValue)
  17298. // {
  17299. // Only count city sites we can get to
  17300. if (pCitySitePlot->getArea() == getArea() && pSettlerUnit->generatePath(pCitySitePlot, MOVE_SAFE_TERRITORY, true))
  17301. {
  17302. if (iValue > iAreaBestFoundValue)
  17303. {
  17304. /*************************************************************************************************/
  17305. /** BETTER_BTS_AI_MOD END */
  17306. /*************************************************************************************************/
  17307. iAreaBestFoundValue = iValue;
  17308. pAreaBestPlot = pCitySitePlot;
  17309. }
  17310. }
  17311. else
  17312. {
  17313. if (iValue > iOtherAreaBestFoundValue)
  17314. {
  17315. iOtherAreaBestFoundValue = iValue;
  17316. pOtherAreaBestPlot = pCitySitePlot;
  17317. }
  17318. }
  17319. }
  17320. }
  17321. }
  17322. if ((0 == iAreaBestFoundValue) && (0 == iOtherAreaBestFoundValue))
  17323. {
  17324. return false;
  17325. }
  17326. if (iAreaBestFoundValue > iOtherAreaBestFoundValue)
  17327. {
  17328. //let the settler walk.
  17329. getGroup()->unloadAll();
  17330. getGroup()->pushMission(MISSION_SKIP);
  17331. return true;
  17332. }
  17333. if (iOtherAreaBestFoundValue > 0)
  17334. {
  17335. getGroup()->pushMission(MISSION_MOVE_TO, pOtherAreaBestPlot->getX_INLINE(), pOtherAreaBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pOtherAreaBestPlot);
  17336. return true;
  17337. }
  17338. iBestValue = 0;
  17339. pBestPlot = NULL;
  17340. pBestFoundPlot = NULL;
  17341. for (iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
  17342. {
  17343. CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
  17344. if (!(pCitySitePlot->isVisibleEnemyUnit(this)))
  17345. {
  17346. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_FOUND, getGroup(), 4) == 0)
  17347. {
  17348. int iPathTurns;
  17349. if (generatePath(pCitySitePlot, 0, true, &iPathTurns))
  17350. {
  17351. iValue = pCitySitePlot->getFoundValue(getOwnerINLINE());
  17352. if (iValue >= GET_PLAYER(getOwnerINLINE()).AI_getMinFoundValue())
  17353. {
  17354. iValue *= 1000;
  17355. iValue /= (2 + iPathTurns);
  17356. if (iValue > iBestValue)
  17357. {
  17358. iBestValue = iValue;
  17359. pBestPlot = getPathEndTurnPlot();
  17360. pBestFoundPlot = pCitySitePlot;
  17361. }
  17362. }
  17363. }
  17364. }
  17365. }
  17366. }
  17367. if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
  17368. {
  17369. FAssert(!(pBestPlot->isImpassable()));
  17370. if ((pBestPlot == pBestFoundPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE()) == 1))
  17371. {
  17372. if (atPlot(pBestFoundPlot))
  17373. {
  17374. unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
  17375. return true;
  17376. }
  17377. else
  17378. {
  17379. getGroup()->pushMission(MISSION_MOVE_TO, pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
  17380. return true;
  17381. }
  17382. }
  17383. else
  17384. {
  17385. FAssert(!atPlot(pBestPlot));
  17386. getGroup()->pushMission(MISSION_MOVE_TO, pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
  17387. return true;
  17388. }
  17389. }
  17390. //Try original logic
  17391. //(sometimes new logic breaks)
  17392. pPlot = plot();
  17393. iBestValue = 0;
  17394. pBestPlot = NULL;
  17395. pBestFoundPlot = NULL;
  17396. int iMinFoundValue = GET_PLAYER(getOwnerINLINE()).AI_getMinFoundValue();
  17397. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  17398. {
  17399. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  17400. if (pLoopPlot->isCoastalLand())
  17401. {
  17402. iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
  17403. if ((iValue > iBestValue) && (iValue >= iMinFoundValue))
  17404. {
  17405. bValid = false;
  17406. pUnitNode = pPlot->headUnitNode();
  17407. while (pUnitNode != NULL)
  17408. {
  17409. pLoopUnit = ::getUnit(pUnitNode->m_data);
  17410. pUnitNode = pPlot->nextUnitNode(pUnitNode);
  17411. if (pLoopUnit->getTransportUnit() == this)
  17412. {
  17413. if (pLoopUnit->canFound(pLoopPlot))
  17414. {
  17415. bValid = true;
  17416. break;
  17417. }
  17418. }
  17419. }
  17420. if (bValid)
  17421. {
  17422. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  17423. {
  17424. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_FOUND, getGroup(), 4) == 0)
  17425. {
  17426. if (generatePath(pLoopPlot, 0, true))
  17427. {
  17428. iBestValue = iValue;
  17429. pBestPlot = getPathEndTurnPlot();
  17430. pBestFoundPlot = pLoopPlot;
  17431. }
  17432. }
  17433. }
  17434. }
  17435. }
  17436. }
  17437. }
  17438. if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
  17439. {
  17440. FAssert(!(pBestPlot->isImpassable()));
  17441. if ((pBestPlot == pBestFoundPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE()) == 1))
  17442. {
  17443. if (atPlot(pBestFoundPlot))
  17444. {
  17445. unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
  17446. return true;
  17447. }
  17448. else
  17449. {
  17450. getGroup()->pushMission(MISSION_MOVE_TO, pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
  17451. return true;
  17452. }
  17453. }
  17454. else
  17455. {
  17456. FAssert(!atPlot(pBestPlot));
  17457. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
  17458. return true;
  17459. }
  17460. }
  17461. return false;
  17462. }
  17463. // Returns true if a mission was pushed...
  17464. bool CvUnitAI::AI_settlerSeaFerry()
  17465. {
  17466. PROFILE_FUNC();
  17467. FAssert(getCargo() > 0);
  17468. FAssert(getUnitAICargo(UNITAI_WORKER) > 0);
  17469. if (!canCargoAllMove())
  17470. {
  17471. return false;
  17472. }
  17473. CvArea* pWaterArea = plot()->waterArea();
  17474. FAssertMsg(pWaterArea != NULL, "Ship out of water?");
  17475. int iBestValue = 0;
  17476. CvPlot* pBestPlot = NULL;
  17477. CvCity* pLoopCity;
  17478. int iLoop;
  17479. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  17480. {
  17481. int iValue = pLoopCity->AI_getWorkersNeeded();
  17482. if (iValue > 0)
  17483. {
  17484. iValue -= GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_FOUND, getGroup());
  17485. if (iValue > 0)
  17486. {
  17487. int iPathTurns;
  17488. if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  17489. {
  17490. iValue += std::max(0, (GET_PLAYER(getOwnerINLINE()).AI_neededWorkers(pLoopCity->area()) - GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), UNITAI_WORKER)));
  17491. iValue *= 1000;
  17492. iValue /= 4 + iPathTurns;
  17493. if (atPlot(pLoopCity->plot()))
  17494. {
  17495. iValue += 100;
  17496. }
  17497. else
  17498. {
  17499. iValue += GC.getGame().getSorenRandNum(100, "AI settler sea ferry");
  17500. }
  17501. if (iValue > iBestValue)
  17502. {
  17503. iBestValue = iValue;
  17504. pBestPlot = pLoopCity->plot();
  17505. }
  17506. }
  17507. }
  17508. }
  17509. }
  17510. if (pBestPlot != NULL)
  17511. {
  17512. if (atPlot(pBestPlot))
  17513. {
  17514. unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
  17515. return true;
  17516. }
  17517. else
  17518. {
  17519. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestPlot);
  17520. return true;
  17521. }
  17522. }
  17523. return false;
  17524. }
  17525. // Returns true if a mission was pushed...
  17526. bool CvUnitAI::AI_specialSeaTransportMissionary()
  17527. {
  17528. //PROFILE_FUNC();
  17529. CLLNode<IDInfo>* pUnitNode;
  17530. CvCity* pCity;
  17531. CvUnit* pMissionaryUnit;
  17532. CvUnit* pLoopUnit;
  17533. CvPlot* pLoopPlot;
  17534. CvPlot* pPlot;
  17535. CvPlot* pBestPlot;
  17536. CvPlot* pBestSpreadPlot;
  17537. int iPathTurns;
  17538. int iValue;
  17539. int iCorpValue;
  17540. int iBestValue;
  17541. int iI, iJ;
  17542. bool bExecutive = false;
  17543. FAssert(getCargo() > 0);
  17544. FAssert(getUnitAICargo(UNITAI_MISSIONARY) > 0);
  17545. if (!canCargoAllMove())
  17546. {
  17547. return false;
  17548. }
  17549. pPlot = plot();
  17550. pMissionaryUnit = NULL;
  17551. pUnitNode = pPlot->headUnitNode();
  17552. while (pUnitNode != NULL)
  17553. {
  17554. pLoopUnit = ::getUnit(pUnitNode->m_data);
  17555. pUnitNode = pPlot->nextUnitNode(pUnitNode);
  17556. if (pLoopUnit->getTransportUnit() == this)
  17557. {
  17558. if (pLoopUnit->AI_getUnitAIType() == UNITAI_MISSIONARY)
  17559. {
  17560. pMissionaryUnit = pLoopUnit;
  17561. break;
  17562. }
  17563. }
  17564. }
  17565. if (pMissionaryUnit == NULL)
  17566. {
  17567. return false;
  17568. }
  17569. iBestValue = 0;
  17570. pBestPlot = NULL;
  17571. pBestSpreadPlot = NULL;
  17572. // XXX what about non-coastal cities?
  17573. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  17574. {
  17575. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  17576. if (pLoopPlot->isCoastalLand())
  17577. {
  17578. pCity = pLoopPlot->getPlotCity();
  17579. if (pCity != NULL)
  17580. {
  17581. iValue = 0;
  17582. iCorpValue = 0;
  17583. for (iJ = 0; iJ < GC.getNumReligionInfos(); iJ++)
  17584. {
  17585. if (pMissionaryUnit->canSpread(pLoopPlot, ((ReligionTypes)iJ)))
  17586. {
  17587. if (GET_PLAYER(getOwnerINLINE()).getStateReligion() == ((ReligionTypes)iJ))
  17588. {
  17589. iValue += 3;
  17590. }
  17591. if (GET_PLAYER(getOwnerINLINE()).hasHolyCity((ReligionTypes)iJ))
  17592. {
  17593. iValue++;
  17594. }
  17595. }
  17596. }
  17597. for (iJ = 0; iJ < GC.getNumCorporationInfos(); iJ++)
  17598. {
  17599. if (pMissionaryUnit->canSpreadCorporation(pLoopPlot, ((CorporationTypes)iJ)))
  17600. {
  17601. if (GET_PLAYER(getOwnerINLINE()).hasHeadquarters((CorporationTypes)iJ))
  17602. {
  17603. iCorpValue += 3;
  17604. }
  17605. }
  17606. }
  17607. if (iValue > 0)
  17608. {
  17609. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  17610. {
  17611. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_SPREAD, getGroup()) == 0)
  17612. {
  17613. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  17614. {
  17615. iValue *= pCity->getPopulation();
  17616. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  17617. {
  17618. iValue *= 4;
  17619. }
  17620. else if (pCity->getTeam() == getTeam())
  17621. {
  17622. iValue *= 3;
  17623. }
  17624. if (pCity->getReligionCount() == 0)
  17625. {
  17626. iValue *= 2;
  17627. }
  17628. iValue /= (pCity->getReligionCount() + 1);
  17629. FAssert(iPathTurns > 0);
  17630. if (iPathTurns == 1)
  17631. {
  17632. iValue *= 2;
  17633. }
  17634. iValue *= 1000;
  17635. iValue /= (iPathTurns + 1);
  17636. if (iValue > iBestValue)
  17637. {
  17638. iBestValue = iValue;
  17639. pBestPlot = getPathEndTurnPlot();
  17640. pBestSpreadPlot = pLoopPlot;
  17641. bExecutive = false;
  17642. }
  17643. }
  17644. }
  17645. }
  17646. }
  17647. if (iCorpValue > 0)
  17648. {
  17649. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  17650. {
  17651. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_SPREAD_CORPORATION, getGroup()) == 0)
  17652. {
  17653. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  17654. {
  17655. iCorpValue *= pCity->getPopulation();
  17656. FAssert(iPathTurns > 0);
  17657. if (iPathTurns == 1)
  17658. {
  17659. /************************************************************************************************/
  17660. /* UNOFFICIAL_PATCH 02/22/10 jdog5000 */
  17661. /* */
  17662. /* Bugfix */
  17663. /************************************************************************************************/
  17664. /* original bts code
  17665. iValue *= 2;
  17666. */
  17667. iCorpValue *= 2;
  17668. /************************************************************************************************/
  17669. /* UNOFFICIAL_PATCH END */
  17670. /************************************************************************************************/
  17671. }
  17672. iCorpValue *= 1000;
  17673. iCorpValue /= (iPathTurns + 1);
  17674. if (iCorpValue > iBestValue)
  17675. {
  17676. iBestValue = iCorpValue;
  17677. pBestPlot = getPathEndTurnPlot();
  17678. pBestSpreadPlot = pLoopPlot;
  17679. bExecutive = true;
  17680. }
  17681. }
  17682. }
  17683. }
  17684. }
  17685. }
  17686. }
  17687. }
  17688. if ((pBestPlot != NULL) && (pBestSpreadPlot != NULL))
  17689. {
  17690. FAssert(!(pBestPlot->isImpassable()) || canMoveImpassable());
  17691. if ((pBestPlot == pBestSpreadPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestSpreadPlot->getX_INLINE(), pBestSpreadPlot->getY_INLINE()) == 1))
  17692. {
  17693. if (atPlot(pBestSpreadPlot))
  17694. {
  17695. unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
  17696. return true;
  17697. }
  17698. else
  17699. {
  17700. getGroup()->pushMission(MISSION_MOVE_TO, pBestSpreadPlot->getX_INLINE(), pBestSpreadPlot->getY_INLINE(), 0, false, false, bExecutive ? MISSIONAI_SPREAD_CORPORATION : MISSIONAI_SPREAD, pBestSpreadPlot);
  17701. return true;
  17702. }
  17703. }
  17704. else
  17705. {
  17706. FAssert(!atPlot(pBestPlot));
  17707. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, bExecutive ? MISSIONAI_SPREAD_CORPORATION : MISSIONAI_SPREAD, pBestSpreadPlot);
  17708. return true;
  17709. }
  17710. }
  17711. return false;
  17712. }
  17713. // Returns true if a mission was pushed...
  17714. bool CvUnitAI::AI_specialSeaTransportSpy()
  17715. {
  17716. //PROFILE_FUNC();
  17717. CvPlot* pLoopPlot;
  17718. CvPlot* pBestPlot;
  17719. CvPlot* pBestSpyPlot;
  17720. PlayerTypes eBestPlayer;
  17721. int iPathTurns;
  17722. int iValue;
  17723. int iBestValue;
  17724. int iI;
  17725. FAssert(getCargo() > 0);
  17726. FAssert(getUnitAICargo(UNITAI_SPY) > 0);
  17727. if (!canCargoAllMove())
  17728. {
  17729. return false;
  17730. }
  17731. iBestValue = 0;
  17732. eBestPlayer = NO_PLAYER;
  17733. for (iI = 0; iI < MAX_CIV_PLAYERS; iI++)
  17734. {
  17735. if (GET_PLAYER((PlayerTypes)iI).isAlive())
  17736. {
  17737. if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
  17738. {
  17739. if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_ANNOYED)
  17740. {
  17741. iValue = GET_PLAYER((PlayerTypes)iI).getTotalPopulation();
  17742. if (iValue > iBestValue)
  17743. {
  17744. iBestValue = iValue;
  17745. eBestPlayer = ((PlayerTypes)iI);
  17746. }
  17747. }
  17748. }
  17749. }
  17750. }
  17751. if (eBestPlayer == NO_PLAYER)
  17752. {
  17753. return false;
  17754. }
  17755. pBestPlot = NULL;
  17756. pBestSpyPlot = NULL;
  17757. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  17758. {
  17759. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  17760. if (pLoopPlot->isCoastalLand())
  17761. {
  17762. if (pLoopPlot->getOwnerINLINE() == eBestPlayer)
  17763. {
  17764. iValue = pLoopPlot->area()->getCitiesPerPlayer(eBestPlayer);
  17765. /************************************************************************************************/
  17766. /* BETTER_BTS_AI_MOD 02/23/10 jdog5000 */
  17767. /* */
  17768. /* Efficiency */
  17769. /************************************************************************************************/
  17770. iValue *= 1000;
  17771. if (iValue > iBestValue)
  17772. {
  17773. /************************************************************************************************/
  17774. /* BETTER_BTS_AI_MOD END */
  17775. /************************************************************************************************/
  17776. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ATTACK_SPY, getGroup(), 4) == 0)
  17777. {
  17778. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  17779. {
  17780. iValue /= (iPathTurns + 1);
  17781. if (iValue > iBestValue)
  17782. {
  17783. iBestValue = iValue;
  17784. pBestPlot = getPathEndTurnPlot();
  17785. pBestSpyPlot = pLoopPlot;
  17786. }
  17787. }
  17788. }
  17789. }
  17790. }
  17791. }
  17792. }
  17793. if ((pBestPlot != NULL) && (pBestSpyPlot != NULL))
  17794. {
  17795. FAssert(!(pBestPlot->isImpassable()));
  17796. if ((pBestPlot == pBestSpyPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestSpyPlot->getX_INLINE(), pBestSpyPlot->getY_INLINE()) == 1))
  17797. {
  17798. if (atPlot(pBestSpyPlot))
  17799. {
  17800. unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
  17801. return true;
  17802. }
  17803. else
  17804. {
  17805. getGroup()->pushMission(MISSION_MOVE_TO, pBestSpyPlot->getX_INLINE(), pBestSpyPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestSpyPlot);
  17806. return true;
  17807. }
  17808. }
  17809. else
  17810. {
  17811. FAssert(!atPlot(pBestPlot));
  17812. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestSpyPlot);
  17813. return true;
  17814. }
  17815. }
  17816. return false;
  17817. }
  17818. // Returns true if a mission was pushed...
  17819. bool CvUnitAI::AI_carrierSeaTransport()
  17820. {
  17821. PROFILE_FUNC();
  17822. CvPlot* pLoopPlot;
  17823. CvPlot* pLoopPlotAir;
  17824. CvPlot* pBestPlot;
  17825. CvPlot* pBestCarrierPlot;
  17826. int iMaxAirRange;
  17827. int iPathTurns;
  17828. int iValue;
  17829. int iBestValue;
  17830. int iDX, iDY;
  17831. int iI;
  17832. iMaxAirRange = 0;
  17833. std::vector<CvUnit*> aCargoUnits;
  17834. getCargoUnits(aCargoUnits);
  17835. for (uint i = 0; i < aCargoUnits.size(); ++i)
  17836. {
  17837. iMaxAirRange = std::max(iMaxAirRange, aCargoUnits[i]->airRange());
  17838. }
  17839. if (iMaxAirRange == 0)
  17840. {
  17841. return false;
  17842. }
  17843. iBestValue = 0;
  17844. pBestPlot = NULL;
  17845. pBestCarrierPlot = NULL;
  17846. /************************************************************************************************/
  17847. /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
  17848. /* */
  17849. /* Naval AI, War tactics, Efficiency */
  17850. /************************************************************************************************/
  17851. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  17852. {
  17853. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  17854. if (AI_plotValid(pLoopPlot))
  17855. {
  17856. if (pLoopPlot->isAdjacentToLand())
  17857. {
  17858. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  17859. {
  17860. iValue = 0;
  17861. for (iDX = -(iMaxAirRange); iDX <= iMaxAirRange; iDX++)
  17862. {
  17863. for (iDY = -(iMaxAirRange); iDY <= iMaxAirRange; iDY++)
  17864. {
  17865. pLoopPlotAir = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iDX, iDY);
  17866. if (pLoopPlotAir != NULL)
  17867. {
  17868. if (plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pLoopPlotAir->getX_INLINE(), pLoopPlotAir->getY_INLINE()) <= iMaxAirRange)
  17869. {
  17870. if (!(pLoopPlotAir->isBarbarian()))
  17871. {
  17872. if (potentialWarAction(pLoopPlotAir))
  17873. {
  17874. if (pLoopPlotAir->isCity())
  17875. {
  17876. iValue += 3;
  17877. // BBAI: Support invasions
  17878. iValue += (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlotAir, MISSIONAI_ASSAULT, getGroup(), 2) * 6);
  17879. }
  17880. if (pLoopPlotAir->getImprovementType() != NO_IMPROVEMENT)
  17881. {
  17882. iValue += 2;
  17883. }
  17884. if (plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pLoopPlotAir->getX_INLINE(), pLoopPlotAir->getY_INLINE()) <= iMaxAirRange/2)
  17885. {
  17886. // BBAI: Support/air defense for land troops
  17887. iValue += pLoopPlotAir->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE());
  17888. }
  17889. }
  17890. }
  17891. }
  17892. }
  17893. }
  17894. }
  17895. if( iValue > 0 )
  17896. {
  17897. iValue *= 1000;
  17898. for (int iDirection = 0; iDirection < NUM_DIRECTION_TYPES; iDirection++)
  17899. {
  17900. CvPlot* pDirectionPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), (DirectionTypes)iDirection);
  17901. if (pDirectionPlot != NULL)
  17902. {
  17903. if (pDirectionPlot->isCity() && isEnemy(pDirectionPlot->getTeam(), pLoopPlot))
  17904. {
  17905. iValue /= 2;
  17906. break;
  17907. }
  17908. }
  17909. }
  17910. if (iValue > iBestValue)
  17911. {
  17912. bool bStealth = (getInvisibleType() != NO_INVISIBLE);
  17913. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_CARRIER, getGroup(), bStealth ? 5 : 3) <= (bStealth ? 0 : 3))
  17914. {
  17915. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  17916. {
  17917. iValue /= (iPathTurns + 1);
  17918. if (iValue > iBestValue)
  17919. {
  17920. iBestValue = iValue;
  17921. pBestPlot = getPathEndTurnPlot();
  17922. pBestCarrierPlot = pLoopPlot;
  17923. }
  17924. }
  17925. }
  17926. }
  17927. }
  17928. }
  17929. }
  17930. }
  17931. }
  17932. /************************************************************************************************/
  17933. /* BETTER_BTS_AI_MOD END */
  17934. /************************************************************************************************/
  17935. if ((pBestPlot != NULL) && (pBestCarrierPlot != NULL))
  17936. {
  17937. if (atPlot(pBestCarrierPlot))
  17938. {
  17939. if (getGroup()->hasCargo())
  17940. {
  17941. CvPlot* pPlot = plot();
  17942. int iNumUnits = pPlot->getNumUnits();
  17943. for (int i = 0; i < iNumUnits; ++i)
  17944. {
  17945. bool bDone = true;
  17946. CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();
  17947. while (pUnitNode != NULL)
  17948. {
  17949. CvUnit* pCargoUnit = ::getUnit(pUnitNode->m_data);
  17950. pUnitNode = pPlot->nextUnitNode(pUnitNode);
  17951. if (pCargoUnit->isCargo())
  17952. {
  17953. FAssert(pCargoUnit->getTransportUnit() != NULL);
  17954. if (pCargoUnit->getOwnerINLINE() == getOwnerINLINE() && (pCargoUnit->getTransportUnit()->getGroup() == getGroup()) && (pCargoUnit->getDomainType() == DOMAIN_AIR))
  17955. {
  17956. if (pCargoUnit->canMove() && pCargoUnit->isGroupHead())
  17957. {
  17958. // careful, this might kill the cargo group
  17959. if (pCargoUnit->getGroup()->AI_update())
  17960. {
  17961. bDone = false;
  17962. break;
  17963. }
  17964. }
  17965. }
  17966. }
  17967. }
  17968. if (bDone)
  17969. {
  17970. break;
  17971. }
  17972. }
  17973. }
  17974. if (canPlunder(pBestCarrierPlot))
  17975. {
  17976. getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, false, false, MISSIONAI_CARRIER, pBestCarrierPlot);
  17977. }
  17978. else
  17979. {
  17980. getGroup()->pushMission(MISSION_SKIP);
  17981. }
  17982. return true;
  17983. }
  17984. else
  17985. {
  17986. FAssert(!atPlot(pBestPlot));
  17987. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_CARRIER, pBestCarrierPlot);
  17988. return true;
  17989. }
  17990. }
  17991. return false;
  17992. }
  17993. // Returns true if a mission was pushed...
  17994. bool CvUnitAI::AI_connectPlot(CvPlot* pPlot, int iRange)
  17995. {
  17996. PROFILE_FUNC();
  17997. CvCity* pLoopCity;
  17998. int iLoop;
  17999. FAssert(canBuildRoute());
  18000. /************************************************************************************************/
  18001. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  18002. /* */
  18003. /* Unit AI, Efficiency */
  18004. /************************************************************************************************/
  18005. // BBAI efficiency: check area for land units before generating paths
  18006. if( (getDomainType() == DOMAIN_LAND) && (pPlot->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
  18007. {
  18008. return false;
  18009. }
  18010. /************************************************************************************************/
  18011. /* BETTER_BTS_AI_MOD END */
  18012. /************************************************************************************************/
  18013. if (!(pPlot->isVisibleEnemyUnit(this)))
  18014. {
  18015. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pPlot, MISSIONAI_BUILD, getGroup(), iRange) == 0)
  18016. {
  18017. if (generatePath(pPlot, MOVE_SAFE_TERRITORY, true))
  18018. {
  18019. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  18020. {
  18021. if (!(pPlot->isConnectedTo(pLoopCity)))
  18022. {
  18023. FAssertMsg(pPlot->getPlotCity() != pLoopCity, "pPlot->getPlotCity() is not expected to be equal with pLoopCity");
  18024. if (plot()->getPlotGroup(getOwnerINLINE()) == pLoopCity->plot()->getPlotGroup(getOwnerINLINE()))
  18025. {
  18026. getGroup()->pushMission(MISSION_ROUTE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pPlot);
  18027. return true;
  18028. }
  18029. }
  18030. }
  18031. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  18032. {
  18033. /************************************************************************************************/
  18034. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  18035. /* */
  18036. /* Unit AI, Efficiency */
  18037. /************************************************************************************************/
  18038. // BBAI efficiency: check same area
  18039. if( (pLoopCity->area() != pPlot->area()) )
  18040. {
  18041. continue;
  18042. }
  18043. /************************************************************************************************/
  18044. /* BETTER_BTS_AI_MOD END */
  18045. /************************************************************************************************/
  18046. if (!(pPlot->isConnectedTo(pLoopCity)))
  18047. {
  18048. FAssertMsg(pPlot->getPlotCity() != pLoopCity, "pPlot->getPlotCity() is not expected to be equal with pLoopCity");
  18049. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  18050. {
  18051. if (generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true))
  18052. {
  18053. if (atPlot(pPlot)) // need to test before moving...
  18054. {
  18055. getGroup()->pushMission(MISSION_ROUTE_TO, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pPlot);
  18056. }
  18057. else
  18058. {
  18059. getGroup()->pushMission(MISSION_ROUTE_TO, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pPlot);
  18060. getGroup()->pushMission(MISSION_ROUTE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pPlot);
  18061. }
  18062. return true;
  18063. }
  18064. }
  18065. }
  18066. }
  18067. }
  18068. }
  18069. }
  18070. return false;
  18071. }
  18072. // Returns true if a mission was pushed...
  18073. bool CvUnitAI::AI_improveCity(CvCity* pCity)
  18074. {
  18075. PROFILE_FUNC();
  18076. CvPlot* pBestPlot;
  18077. BuildTypes eBestBuild;
  18078. MissionTypes eMission;
  18079. if (AI_bestCityBuild(pCity, &pBestPlot, &eBestBuild, NULL, this))
  18080. {
  18081. FAssertMsg(pBestPlot != NULL, "BestPlot is not assigned a valid value");
  18082. FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
  18083. FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
  18084. if ((plot()->getWorkingCity() != pCity) || (GC.getBuildInfo(eBestBuild).getRoute() != NO_ROUTE))
  18085. {
  18086. eMission = MISSION_ROUTE_TO;
  18087. }
  18088. else
  18089. {
  18090. eMission = MISSION_MOVE_TO;
  18091. if (NULL != pBestPlot && generatePath(pBestPlot) && (getPathLastNode()->m_iData2 == 1) && (getPathLastNode()->m_iData1 == 0))
  18092. {
  18093. if (pBestPlot->getRouteType() != NO_ROUTE)
  18094. {
  18095. eMission = MISSION_ROUTE_TO;
  18096. }
  18097. }
  18098. else if (plot()->getRouteType() == NO_ROUTE)
  18099. {
  18100. int iPlotMoveCost = 0;
  18101. iPlotMoveCost = ((plot()->getFeatureType() == NO_FEATURE) ? GC.getTerrainInfo(plot()->getTerrainType()).getMovementCost() : GC.getFeatureInfo(plot()->getFeatureType()).getMovementCost());
  18102. if (plot()->isHills())
  18103. {
  18104. iPlotMoveCost += GC.getHILLS_EXTRA_MOVEMENT();
  18105. }
  18106. if (iPlotMoveCost > 1)
  18107. {
  18108. eMission = MISSION_ROUTE_TO;
  18109. }
  18110. }
  18111. }
  18112. eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);
  18113. getGroup()->pushMission(eMission, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
  18114. getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
  18115. return true;
  18116. }
  18117. return false;
  18118. }
  18119. bool CvUnitAI::AI_improveLocalPlot(int iRange, CvCity* pIgnoreCity)
  18120. {
  18121. int iX, iY;
  18122. int iBestValue = 0;
  18123. CvPlot* pBestPlot = NULL;
  18124. BuildTypes eBestBuild = NO_BUILD;
  18125. for (iX = -iRange; iX <= iRange; iX++)
  18126. {
  18127. for (iY = -iRange; iY <= iRange; iY++)
  18128. {
  18129. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
  18130. if ((pLoopPlot != NULL) && (pLoopPlot->isCityRadius()))
  18131. {
  18132. CvCity* pCity = pLoopPlot->getWorkingCity();
  18133. if ((NULL != pCity) && (pCity->getOwnerINLINE() == getOwnerINLINE()))
  18134. {
  18135. if ((NULL == pIgnoreCity) || (pCity != pIgnoreCity))
  18136. {
  18137. if (AI_plotValid(pLoopPlot))
  18138. {
  18139. int iIndex = pCity->getCityPlotIndex(pLoopPlot);
  18140. if (iIndex != CITY_HOME_PLOT)
  18141. {
  18142. if (((NULL == pIgnoreCity) || ((pCity->AI_getWorkersNeeded() > 0) && (pCity->AI_getWorkersHave() < (1 + pCity->AI_getWorkersNeeded() * 2 / 3)))) && (pCity->AI_getBestBuild(iIndex) != NO_BUILD))
  18143. {
  18144. if (canBuild(pLoopPlot, pCity->AI_getBestBuild(iIndex)))
  18145. {
  18146. bool bAllowed = true;
  18147. if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION))
  18148. {
  18149. if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT && pLoopPlot->getImprovementType() != GC.getDefineINT("RUINS_IMPROVEMENT"))
  18150. {
  18151. bAllowed = false;
  18152. }
  18153. }
  18154. if (bAllowed)
  18155. {
  18156. if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT && GC.getBuildInfo(pCity->AI_getBestBuild(iIndex)).getImprovement() != NO_IMPROVEMENT)
  18157. {
  18158. bAllowed = false;
  18159. }
  18160. }
  18161. if (bAllowed)
  18162. {
  18163. int iValue = pCity->AI_getBestBuildValue(iIndex);
  18164. int iPathTurns;
  18165. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  18166. {
  18167. int iMaxWorkers = 1;
  18168. if (plot() == pLoopPlot)
  18169. {
  18170. iValue *= 3;
  18171. iValue /= 2;
  18172. }
  18173. else if (getPathLastNode()->m_iData1 == 0)
  18174. {
  18175. iPathTurns++;
  18176. }
  18177. else if (iPathTurns <= 1)
  18178. {
  18179. iMaxWorkers = AI_calculatePlotWorkersNeeded(pLoopPlot, pCity->AI_getBestBuild(iIndex));
  18180. }
  18181. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup()) < iMaxWorkers)
  18182. {
  18183. iValue *= 1000;
  18184. iValue /= 1 + iPathTurns;
  18185. if (iValue > iBestValue)
  18186. {
  18187. iBestValue = iValue;
  18188. pBestPlot = pLoopPlot;
  18189. eBestBuild = pCity->AI_getBestBuild(iIndex);
  18190. }
  18191. }
  18192. }
  18193. }
  18194. }
  18195. }
  18196. }
  18197. }
  18198. }
  18199. }
  18200. }
  18201. }
  18202. }
  18203. if (pBestPlot != NULL)
  18204. {
  18205. FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
  18206. FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
  18207. FAssert(pBestPlot->getWorkingCity() != NULL);
  18208. if (NULL != pBestPlot->getWorkingCity())
  18209. {
  18210. pBestPlot->getWorkingCity()->AI_changeWorkersHave(+1);
  18211. if (plot()->getWorkingCity() != NULL)
  18212. {
  18213. plot()->getWorkingCity()->AI_changeWorkersHave(-1);
  18214. }
  18215. }
  18216. MissionTypes eMission = MISSION_MOVE_TO;
  18217. int iPathTurns;
  18218. if (generatePath(pBestPlot, 0, true, &iPathTurns) && (getPathLastNode()->m_iData2 == 1) && (getPathLastNode()->m_iData1 == 0))
  18219. {
  18220. if (pBestPlot->getRouteType() != NO_ROUTE)
  18221. {
  18222. eMission = MISSION_ROUTE_TO;
  18223. }
  18224. }
  18225. else if (plot()->getRouteType() == NO_ROUTE)
  18226. {
  18227. int iPlotMoveCost = 0;
  18228. iPlotMoveCost = ((plot()->getFeatureType() == NO_FEATURE) ? GC.getTerrainInfo(plot()->getTerrainType()).getMovementCost() : GC.getFeatureInfo(plot()->getFeatureType()).getMovementCost());
  18229. if (plot()->isHills())
  18230. {
  18231. iPlotMoveCost += GC.getHILLS_EXTRA_MOVEMENT();
  18232. }
  18233. if (iPlotMoveCost > 1)
  18234. {
  18235. eMission = MISSION_ROUTE_TO;
  18236. }
  18237. }
  18238. eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);
  18239. getGroup()->pushMission(eMission, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
  18240. getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
  18241. return true;
  18242. }
  18243. return false;
  18244. }
  18245. // Returns true if a mission was pushed...
  18246. bool CvUnitAI::AI_nextCityToImprove(CvCity* pCity)
  18247. {
  18248. PROFILE_FUNC();
  18249. CvCity* pLoopCity;
  18250. CvPlot* pPlot;
  18251. CvPlot* pBestPlot;
  18252. BuildTypes eBuild;
  18253. BuildTypes eBestBuild;
  18254. int iPathTurns;
  18255. int iValue;
  18256. int iBestValue;
  18257. int iLoop;
  18258. iBestValue = 0;
  18259. eBestBuild = NO_BUILD;
  18260. pBestPlot = NULL;
  18261. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  18262. {
  18263. if (pLoopCity != pCity)
  18264. {
  18265. /************************************************************************************************/
  18266. /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
  18267. /* */
  18268. /* Worker AI, Efficiency */
  18269. /************************************************************************************************/
  18270. // BBAI efficiency: check area for land units before path generation
  18271. if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
  18272. {
  18273. continue;
  18274. }
  18275. //iValue = pLoopCity->AI_totalBestBuildValue(area());
  18276. int iWorkersNeeded = pLoopCity->AI_getWorkersNeeded();
  18277. int iWorkersHave = pLoopCity->AI_getWorkersHave();
  18278. iValue = std::max(0, iWorkersNeeded - iWorkersHave) * 100;
  18279. iValue += iWorkersNeeded * 10;
  18280. iValue *= (iWorkersNeeded + 1);
  18281. iValue /= (iWorkersHave + 1);
  18282. if (iValue > 0)
  18283. {
  18284. if (AI_bestCityBuild(pLoopCity, &pPlot, &eBuild, NULL, this))
  18285. {
  18286. FAssert(pPlot != NULL);
  18287. FAssert(eBuild != NO_BUILD);
  18288. if( AI_plotValid(pPlot) )
  18289. {
  18290. iValue *= 1000;
  18291. if (pLoopCity->isCapital())
  18292. {
  18293. iValue *= 2;
  18294. }
  18295. if( iValue > iBestValue )
  18296. {
  18297. if( generatePath(pPlot, 0, true, &iPathTurns) )
  18298. {
  18299. iValue /= (iPathTurns + 1);
  18300. if (iValue > iBestValue)
  18301. {
  18302. iBestValue = iValue;
  18303. eBestBuild = eBuild;
  18304. pBestPlot = pPlot;
  18305. FAssert(!atPlot(pBestPlot) || NULL == pCity || pCity->AI_getWorkersNeeded() == 0 || pCity->AI_getWorkersHave() > pCity->AI_getWorkersNeeded() + 1);
  18306. }
  18307. }
  18308. }
  18309. }
  18310. /************************************************************************************************/
  18311. /* BETTER_BTS_AI_MOD END */
  18312. /************************************************************************************************/
  18313. }
  18314. }
  18315. }
  18316. }
  18317. if (pBestPlot != NULL)
  18318. {
  18319. FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
  18320. FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
  18321. if (plot()->getWorkingCity() != NULL)
  18322. {
  18323. plot()->getWorkingCity()->AI_changeWorkersHave(-1);
  18324. }
  18325. FAssert(pBestPlot->getWorkingCity() != NULL || GC.getBuildInfo(eBestBuild).getImprovement() == NO_IMPROVEMENT);
  18326. if (NULL != pBestPlot->getWorkingCity())
  18327. {
  18328. pBestPlot->getWorkingCity()->AI_changeWorkersHave(+1);
  18329. }
  18330. eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);
  18331. getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
  18332. getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
  18333. return true;
  18334. }
  18335. return false;
  18336. }
  18337. // Returns true if a mission was pushed...
  18338. bool CvUnitAI::AI_nextCityToImproveAirlift()
  18339. {
  18340. PROFILE_FUNC();
  18341. CvCity* pCity;
  18342. CvCity* pLoopCity;
  18343. CvPlot* pBestPlot;
  18344. int iValue;
  18345. int iBestValue;
  18346. int iLoop;
  18347. if (getGroup()->getNumUnits() > 1)
  18348. {
  18349. return false;
  18350. }
  18351. pCity = plot()->getPlotCity();
  18352. if (pCity == NULL)
  18353. {
  18354. return false;
  18355. }
  18356. if (pCity->getMaxAirlift() == 0)
  18357. {
  18358. return false;
  18359. }
  18360. iBestValue = 0;
  18361. pBestPlot = NULL;
  18362. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  18363. {
  18364. if (pLoopCity != pCity)
  18365. {
  18366. if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
  18367. {
  18368. iValue = pLoopCity->AI_totalBestBuildValue(pLoopCity->area());
  18369. if (iValue > iBestValue)
  18370. {
  18371. iBestValue = iValue;
  18372. pBestPlot = pLoopCity->plot();
  18373. FAssert(pLoopCity != pCity);
  18374. }
  18375. }
  18376. }
  18377. }
  18378. if (pBestPlot != NULL)
  18379. {
  18380. getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  18381. return true;
  18382. }
  18383. return false;
  18384. }
  18385. // Returns true if a mission was pushed...
  18386. bool CvUnitAI::AI_irrigateTerritory()
  18387. {
  18388. PROFILE_FUNC();
  18389. CvPlot* pLoopPlot;
  18390. CvPlot* pBestPlot;
  18391. ImprovementTypes eImprovement;
  18392. BuildTypes eBuild;
  18393. BuildTypes eBestBuild;
  18394. BuildTypes eBestTempBuild;
  18395. BonusTypes eNonObsoleteBonus;
  18396. bool bValid;
  18397. int iPathTurns;
  18398. int iValue;
  18399. int iBestValue;
  18400. int iBestTempBuildValue;
  18401. int iI, iJ;
  18402. iBestValue = 0;
  18403. eBestBuild = NO_BUILD;
  18404. pBestPlot = NULL;
  18405. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  18406. {
  18407. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  18408. if (AI_plotValid(pLoopPlot))
  18409. {
  18410. if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
  18411. {
  18412. if (pLoopPlot->getWorkingCity() == NULL)
  18413. {
  18414. eImprovement = pLoopPlot->getImprovementType();
  18415. if ((eImprovement == NO_IMPROVEMENT) || !(GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION) && !(eImprovement == (GC.getDefineINT("RUINS_IMPROVEMENT")))))
  18416. {
  18417. if ((eImprovement == NO_IMPROVEMENT) || !(GC.getImprovementInfo(eImprovement).isCarriesIrrigation()))
  18418. {
  18419. eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());
  18420. //if ((eImprovement == NO_IMPROVEMENT) || (eNonObsoleteBonus == NO_BONUS) || !(GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus)))
  18421. if (eImprovement == NO_IMPROVEMENT || eNonObsoleteBonus == NO_BONUS || !GET_PLAYER(getOwnerINLINE()).doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus))
  18422. {
  18423. if (pLoopPlot->isIrrigationAvailable(true))
  18424. {
  18425. iBestTempBuildValue = MAX_INT;
  18426. eBestTempBuild = NO_BUILD;
  18427. for (iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
  18428. {
  18429. eBuild = ((BuildTypes)iJ);
  18430. FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");
  18431. if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
  18432. {
  18433. if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).isCarriesIrrigation())
  18434. {
  18435. if (canBuild(pLoopPlot, eBuild))
  18436. {
  18437. iValue = 10000;
  18438. iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);
  18439. // XXX feature production???
  18440. if (iValue < iBestTempBuildValue)
  18441. {
  18442. iBestTempBuildValue = iValue;
  18443. eBestTempBuild = eBuild;
  18444. }
  18445. }
  18446. }
  18447. }
  18448. }
  18449. if (eBestTempBuild != NO_BUILD)
  18450. {
  18451. bValid = true;
  18452. if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_LEAVE_FORESTS))
  18453. {
  18454. if (pLoopPlot->getFeatureType() != NO_FEATURE)
  18455. {
  18456. if (GC.getBuildInfo(eBestTempBuild).isFeatureRemove(pLoopPlot->getFeatureType())
  18457. //FfH: Added by Kael 04/24/2008
  18458. && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pLoopPlot->getFeatureType())
  18459. //FfH: End Add
  18460. )
  18461. {
  18462. if (GC.getFeatureInfo(pLoopPlot->getFeatureType()).getYieldChange(YIELD_PRODUCTION) > 0)
  18463. {
  18464. bValid = false;
  18465. }
  18466. }
  18467. }
  18468. }
  18469. if (bValid)
  18470. {
  18471. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  18472. {
  18473. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 1) == 0)
  18474. {
  18475. if (generatePath(pLoopPlot, 0, true, &iPathTurns)) // XXX should this actually be at the top of the loop? (with saved paths and all...)
  18476. {
  18477. iValue = 10000;
  18478. iValue /= (iPathTurns + 1);
  18479. if (iValue > iBestValue)
  18480. {
  18481. iBestValue = iValue;
  18482. eBestBuild = eBestTempBuild;
  18483. pBestPlot = pLoopPlot;
  18484. }
  18485. }
  18486. }
  18487. }
  18488. }
  18489. }
  18490. }
  18491. }
  18492. }
  18493. }
  18494. }
  18495. }
  18496. }
  18497. }
  18498. if (pBestPlot != NULL)
  18499. {
  18500. FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
  18501. FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
  18502. getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
  18503. getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
  18504. return true;
  18505. }
  18506. return false;
  18507. }
  18508. // Tries to build a fort. Only in own territory if SuperForts/AdvancedTactics isn't enabled.
  18509. // Returns true if a mission was pushed.
  18510. bool CvUnitAI::AI_fortTerritory(bool bCanal, bool bAirbase)
  18511. {
  18512. PROFILE_FUNC();
  18513. // lfgr 07/2019: Barbarians don't build forts
  18514. if( GET_PLAYER(getOwnerINLINE()).isBarbarian() ) {
  18515. return false;
  18516. }
  18517. // lfgr end
  18518. int iBestValue = 0;
  18519. BuildTypes eBestBuild = NO_BUILD;
  18520. CvPlot* pBestPlot = NULL;
  18521. CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  18522. for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  18523. {
  18524. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  18525. if (AI_plotValid(pLoopPlot))
  18526. {
  18527. if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()
  18528. // Super Forts *canal* *choke* begin
  18529. || (GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS) && pLoopPlot->getOwnerINLINE() == NO_PLAYER && pLoopPlot->isRevealed(getTeam(), false)))
  18530. // Super Forts end
  18531. {
  18532. if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT
  18533. // Super Forts *canal* *choke* begin
  18534. || !pLoopPlot->isCityRadius())
  18535. // Super Forts end
  18536. {
  18537. int iValue = 0;
  18538. iValue += bCanal ? kOwner.AI_getPlotCanalValue(pLoopPlot) : 0;
  18539. iValue += bAirbase ? kOwner.AI_getPlotAirbaseValue(pLoopPlot) : 0;
  18540. // Super Forts *choke* begin
  18541. iValue += kOwner.AI_getPlotChokeValue(pLoopPlot);
  18542. /* The commented lines below weren't in the original BTS code, and shouldn't be necessary because
  18543. the canal, airbase, and choke functions all consider defense bonus in their values
  18544. if (pLoopPlot->isHills())
  18545. iValue += 10;
  18546. */
  18547. if (GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS))
  18548. {
  18549. CvPlot* pAdjacentPlot;
  18550. for (int iI = 0; iI < NUM_DIRECTION_TYPES; ++iI)
  18551. {
  18552. pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
  18553. if (pAdjacentPlot != NULL)
  18554. {
  18555. if(pAdjacentPlot->getOwnerINLINE() == NO_PLAYER)
  18556. {
  18557. BonusTypes eNonObsoleteBonus = pAdjacentPlot->getNonObsoleteBonusType(getTeam());
  18558. if (eNonObsoleteBonus != NO_BONUS)
  18559. {
  18560. if (!GET_PLAYER(getOwnerINLINE()).hasBonus(eNonObsoleteBonus) || GC.getBonusInfo(eNonObsoleteBonus).isMana())
  18561. {
  18562. iValue += 250;
  18563. }
  18564. else
  18565. {
  18566. iValue += 50;
  18567. }
  18568. }
  18569. }
  18570. }
  18571. }
  18572. }
  18573. int iMinAcceptableValue = 0;
  18574. if(pLoopPlot->getOwnerINLINE() == NO_PLAYER || pLoopPlot->isBeingWorked())
  18575. { // Don't go outside borders for low values
  18576. iMinAcceptableValue += 150;
  18577. }
  18578. if (iValue > iMinAcceptableValue)
  18579. {
  18580. int iBestTempBuildValue = MAX_INT;
  18581. BuildTypes eBestTempBuild = NO_BUILD;
  18582. int iPlotValue = iValue;
  18583. iPlotValue += bCanal ? 0 : kOwner.AI_getPlotCanalValue(pLoopPlot) / 4;
  18584. iPlotValue += bAirbase ? 0 : kOwner.AI_getPlotAirbaseValue(pLoopPlot) / 4;
  18585. // Super Forts end
  18586. for (int iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
  18587. {
  18588. BuildTypes eBuild = ((BuildTypes)iJ);
  18589. FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");
  18590. if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
  18591. {
  18592. if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).isActsAsCity())
  18593. {
  18594. if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).getDefenseModifier() > 0)
  18595. {
  18596. if (canBuild(pLoopPlot, eBuild))
  18597. {
  18598. iValue = 10000;
  18599. iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);
  18600. if (iValue < iBestTempBuildValue)
  18601. {
  18602. iBestTempBuildValue = iValue;
  18603. eBestTempBuild = eBuild;
  18604. }
  18605. }
  18606. }
  18607. }
  18608. }
  18609. }
  18610. if (eBestTempBuild != NO_BUILD)
  18611. {
  18612. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  18613. {
  18614. bool bValid = true;
  18615. if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_LEAVE_FORESTS))
  18616. {
  18617. if (pLoopPlot->getFeatureType() != NO_FEATURE)
  18618. {
  18619. if (GC.getBuildInfo(eBestTempBuild).isFeatureRemove(pLoopPlot->getFeatureType())
  18620. //FfH: Added by Kael 04/24/2008
  18621. && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pLoopPlot->getFeatureType())
  18622. //FfH: End Add
  18623. )
  18624. {
  18625. if (GC.getFeatureInfo(pLoopPlot->getFeatureType()).getYieldChange(YIELD_PRODUCTION) > 0)
  18626. {
  18627. bValid = false;
  18628. }
  18629. }
  18630. }
  18631. }
  18632. if (bValid)
  18633. {
  18634. // Super Forts begin *canal* *choke*
  18635. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 1/*3*/) == 0)
  18636. {
  18637. int iPathTurns;
  18638. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  18639. {
  18640. //iValue *= 1000;
  18641. iValue = iPlotValue * 100;
  18642. iValue /= (iPathTurns + 1);
  18643. if(pLoopPlot->getOwnerINLINE() == NO_PLAYER)
  18644. {
  18645. CvCity* pNearestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), getOwnerINLINE(), NO_TEAM, false);
  18646. if((pNearestCity == NULL) ||
  18647. (plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE()) > GC.getDefineINT("AI_WORKER_MAX_DISTANCE_FROM_CITY_OUT_BORDERS")) ||
  18648. (iPathTurns > (GC.getDefineINT("AI_WORKER_MAX_DISTANCE_FROM_CITY_OUT_BORDERS") / 2)))
  18649. {
  18650. iValue = 0;
  18651. }
  18652. }
  18653. // Super Forts end
  18654. if (iValue > iBestValue)
  18655. {
  18656. iBestValue = iValue;
  18657. eBestBuild = eBestTempBuild;
  18658. pBestPlot = pLoopPlot;
  18659. }
  18660. }
  18661. }
  18662. }
  18663. }
  18664. }
  18665. }
  18666. }
  18667. }
  18668. }
  18669. }
  18670. if (pBestPlot != NULL)
  18671. {
  18672. FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
  18673. FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
  18674. getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
  18675. getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
  18676. return true;
  18677. }
  18678. return false;
  18679. }
  18680. // Returns true if a mission was pushed...
  18681. bool CvUnitAI::AI_improveBonus(int iMinValue, CvPlot** ppBestPlot, BuildTypes* peBestBuild, int* piBestValue, bool bInsideBordersOrCurrentPlot)
  18682. {
  18683. // LFGR_TODO: Maybe do some caching, this is called multiple times in the same turn by the same worker.
  18684. PROFILE_FUNC();
  18685. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  18686. CvPlot* pLoopPlot;
  18687. CvPlot* pBestPlot;
  18688. ImprovementTypes eImprovement;
  18689. BuildTypes eBuild;
  18690. BuildTypes eBestBuild;
  18691. BuildTypes eBestTempBuild;
  18692. BonusTypes eNonObsoleteBonus;
  18693. int iPathTurns;
  18694. int iValue;
  18695. int iBestValue;
  18696. int iBestTempBuildValue;
  18697. int iBestResourceValue;
  18698. int iI, iJ;
  18699. bool bBestBuildIsRoute = false;
  18700. bool bCanRoute;
  18701. bool bIsConnected;
  18702. iBestValue = 0;
  18703. iBestResourceValue = 0;
  18704. eBestBuild = NO_BUILD;
  18705. pBestPlot = NULL;
  18706. if( gUnitLogLevel >= 3 ){logBBAI(" Try to improve some bonus");}
  18707. bCanRoute = canBuildRoute();
  18708. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  18709. {
  18710. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  18711. // Super Forts begin *AI_worker*: Allow building outside borders if super forts is enabled
  18712. if ((pLoopPlot->getOwnerINLINE() == getOwnerINLINE() ||
  18713. ( ( !bInsideBordersOrCurrentPlot || pLoopPlot == plot() ) && GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)
  18714. && pLoopPlot->getOwnerINLINE() == NO_PLAYER && pLoopPlot->isRevealed(getTeam(), false) )
  18715. ) && AI_plotValid(pLoopPlot))
  18716. //if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE() && AI_plotValid(pLoopPlot)) - Original Code
  18717. // Super Forts end
  18718. {
  18719. bool bCanImprove = (pLoopPlot->area() == area());
  18720. if (!bCanImprove)
  18721. {
  18722. if (DOMAIN_SEA == getDomainType() && pLoopPlot->isWater() && plot()->isAdjacentToArea(pLoopPlot->area()))
  18723. {
  18724. bCanImprove = true;
  18725. }
  18726. }
  18727. //FfH: Added by Kael 12/20/2008
  18728. if (pLoopPlot->isVisibleEnemyUnit(this))
  18729. {
  18730. bCanImprove = false;
  18731. }
  18732. if (!atPlot(pLoopPlot))
  18733. {
  18734. if (!canMoveInto(pLoopPlot))
  18735. {
  18736. bCanImprove = false;
  18737. }
  18738. }
  18739. //FfH: End Add
  18740. if (bCanImprove)
  18741. {
  18742. eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());
  18743. if (eNonObsoleteBonus != NO_BONUS)
  18744. {
  18745. bIsConnected = pLoopPlot->isConnectedToCapital(getOwnerINLINE());
  18746. // Super Forts begin *AI_worker* - This section makes sure the plot is "close enough" to a city to be worth building on
  18747. bool bCloseEnough = false;
  18748. if(pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
  18749. {
  18750. bCloseEnough = true;
  18751. }
  18752. // Automated human workers will not look outside borders to build forts on bonuses the player already has
  18753. else if(!isHuman() || !GET_PLAYER(getOwnerINLINE()).hasBonus(eNonObsoleteBonus))
  18754. {
  18755. CvCity* pNearestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), getOwnerINLINE(), NO_TEAM, false);
  18756. int iPathTurns;
  18757. if ((pNearestCity != NULL) && generatePath(pLoopPlot, 0, true, &iPathTurns))
  18758. {
  18759. int iDistanceModifier = 1;
  18760. if(GET_PLAYER(getOwnerINLINE()).hasBonus(eNonObsoleteBonus))
  18761. {
  18762. iDistanceModifier = 2; // AI will not travel as far for bonuses they already have
  18763. }
  18764. if((plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE())*iDistanceModifier) <= GC.getDefineINT("AI_WORKER_MAX_DISTANCE_FROM_CITY_OUT_BORDERS"))
  18765. {
  18766. bCloseEnough = true;
  18767. }
  18768. if (iPathTurns > (GC.getDefineINT("AI_WORKER_MAX_DISTANCE_FROM_CITY_OUT_BORDERS") / 2))
  18769. {
  18770. bCloseEnough = false;
  18771. }
  18772. }
  18773. }
  18774. if (((pLoopPlot->getWorkingCity() != NULL) || (bIsConnected || bCanRoute)) && bCloseEnough)
  18775. //if ((pLoopPlot->getWorkingCity() != NULL) || (bIsConnected || bCanRoute)) // Original Code
  18776. // Super Forts end
  18777. {
  18778. if( gUnitLogLevel >= 3 ){
  18779. logBBAI(" Found bonus %s on %d|%d (%s), check whether we want to improve that...",
  18780. GC.getBonusInfo( eNonObsoleteBonus ).getType(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(),
  18781. ( pLoopPlot->getOwnerINLINE() == getOwnerINLINE() ? "owned" : "unowned" ) );
  18782. }
  18783. eImprovement = pLoopPlot->getImprovementType();
  18784. bool bDoImprove = false;
  18785. if (eImprovement == NO_IMPROVEMENT)
  18786. {
  18787. bDoImprove = true;
  18788. }
  18789. else if (GC.getImprovementInfo(eImprovement).isActsAsCity() || GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
  18790. {
  18791. bDoImprove = false;
  18792. }
  18793. // Super Forts begin *AI_worker* (No need to loop through builds if the improvement is permanent)
  18794. else if (GC.getImprovementInfo(eImprovement).isPermanent())
  18795. {
  18796. bDoImprove = false;
  18797. }
  18798. // Super Forts end
  18799. else if (eImprovement == (ImprovementTypes)(GC.getDefineINT("RUINS_IMPROVEMENT")))
  18800. {
  18801. bDoImprove = true;
  18802. }
  18803. else if (!GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION))
  18804. {
  18805. bDoImprove = true;
  18806. }
  18807. iBestTempBuildValue = MAX_INT;
  18808. eBestTempBuild = NO_BUILD;
  18809. if (bDoImprove)
  18810. {
  18811. if( gUnitLogLevel >= 3 ){
  18812. logBBAI(" We want to improve this, checking for builds..." );
  18813. }
  18814. for (iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
  18815. {
  18816. eBuild = ((BuildTypes)iJ);
  18817. if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
  18818. {
  18819. // Super Forts *AI_worker* (added if statement)
  18820. ImprovementTypes eImprovement = (ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement();
  18821. CvImprovementInfo& kImprovement = GC.getImprovementInfo( eImprovement );
  18822. if(pLoopPlot->getOwnerINLINE() == getOwnerINLINE() || kImprovement.isActsAsCity() && kImprovement.isOutsideBorders())
  18823. {
  18824. //if (GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).isImprovementBonusTrade(eNonObsoleteBonus) || (!pLoopPlot->isCityRadius() && GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).isActsAsCity()))
  18825. if (kOwner.doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus)) // K-Mod
  18826. {
  18827. if (canBuild(pLoopPlot, eBuild))
  18828. {
  18829. if ((pLoopPlot->getFeatureType() == NO_FEATURE) || !GC.getBuildInfo(eBuild).isFeatureRemove(pLoopPlot->getFeatureType()) || !GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_LEAVE_FORESTS)
  18830. //FfH: Added by Kael 04/24/2008
  18831. || GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pLoopPlot->getFeatureType())
  18832. //FfH: End Add
  18833. )
  18834. {
  18835. iValue = 10000;
  18836. iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);
  18837. /*FfH: Added by Chalid AiManaAndBonus 06/10/2006*/
  18838. if (!isHuman())
  18839. {
  18840. iValue /= 100;
  18841. iValue *= std::max(0, (100-GC.getLeaderHeadInfo(GET_PLAYER(getOwnerINLINE()).getPersonalityType()).getImprovementWeightModifier((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement())));
  18842. }
  18843. //iValue -= GC.getGameINLINE().getSorenRandNum(4000, "AIBonus");
  18844. //FfH: End Add
  18845. // XXX feature production???
  18846. if (iValue < iBestTempBuildValue)
  18847. {
  18848. iBestTempBuildValue = iValue;
  18849. eBestTempBuild = eBuild;
  18850. }
  18851. }
  18852. }
  18853. }
  18854. } // Super Forts (closing bracket of if statement added above)
  18855. }
  18856. }
  18857. if( gUnitLogLevel >= 3 ) {
  18858. if( eBestTempBuild == NO_BUILD ) {logBBAI(" No build found!" );}
  18859. else {logBBAI(" Best build %s", GC.getBuildInfo( eBestTempBuild ).getType() );}
  18860. }
  18861. }
  18862. if (eBestTempBuild == NO_BUILD)
  18863. {
  18864. bDoImprove = false;
  18865. }
  18866. // Super Forts begin *AI_worker* (if not building an improvement and you don't own the plot then continue so the AI doesn't consider building a route)
  18867. if(!bDoImprove && pLoopPlot->getOwnerINLINE() != getOwnerINLINE())
  18868. {
  18869. continue;
  18870. }
  18871. // Super Forts end
  18872. if ((eBestTempBuild != NO_BUILD) || (bCanRoute && !bIsConnected))
  18873. {
  18874. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  18875. {
  18876. iValue = kOwner.AI_bonusVal(eNonObsoleteBonus);
  18877. if( gUnitLogLevel >= 3 ){ logBBAI(" Reachable. Base value: %d", iValue ); }
  18878. if (bDoImprove)
  18879. {
  18880. eImprovement = (ImprovementTypes)GC.getBuildInfo(eBestTempBuild).getImprovement();
  18881. FAssert(eImprovement != NO_IMPROVEMENT);
  18882. //iValue += (GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBestTempBuild).getImprovement()))
  18883. iValue += 5 * pLoopPlot->calculateImprovementYieldChange(eImprovement, YIELD_FOOD, getOwnerINLINE(), false);
  18884. //>>>>Unofficial Bug Fix: Modified by Denev 2010/02/21
  18885. //*** Elvish civilization can see the amount of production from forest chopping.
  18886. /*
  18887. iValue += 5 * pLoopPlot->calculateNatureYield(YIELD_FOOD, getTeam(), (pLoopPlot->getFeatureType() == NO_FEATURE) ? true : (GC.getBuildInfo(eBestTempBuild).isFeatureRemove(pLoopPlot->getFeatureType())
  18888. //FfH: Added by Kael 04/24/2008
  18889. && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pLoopPlot->getFeatureType()))
  18890. //FfH: End Add
  18891. );
  18892. */
  18893. iValue += 5 * pLoopPlot->calculateNatureYield(YIELD_FOOD, getOwnerINLINE(), pLoopPlot->isFeatureRemove(eBestTempBuild));
  18894. //<<<<Unofficial Bug Fix: End Modify
  18895. if( gUnitLogLevel >= 3 ){ logBBAI(" Value after considering improvement: %d", iValue ); }
  18896. }
  18897. iValue += std::max(0, 100 * GC.getBonusInfo(eNonObsoleteBonus).getAIObjective());
  18898. if (kOwner.getNumTradeableBonuses(eNonObsoleteBonus) == 0)
  18899. {
  18900. iValue *= 2;
  18901. }
  18902. if( gUnitLogLevel >= 3 ){ logBBAI(" Value after considering objective, trade: %d", iValue ); }
  18903. int iMaxWorkers = 1;
  18904. // Super Forts begin *AI_worker*
  18905. if ((eBestTempBuild != NO_BUILD) && (GC.getBuildInfo(eBestTempBuild).getTime() > 0))
  18906. //if ((eBestTempBuild != NO_BUILD) && (!GC.getBuildInfo(eBestTempBuild).isKill())) - Original Code
  18907. // Super Forts end
  18908. {
  18909. //allow teaming.
  18910. iMaxWorkers = AI_calculatePlotWorkersNeeded(pLoopPlot, eBestTempBuild);
  18911. if (getPathLastNode()->m_iData1 == 0)
  18912. {
  18913. iMaxWorkers = std::min((iMaxWorkers + 1) / 2, 1 + kOwner.AI_baseBonusVal(eNonObsoleteBonus) / 20);
  18914. }
  18915. }
  18916. if( gUnitLogLevel >= 3 ){ logBBAI(" Using at most %d workers", iMaxWorkers ); }
  18917. if ((kOwner.AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup()) < iMaxWorkers)
  18918. && (!bDoImprove || (pLoopPlot->getBuildTurnsLeft(eBestTempBuild, 0, 0) > (iPathTurns * 2 - 1))))
  18919. {
  18920. if( gUnitLogLevel >= 3 ){ logBBAI(" Workers are still required!" ); }
  18921. if (bDoImprove)
  18922. {
  18923. iValue *= 1000;
  18924. if (atPlot(pLoopPlot))
  18925. {
  18926. iValue *= 3;
  18927. if( gUnitLogLevel >= 3 ){ logBBAI(" We're at the plot already: triple value" ); }
  18928. }
  18929. iValue /= (iPathTurns + 1);
  18930. if( gUnitLogLevel >= 3 ){ logBBAI(" Divide by path turns: %d", iPathTurns ); }
  18931. if (pLoopPlot->isCityRadius())
  18932. {
  18933. iValue *= 2;
  18934. if( gUnitLogLevel >= 3 ){ logBBAI(" In city radius: double value" ); }
  18935. }
  18936. if( gUnitLogLevel >= 3 ){ logBBAI(" Final improvement build value: %d", iValue ); }
  18937. if (iValue > iBestValue)
  18938. {
  18939. iBestValue = iValue;
  18940. eBestBuild = eBestTempBuild;
  18941. pBestPlot = pLoopPlot;
  18942. bBestBuildIsRoute = false;
  18943. iBestResourceValue = iValue;
  18944. }
  18945. }
  18946. else
  18947. {
  18948. FAssert(bCanRoute && !bIsConnected);
  18949. eImprovement = pLoopPlot->getImprovementType();
  18950. //if ((eImprovement != NO_IMPROVEMENT) && (GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus)))
  18951. if (kOwner.doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus))
  18952. {
  18953. iValue *= 1000;
  18954. iValue /= (iPathTurns + 1);
  18955. if( gUnitLogLevel >= 3 ){ logBBAI(" Final road build value: %d", iValue ); }
  18956. if (iValue > iBestValue)
  18957. {
  18958. iBestValue = iValue;
  18959. eBestBuild = NO_BUILD;
  18960. pBestPlot = pLoopPlot;
  18961. bBestBuildIsRoute = true;
  18962. }
  18963. }
  18964. }
  18965. }
  18966. }
  18967. }
  18968. }
  18969. }
  18970. }
  18971. }
  18972. }
  18973. if( gUnitLogLevel >= 3 && eBestBuild != NO_BUILD ){
  18974. logBBAI(" Best plot: %d|%d, best build: %s with value %d",
  18975. pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), GC.getBuildInfo( eBestBuild ).getType(), iBestValue );
  18976. }
  18977. if ((iBestValue < iMinValue) && (NULL != ppBestPlot))
  18978. {
  18979. FAssert(NULL != peBestBuild);
  18980. FAssert(NULL != piBestValue);
  18981. *ppBestPlot = pBestPlot;
  18982. *peBestBuild = eBestBuild;
  18983. *piBestValue = iBestResourceValue;
  18984. }
  18985. if (pBestPlot != NULL)
  18986. {
  18987. if (eBestBuild != NO_BUILD)
  18988. {
  18989. FAssertMsg(!bBestBuildIsRoute, "BestBuild should not be a route");
  18990. FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
  18991. MissionTypes eBestMission = MISSION_MOVE_TO;
  18992. if ((pBestPlot->getWorkingCity() == NULL) || !pBestPlot->getWorkingCity()->isConnectedToCapital())
  18993. {
  18994. eBestMission = MISSION_ROUTE_TO;
  18995. }
  18996. else
  18997. {
  18998. int iDistance = stepDistance(getX_INLINE(), getY_INLINE(), pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  18999. int iPathTurns;
  19000. if (generatePath(pBestPlot, 0, false, &iPathTurns))
  19001. {
  19002. if (iPathTurns >= iDistance)
  19003. {
  19004. eBestMission = MISSION_ROUTE_TO;
  19005. }
  19006. }
  19007. }
  19008. eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);
  19009. getGroup()->pushMission(eBestMission, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
  19010. getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
  19011. if( gUnitLogLevel >= 3 ){logBBAI(" ... improving bonus at %d, %d with %S (value: %d)", pBestPlot->getX(), pBestPlot->getY(), GC.getBuildInfo((BuildTypes)eBestBuild).getTextKeyWide(), iBestValue);}
  19012. return true;
  19013. }
  19014. else if (bBestBuildIsRoute)
  19015. {
  19016. if (AI_connectPlot(pBestPlot))
  19017. {
  19018. if( gUnitLogLevel >= 3 ){logBBAI(" ... building road to %d, %d (value: %d)", pBestPlot->getX(), iBestValue);}
  19019. return true;
  19020. }
  19021. /*else
  19022. {
  19023. // the plot may be connected, but not connected to capital, if capital is not on same area, or if civ has no capital (like barbarians)
  19024. FAssertMsg(false, "Expected that a route could be built to eBestPlot");
  19025. }*/
  19026. }
  19027. else
  19028. {
  19029. FAssert(false);
  19030. }
  19031. }
  19032. return false;
  19033. }
  19034. //returns true if a mission is pushed
  19035. //if eBuild is NO_BUILD, assumes a route is desired.
  19036. bool CvUnitAI::AI_improvePlot(CvPlot* pPlot, BuildTypes eBuild)
  19037. {
  19038. FAssert(pPlot != NULL);
  19039. if (eBuild != NO_BUILD)
  19040. {
  19041. FAssertMsg(eBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
  19042. eBuild = AI_betterPlotBuild(pPlot, eBuild);
  19043. if (!atPlot(pPlot))
  19044. {
  19045. getGroup()->pushMission(MISSION_MOVE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pPlot);
  19046. }
  19047. getGroup()->pushMission(MISSION_BUILD, eBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pPlot);
  19048. return true;
  19049. }
  19050. else if (canBuildRoute())
  19051. {
  19052. if (AI_connectPlot(pPlot))
  19053. {
  19054. return true;
  19055. }
  19056. }
  19057. return false;
  19058. }
  19059. BuildTypes CvUnitAI::AI_betterPlotBuild(CvPlot* pPlot, BuildTypes eBuild)
  19060. {
  19061. FAssert(pPlot != NULL);
  19062. FAssert(eBuild != NO_BUILD);
  19063. bool bBuildRoute = false;
  19064. bool bClearFeature = false;
  19065. FeatureTypes eFeature = pPlot->getFeatureType();
  19066. CvBuildInfo& kOriginalBuildInfo = GC.getBuildInfo(eBuild);
  19067. if (kOriginalBuildInfo.getRoute() != NO_ROUTE)
  19068. {
  19069. return eBuild;
  19070. }
  19071. int iWorkersNeeded = AI_calculatePlotWorkersNeeded(pPlot, eBuild);
  19072. /********************************************************************************/
  19073. /* BETTER_BTS_AI_MOD 7/31/08 jdog5000 */
  19074. /* */
  19075. /* Bugfix */
  19076. /********************************************************************************/
  19077. //if ((pPlot->getBonusType() == NO_BONUS) && (pPlot->getWorkingCity() != NULL))
  19078. if ((pPlot->getNonObsoleteBonusType(getTeam()) == NO_BONUS) && (pPlot->getWorkingCity() != NULL))
  19079. {
  19080. iWorkersNeeded = std::max(1, std::min(iWorkersNeeded, pPlot->getWorkingCity()->AI_getWorkersHave()));
  19081. }
  19082. /********************************************************************************/
  19083. /* BETTER_BTS_AI_MOD END */
  19084. /********************************************************************************/
  19085. if (eFeature != NO_FEATURE)
  19086. {
  19087. CvFeatureInfo& kFeatureInfo = GC.getFeatureInfo(eFeature);
  19088. if (kOriginalBuildInfo.isFeatureRemove(eFeature)
  19089. //FfH: Added by Kael 04/24/2008
  19090. && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pPlot->getFeatureType())
  19091. //FfH: End Add
  19092. )
  19093. {
  19094. if ((kOriginalBuildInfo.getImprovement() == NO_IMPROVEMENT) || (!pPlot->isBeingWorked() || (kFeatureInfo.getYieldChange(YIELD_FOOD) + kFeatureInfo.getYieldChange(YIELD_PRODUCTION)) <= 0))
  19095. {
  19096. bClearFeature = true;
  19097. }
  19098. }
  19099. if ((kFeatureInfo.getMovementCost() > 1) && (iWorkersNeeded > 1))
  19100. {
  19101. bBuildRoute = true;
  19102. }
  19103. }
  19104. /********************************************************************************/
  19105. /* BETTER_BTS_AI_MOD 7/31/08 jdog5000 */
  19106. /* */
  19107. /* Bugfix */
  19108. /********************************************************************************/
  19109. //if (pPlot->getBonusType() != NO_BONUS)
  19110. if (pPlot->getNonObsoleteBonusType(getTeam()) != NO_BONUS)
  19111. {
  19112. bBuildRoute = true;
  19113. }
  19114. else if (pPlot->isHills())
  19115. {
  19116. if ((GC.getHILLS_EXTRA_MOVEMENT() > 0) && (iWorkersNeeded > 1))
  19117. {
  19118. bBuildRoute = true;
  19119. }
  19120. }
  19121. /********************************************************************************/
  19122. /* BETTER_BTS_AI_MOD END */
  19123. /********************************************************************************/
  19124. if (pPlot->getRouteType() != NO_ROUTE)
  19125. {
  19126. bBuildRoute = false;
  19127. }
  19128. BuildTypes eBestBuild = NO_BUILD;
  19129. int iBestValue = 0;
  19130. for (int iBuild = 0; iBuild < GC.getNumBuildInfos(); iBuild++)
  19131. {
  19132. BuildTypes eBuild = ((BuildTypes)iBuild);
  19133. CvBuildInfo& kBuildInfo = GC.getBuildInfo(eBuild);
  19134. RouteTypes eRoute = (RouteTypes)kBuildInfo.getRoute();
  19135. if ((bBuildRoute && (eRoute != NO_ROUTE)) || (bClearFeature && kBuildInfo.isFeatureRemove(eFeature)
  19136. //FfH: Added by Kael 04/24/2008
  19137. && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pPlot->getFeatureType())
  19138. //FfH: End Add
  19139. ))
  19140. {
  19141. if (canBuild(pPlot, eBuild))
  19142. {
  19143. int iValue = 10000;
  19144. if (bBuildRoute && (eRoute != NO_ROUTE))
  19145. {
  19146. iValue *= (1 + GC.getRouteInfo(eRoute).getValue());
  19147. iValue /= 2;
  19148. /********************************************************************************/
  19149. /* BETTER_BTS_AI_MOD 7/31/08 jdog5000 */
  19150. /* */
  19151. /* Bugfix */
  19152. /********************************************************************************/
  19153. //if if (pPlot->getBonusType() != NO_BONUS)
  19154. if (pPlot->getNonObsoleteBonusType(getTeam()) != NO_BONUS)
  19155. {
  19156. iValue *= 2;
  19157. }
  19158. /********************************************************************************/
  19159. /* BETTER_BTS_AI_MOD END */
  19160. /********************************************************************************/
  19161. if (pPlot->getWorkingCity() != NULL)
  19162. {
  19163. iValue *= 2 + iWorkersNeeded + ((pPlot->isHills() && (iWorkersNeeded > 1)) ? 2 * GC.getHILLS_EXTRA_MOVEMENT() : 0);
  19164. iValue /= 3;
  19165. }
  19166. ImprovementTypes eImprovement = (ImprovementTypes)kOriginalBuildInfo.getImprovement();
  19167. if (eImprovement != NO_IMPROVEMENT)
  19168. {
  19169. int iRouteMultiplier = ((GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eRoute, YIELD_FOOD)) * 100);
  19170. iRouteMultiplier += ((GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eRoute, YIELD_PRODUCTION)) * 100);
  19171. iRouteMultiplier += ((GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eRoute, YIELD_COMMERCE)) * 60);
  19172. iValue *= 100 + iRouteMultiplier;
  19173. iValue /= 100;
  19174. }
  19175. int iPlotGroupId = -1;
  19176. for (int iDirection = 0; iDirection < NUM_DIRECTION_TYPES; iDirection++)
  19177. {
  19178. CvPlot* pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), (DirectionTypes)iDirection);
  19179. if (pLoopPlot != NULL)
  19180. {
  19181. if (pPlot->isRiver() || (pLoopPlot->getRouteType() != NO_ROUTE))
  19182. {
  19183. CvPlotGroup* pLoopGroup = pLoopPlot->getPlotGroup(getOwnerINLINE());
  19184. if (pLoopGroup != NULL)
  19185. {
  19186. if (pLoopGroup->getID() != -1)
  19187. {
  19188. if (pLoopGroup->getID() != iPlotGroupId)
  19189. {
  19190. //This plot bridges plot groups, so route it.
  19191. iValue *= 4;
  19192. break;
  19193. }
  19194. else
  19195. {
  19196. iPlotGroupId = pLoopGroup->getID();
  19197. }
  19198. }
  19199. }
  19200. }
  19201. }
  19202. }
  19203. }
  19204. iValue /= (kBuildInfo.getTime() + 1);
  19205. if (iValue > iBestValue)
  19206. {
  19207. iBestValue = iValue;
  19208. eBestBuild = eBuild;
  19209. }
  19210. }
  19211. }
  19212. }
  19213. if (eBestBuild == NO_BUILD)
  19214. {
  19215. return eBuild;
  19216. }
  19217. return eBestBuild;
  19218. }
  19219. // Returns true if a mission was pushed...
  19220. bool CvUnitAI::AI_connectBonus(bool bTestTrade)
  19221. {
  19222. PROFILE_FUNC();
  19223. CvPlot* pLoopPlot;
  19224. BonusTypes eNonObsoleteBonus;
  19225. int iI;
  19226. // XXX how do we make sure that we can build roads???
  19227. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  19228. {
  19229. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  19230. if (AI_plotValid(pLoopPlot))
  19231. {
  19232. if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
  19233. {
  19234. eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());
  19235. if (eNonObsoleteBonus != NO_BONUS)
  19236. {
  19237. if (!(pLoopPlot->isConnectedToCapital()))
  19238. {
  19239. //if (!bTestTrade || ((pLoopPlot->getImprovementType() != NO_IMPROVEMENT) && (GC.getImprovementInfo(pLoopPlot->getImprovementType()).isImprovementBonusTrade(eNonObsoleteBonus))))
  19240. if (!bTestTrade || GET_PLAYER(getOwnerINLINE()).doesImprovementConnectBonus(pLoopPlot->getImprovementType(), eNonObsoleteBonus))
  19241. {
  19242. if (AI_connectPlot(pLoopPlot))
  19243. {
  19244. return true;
  19245. }
  19246. }
  19247. }
  19248. }
  19249. }
  19250. }
  19251. }
  19252. return false;
  19253. }
  19254. // Returns true if a mission was pushed...
  19255. bool CvUnitAI::AI_connectCity()
  19256. {
  19257. PROFILE_FUNC();
  19258. CvCity* pLoopCity;
  19259. int iLoop;
  19260. // XXX how do we make sure that we can build roads???
  19261. pLoopCity = plot()->getWorkingCity();
  19262. if (pLoopCity != NULL)
  19263. {
  19264. if (AI_plotValid(pLoopCity->plot()))
  19265. {
  19266. if (!(pLoopCity->isConnectedToCapital()))
  19267. {
  19268. if (AI_connectPlot(pLoopCity->plot(), 1))
  19269. {
  19270. return true;
  19271. }
  19272. }
  19273. }
  19274. }
  19275. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  19276. {
  19277. if (AI_plotValid(pLoopCity->plot()))
  19278. {
  19279. if (!(pLoopCity->isConnectedToCapital()))
  19280. {
  19281. if (AI_connectPlot(pLoopCity->plot(), 1))
  19282. {
  19283. return true;
  19284. }
  19285. }
  19286. }
  19287. }
  19288. return false;
  19289. }
  19290. // Returns true if a mission was pushed...
  19291. bool CvUnitAI::AI_routeCity()
  19292. {
  19293. PROFILE_FUNC();
  19294. CvCity* pRouteToCity;
  19295. CvCity* pLoopCity;
  19296. int iLoop;
  19297. FAssert(canBuildRoute());
  19298. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  19299. {
  19300. if (AI_plotValid(pLoopCity->plot()))
  19301. {
  19302. /************************************************************************************************/
  19303. /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
  19304. /* */
  19305. /* Unit AI, Efficiency */
  19306. /************************************************************************************************/
  19307. // BBAI efficiency: check area for land units before generating path
  19308. if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
  19309. {
  19310. continue;
  19311. }
  19312. pRouteToCity = pLoopCity->AI_getRouteToCity();
  19313. if (pRouteToCity != NULL)
  19314. {
  19315. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  19316. {
  19317. if (!(pRouteToCity->plot()->isVisibleEnemyUnit(this)))
  19318. {
  19319. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pRouteToCity->plot(), MISSIONAI_BUILD, getGroup()) == 0)
  19320. {
  19321. if (generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true))
  19322. {
  19323. /************************************************************************************************/
  19324. /* BETTER_BTS_AI_MOD END */
  19325. /************************************************************************************************/
  19326. if (generatePath(pRouteToCity->plot(), MOVE_SAFE_TERRITORY, true))
  19327. {
  19328. getGroup()->pushMission(MISSION_ROUTE_TO, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pRouteToCity->plot());
  19329. getGroup()->pushMission(MISSION_ROUTE_TO, pRouteToCity->getX_INLINE(), pRouteToCity->getY_INLINE(), MOVE_SAFE_TERRITORY, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pRouteToCity->plot());
  19330. return true;
  19331. }
  19332. }
  19333. }
  19334. }
  19335. }
  19336. }
  19337. }
  19338. }
  19339. return false;
  19340. }
  19341. // Returns true if a mission was pushed...
  19342. bool CvUnitAI::AI_routeTerritory(bool bImprovementOnly)
  19343. {
  19344. PROFILE_FUNC();
  19345. CvPlot* pLoopPlot;
  19346. CvPlot* pBestPlot;
  19347. ImprovementTypes eImprovement;
  19348. RouteTypes eBestRoute;
  19349. bool bValid;
  19350. int iPathTurns;
  19351. int iValue;
  19352. int iBestValue;
  19353. int iI, iJ;
  19354. // XXX how do we make sure that we can build roads???
  19355. FAssert(canBuildRoute());
  19356. iBestValue = 0;
  19357. pBestPlot = NULL;
  19358. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  19359. {
  19360. pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  19361. if (AI_plotValid(pLoopPlot))
  19362. {
  19363. if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
  19364. {
  19365. eBestRoute = GET_PLAYER(getOwnerINLINE()).getBestRoute(pLoopPlot);
  19366. if (eBestRoute != NO_ROUTE)
  19367. {
  19368. if (eBestRoute != pLoopPlot->getRouteType())
  19369. {
  19370. if (bImprovementOnly)
  19371. {
  19372. bValid = false;
  19373. eImprovement = pLoopPlot->getImprovementType();
  19374. if (eImprovement != NO_IMPROVEMENT)
  19375. {
  19376. for (iJ = 0; iJ < NUM_YIELD_TYPES; iJ++)
  19377. {
  19378. if (GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eBestRoute, iJ) > 0)
  19379. {
  19380. bValid = true;
  19381. break;
  19382. }
  19383. }
  19384. }
  19385. }
  19386. else
  19387. {
  19388. bValid = true;
  19389. }
  19390. if (bValid)
  19391. {
  19392. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  19393. {
  19394. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 1) == 0)
  19395. {
  19396. if (generatePath(pLoopPlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
  19397. {
  19398. iValue = 10000;
  19399. iValue /= (iPathTurns + 1);
  19400. if (iValue > iBestValue)
  19401. {
  19402. iBestValue = iValue;
  19403. pBestPlot = pLoopPlot;
  19404. }
  19405. }
  19406. }
  19407. }
  19408. }
  19409. }
  19410. }
  19411. }
  19412. }
  19413. }
  19414. if (pBestPlot != NULL)
  19415. {
  19416. getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pBestPlot);
  19417. return true;
  19418. }
  19419. return false;
  19420. }
  19421. // Returns true if a mission was pushed...
  19422. bool CvUnitAI::AI_travelToUpgradeCity()
  19423. {
  19424. PROFILE_FUNC();
  19425. // is there a city which can upgrade us?
  19426. CvCity* pUpgradeCity = getUpgradeCity(/*bSearch*/ true);
  19427. if (pUpgradeCity != NULL)
  19428. {
  19429. // cache some stuff
  19430. CvPlot* pPlot = plot();
  19431. bool bSeaUnit = (getDomainType() == DOMAIN_SEA);
  19432. bool bCanAirliftUnit = (getDomainType() == DOMAIN_LAND);
  19433. bool bShouldSkipToUpgrade = (getDomainType() != DOMAIN_AIR);
  19434. // if we at the upgrade city, stop, wait to get upgraded
  19435. if (pUpgradeCity->plot() == pPlot || isUpgradeOutsideBorders())
  19436. {
  19437. if (!bShouldSkipToUpgrade)
  19438. {
  19439. return false;
  19440. }
  19441. getGroup()->pushMission(MISSION_SKIP);
  19442. return true;
  19443. }
  19444. if (DOMAIN_AIR == getDomainType())
  19445. {
  19446. FAssert(!atPlot(pUpgradeCity->plot()));
  19447. getGroup()->pushMission(MISSION_MOVE_TO, pUpgradeCity->getX_INLINE(), pUpgradeCity->getY_INLINE());
  19448. return true;
  19449. }
  19450. // find the closest city
  19451. CvCity* pClosestCity = pPlot->getPlotCity();
  19452. bool bAtClosestCity = (pClosestCity != NULL);
  19453. if (pClosestCity == NULL)
  19454. {
  19455. pClosestCity = pPlot->getWorkingCity();
  19456. }
  19457. if (pClosestCity == NULL)
  19458. {
  19459. pClosestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), NO_PLAYER, getTeam(), true, bSeaUnit);
  19460. }
  19461. // can we path to the upgrade city?
  19462. int iUpgradeCityPathTurns;
  19463. CvPlot* pThisTurnPlot = NULL;
  19464. bool bCanPathToUpgradeCity = generatePath(pUpgradeCity->plot(), 0, true, &iUpgradeCityPathTurns);
  19465. if (bCanPathToUpgradeCity)
  19466. {
  19467. pThisTurnPlot = getPathEndTurnPlot();
  19468. }
  19469. // if we close to upgrade city, head there
  19470. if (NULL != pThisTurnPlot && NULL != pClosestCity && (pClosestCity == pUpgradeCity || iUpgradeCityPathTurns < 4))
  19471. {
  19472. FAssert(!atPlot(pThisTurnPlot));
  19473. getGroup()->pushMission(MISSION_MOVE_TO, pThisTurnPlot->getX_INLINE(), pThisTurnPlot->getY_INLINE());
  19474. if( gUnitLogLevel >= 3 )
  19475. {
  19476. logBBAI(" %S (unit %d - %S) (groupsize: %d) traveling to upgrade city %S \n", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription(), getGroup()->getNumUnits(), pUpgradeCity->getName().GetCString());
  19477. }
  19478. return true;
  19479. }
  19480. // check for better airlift choice
  19481. if (bCanAirliftUnit && NULL != pClosestCity && pClosestCity->getMaxAirlift() > 0)
  19482. {
  19483. // if we at the closest city, then do the airlift, or wait
  19484. if (bAtClosestCity)
  19485. {
  19486. // can we do the airlift this turn?
  19487. if (canAirliftAt(pClosestCity->plot(), pUpgradeCity->getX_INLINE(), pUpgradeCity->getY_INLINE()))
  19488. {
  19489. getGroup()->pushMission(MISSION_AIRLIFT, pUpgradeCity->getX_INLINE(), pUpgradeCity->getY_INLINE());
  19490. return true;
  19491. }
  19492. // wait to do it next turn
  19493. else
  19494. {
  19495. getGroup()->pushMission(MISSION_SKIP);
  19496. return true;
  19497. }
  19498. }
  19499. int iClosestCityPathTurns;
  19500. CvPlot* pThisTurnPlotForAirlift = NULL;
  19501. bool bCanPathToClosestCity = generatePath(pClosestCity->plot(), 0, true, &iClosestCityPathTurns);
  19502. if (bCanPathToClosestCity)
  19503. {
  19504. pThisTurnPlotForAirlift = getPathEndTurnPlot();
  19505. }
  19506. // is the closest city closer pathing? If so, move toward closest city
  19507. if (NULL != pThisTurnPlotForAirlift && (!bCanPathToUpgradeCity || iClosestCityPathTurns < iUpgradeCityPathTurns))
  19508. {
  19509. FAssert(!atPlot(pThisTurnPlotForAirlift));
  19510. getGroup()->pushMission(MISSION_MOVE_TO, pThisTurnPlotForAirlift->getX_INLINE(), pThisTurnPlotForAirlift->getY_INLINE());
  19511. return true;
  19512. }
  19513. }
  19514. // did not have better airlift choice, go ahead and path to the upgrade city
  19515. if (NULL != pThisTurnPlot)
  19516. {
  19517. FAssert(!atPlot(pThisTurnPlot));
  19518. getGroup()->pushMission(MISSION_MOVE_TO, pThisTurnPlot->getX_INLINE(), pThisTurnPlot->getY_INLINE());
  19519. if( gUnitLogLevel >= 3 )
  19520. {
  19521. logBBAI(" %S (unit %d - %S) (groupsize: %d) traveling to upgrade city (2) %S \n", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription(), getGroup()->getNumUnits(), pUpgradeCity->getName().GetCString());
  19522. }
  19523. return true;
  19524. }
  19525. }
  19526. return false;
  19527. }
  19528. // Returns true if a mission was pushed...
  19529. bool CvUnitAI::AI_retreatToCity(bool bPrimary, bool bAirlift, int iMaxPath)
  19530. {
  19531. PROFILE_FUNC();
  19532. CvCity* pCity;
  19533. CvCity* pLoopCity;
  19534. CvPlot* pBestPlot = NULL;
  19535. int iPathTurns;
  19536. int iValue;
  19537. int iBestValue = MAX_INT;
  19538. int iPass;
  19539. int iLoop;
  19540. int iCurrentDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot());
  19541. pCity = plot()->getPlotCity();
  19542. if (0 == iCurrentDanger)
  19543. {
  19544. if (pCity != NULL)
  19545. {
  19546. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  19547. {
  19548. if (!bPrimary || GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pCity->area()))
  19549. {
  19550. if (!bAirlift || (pCity->getMaxAirlift() > 0))
  19551. {
  19552. if (!(pCity->plot()->isVisibleEnemyUnit(this)))
  19553. {
  19554. getGroup()->pushMission(MISSION_SKIP);
  19555. return true;
  19556. }
  19557. }
  19558. }
  19559. }
  19560. }
  19561. }
  19562. for (iPass = 0; iPass < 4; iPass++)
  19563. {
  19564. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  19565. {
  19566. if (AI_plotValid(pLoopCity->plot()))
  19567. {
  19568. if (!bPrimary || GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopCity->area()))
  19569. {
  19570. if (!bAirlift || (pLoopCity->getMaxAirlift() > 0))
  19571. {
  19572. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  19573. {
  19574. /************************************************************************************************/
  19575. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  19576. /* */
  19577. /* Unit AI, Efficiency */
  19578. /************************************************************************************************/
  19579. // BBAI efficiency: check area for land units before generating path
  19580. if( !bAirlift && (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
  19581. {
  19582. continue;
  19583. }
  19584. /************************************************************************************************/
  19585. /* BETTER_BTS_AI_MOD END */
  19586. /************************************************************************************************/
  19587. if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), ((iPass > 1) ? MOVE_IGNORE_DANGER : 0), true, &iPathTurns))
  19588. {
  19589. if (iPathTurns <= ((iPass == 2) ? 1 : iMaxPath))
  19590. {
  19591. /************************************************************************************************/
  19592. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  19593. /* */
  19594. /* Naval AI */
  19595. /************************************************************************************************/
  19596. /* original bts code
  19597. if ((iPass > 0) || (getGroup()->canFight() || GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopCity->plot()) < iCurrentDanger))
  19598. */
  19599. // Water units can't defend a city
  19600. // Any unthreatened city acceptable on 0th pass, solves problem where sea units
  19601. // would oscillate in and out of threatened city because they had iCurrentDanger = 0
  19602. // on turns outside city
  19603. bool bCheck = (iPass > 0) || (getGroup()->canDefend());
  19604. if( !bCheck )
  19605. {
  19606. int iLoopDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopCity->plot());
  19607. bCheck = (iLoopDanger == 0) || (iLoopDanger < iCurrentDanger);
  19608. }
  19609. if( bCheck )
  19610. /************************************************************************************************/
  19611. /* BETTER_BTS_AI_MOD END */
  19612. /************************************************************************************************/
  19613. {
  19614. iValue = iPathTurns;
  19615. if (AI_getUnitAIType() == UNITAI_SETTLER_SEA)
  19616. {
  19617. iValue *= 1 + std::max(0, GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), UNITAI_SETTLE) - GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), UNITAI_SETTLER_SEA));
  19618. }
  19619. if (iValue < iBestValue)
  19620. {
  19621. iBestValue = iValue;
  19622. pBestPlot = getPathEndTurnPlot();
  19623. /************************************************************************************************/
  19624. /* BETTER_BTS_AI_MOD 01/27/08 jdog5000 */
  19625. /* */
  19626. /* Bugfix */
  19627. /************************************************************************************************/
  19628. // Not sure what can go wrong here, it seems somehow m_iData1 (moves) was set to 0
  19629. // for first node in path so m_iData2 (turns) incremented
  19630. if( atPlot(pBestPlot) )
  19631. {
  19632. //FAssert(false);
  19633. pBestPlot = getGroup()->getPathFirstPlot();
  19634. FAssert(!atPlot(pBestPlot));
  19635. }
  19636. /************************************************************************************************/
  19637. /* BETTER_BTS_AI_MOD END */
  19638. /************************************************************************************************/
  19639. }
  19640. }
  19641. }
  19642. }
  19643. }
  19644. }
  19645. }
  19646. }
  19647. }
  19648. if (pBestPlot != NULL)
  19649. {
  19650. break;
  19651. }
  19652. else if (iPass == 0)
  19653. {
  19654. if (pCity != NULL)
  19655. {
  19656. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  19657. {
  19658. if (!bPrimary || GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pCity->area()))
  19659. {
  19660. if (!bAirlift || (pCity->getMaxAirlift() > 0))
  19661. {
  19662. if (!(pCity->plot()->isVisibleEnemyUnit(this)))
  19663. {
  19664. getGroup()->pushMission(MISSION_SKIP);
  19665. return true;
  19666. }
  19667. }
  19668. }
  19669. }
  19670. }
  19671. }
  19672. if (getGroup()->alwaysInvisible())
  19673. {
  19674. break;
  19675. }
  19676. }
  19677. if (pBestPlot != NULL)
  19678. {
  19679. FAssert(!atPlot(pBestPlot));
  19680. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((iPass > 0) ? MOVE_IGNORE_DANGER : 0));
  19681. return true;
  19682. }
  19683. if (pCity != NULL)
  19684. {
  19685. if (pCity->getTeam() == getTeam())
  19686. {
  19687. getGroup()->pushMission(MISSION_SKIP);
  19688. return true;
  19689. }
  19690. }
  19691. return false;
  19692. }
  19693. // Returns true if a mission was pushed...
  19694. /************************************************************************************************/
  19695. /* BETTER_BTS_AI_MOD 01/15/09 jdog5000 */
  19696. /* */
  19697. /* Naval AI */
  19698. /************************************************************************************************/
  19699. /* original bts code
  19700. bool CvUnitAI::AI_pickup(UnitAITypes eUnitAI)
  19701. */
  19702. bool CvUnitAI::AI_pickup(UnitAITypes eUnitAI, bool bCountProduction, int iMaxPath)
  19703. /************************************************************************************************/
  19704. /* BETTER_BTS_AI_MOD END */
  19705. /************************************************************************************************/
  19706. {
  19707. PROFILE_FUNC();
  19708. CvCity* pCity;
  19709. CvCity* pLoopCity;
  19710. CvPlot* pBestPlot;
  19711. CvPlot* pBestPickupPlot;
  19712. int iPathTurns;
  19713. int iValue;
  19714. int iBestValue;
  19715. int iLoop;
  19716. FAssert(cargoSpace() > 0);
  19717. if (0 == cargoSpace())
  19718. {
  19719. return false;
  19720. }
  19721. pCity = plot()->getPlotCity();
  19722. if (pCity != NULL)
  19723. {
  19724. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  19725. {
  19726. /************************************************************************************************/
  19727. /* BETTER_BTS_AI_MOD 01/23/09 jdog5000 */
  19728. /* */
  19729. /* Naval AI */
  19730. /************************************************************************************************/
  19731. /* original bts code
  19732. if (pCity->plot()->plotCount(PUF_isUnitAIType, eUnitAI, -1, getOwnerINLINE()) > 0)
  19733. {
  19734. if ((AI_getUnitAIType() != UNITAI_ASSAULT_SEA) || pCity->AI_isDefended(-1))
  19735. {
  19736. */
  19737. if( (GC.getGameINLINE().getGameTurn() - pCity->getGameTurnAcquired()) > 15 || (GET_TEAM(getTeam()).countEnemyPowerByArea(pCity->area()) == 0) )
  19738. {
  19739. bool bConsider = false;
  19740. if(AI_getUnitAIType() == UNITAI_ASSAULT_SEA)
  19741. {
  19742. // Improve island hopping
  19743. if( pCity->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE )
  19744. {
  19745. bConsider = false;
  19746. }
  19747. else if( eUnitAI == UNITAI_ATTACK_CITY && !(pCity->AI_isDanger()) )
  19748. {
  19749. bConsider = (pCity->plot()->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isDomainType, DOMAIN_LAND) > pCity->AI_neededDefenders());
  19750. }
  19751. else
  19752. {
  19753. bConsider = pCity->AI_isDefended(-1);
  19754. }
  19755. }
  19756. else if(AI_getUnitAIType() == UNITAI_SETTLER_SEA)
  19757. {
  19758. if( eUnitAI == UNITAI_CITY_DEFENSE )
  19759. {
  19760. bConsider = (pCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isCityAIType) > 1);
  19761. }
  19762. else
  19763. {
  19764. bConsider = true;
  19765. }
  19766. }
  19767. else
  19768. {
  19769. bConsider = true;
  19770. }
  19771. if ( bConsider )
  19772. {
  19773. // only count units which are available to load
  19774. int iCount = pCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, eUnitAI, -1, getOwnerINLINE(), NO_TEAM, PUF_isFiniteRange);
  19775. if (bCountProduction && (pCity->getProductionUnitAI() == eUnitAI))
  19776. {
  19777. if( pCity->getProductionTurnsLeft() < 4 )
  19778. {
  19779. CvUnitInfo& kUnitInfo = GC.getUnitInfo(pCity->getProductionUnit());
  19780. if ((kUnitInfo.getDomainType() != DOMAIN_AIR) || kUnitInfo.getAirRange() > 0)
  19781. {
  19782. iCount++;
  19783. }
  19784. }
  19785. }
  19786. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCity->plot(), MISSIONAI_PICKUP, getGroup()) < ((iCount + (cargoSpace() - 1)) / cargoSpace()))
  19787. {
  19788. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_PICKUP, pCity->plot());
  19789. return true;
  19790. }
  19791. }
  19792. }
  19793. /************************************************************************************************/
  19794. /* BETTER_BTS_AI_MOD END */
  19795. /************************************************************************************************/
  19796. }
  19797. }
  19798. iBestValue = 0;
  19799. pBestPlot = NULL;
  19800. pBestPickupPlot = NULL;
  19801. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  19802. {
  19803. if (AI_plotValid(pLoopCity->plot()))
  19804. {
  19805. /************************************************************************************************/
  19806. /* BETTER_BTS_AI_MOD 01/23/09 jdog5000 */
  19807. /* */
  19808. /* Naval AI */
  19809. /************************************************************************************************/
  19810. if( (GC.getGameINLINE().getGameTurn() - pLoopCity->getGameTurnAcquired()) > 15 || (GET_TEAM(getTeam()).countEnemyPowerByArea(pLoopCity->area()) == 0) )
  19811. {
  19812. bool bConsider = false;
  19813. if(AI_getUnitAIType() == UNITAI_ASSAULT_SEA)
  19814. {
  19815. if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE )
  19816. {
  19817. bConsider = false;
  19818. }
  19819. else if( eUnitAI == UNITAI_ATTACK_CITY && !(pLoopCity->AI_isDanger()) )
  19820. {
  19821. // Improve island hopping
  19822. bConsider = (pLoopCity->plot()->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isDomainType, DOMAIN_LAND) > pLoopCity->AI_neededDefenders());
  19823. }
  19824. else
  19825. {
  19826. bConsider = pLoopCity->AI_isDefended(-1);
  19827. }
  19828. }
  19829. else if(AI_getUnitAIType() == UNITAI_SETTLER_SEA)
  19830. {
  19831. if( eUnitAI == UNITAI_CITY_DEFENSE )
  19832. {
  19833. bConsider = (pLoopCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isCityAIType) > 1);
  19834. }
  19835. else
  19836. {
  19837. bConsider = true;
  19838. }
  19839. }
  19840. else
  19841. {
  19842. bConsider = true;
  19843. }
  19844. if ( bConsider )
  19845. {
  19846. // only count units which are available to load, have had a chance to move since being built
  19847. int iCount = pLoopCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, eUnitAI, -1, getOwnerINLINE(), NO_TEAM, (bCountProduction ? PUF_isFiniteRange : PUF_isFiniteRangeAndNotJustProduced));
  19848. iValue = iCount * 10;
  19849. if (bCountProduction && (pLoopCity->getProductionUnitAI() == eUnitAI))
  19850. {
  19851. CvUnitInfo& kUnitInfo = GC.getUnitInfo(pLoopCity->getProductionUnit());
  19852. if ((kUnitInfo.getDomainType() != DOMAIN_AIR) || kUnitInfo.getAirRange() > 0)
  19853. {
  19854. iValue++;
  19855. iCount++;
  19856. }
  19857. }
  19858. if (iValue > 0)
  19859. {
  19860. iValue += pLoopCity->getPopulation();
  19861. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  19862. {
  19863. if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_PICKUP, getGroup()) < ((iCount + (cargoSpace() - 1)) / cargoSpace()))
  19864. {
  19865. if( !(pLoopCity->AI_isDanger()) )
  19866. {
  19867. if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  19868. {
  19869. if( AI_getUnitAIType() == UNITAI_ASSAULT_SEA )
  19870. {
  19871. if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT )
  19872. {
  19873. iValue *= 4;
  19874. }
  19875. else if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT_ASSIST )
  19876. {
  19877. iValue *= 2;
  19878. }
  19879. }
  19880. iValue *= 1000;
  19881. iValue /= (iPathTurns + 3);
  19882. if( (iValue > iBestValue) && (iPathTurns <= iMaxPath) )
  19883. {
  19884. iBestValue = iValue;
  19885. // Do one turn along path, then reevaluate
  19886. // Causes update of destination based on troop movement
  19887. //pBestPlot = pLoopCity->plot();
  19888. pBestPlot = getPathEndTurnPlot();
  19889. pBestPickupPlot = pLoopCity->plot();
  19890. if( pBestPlot == NULL || atPlot(pBestPlot) )
  19891. {
  19892. //FAssert(false);
  19893. pBestPlot = pBestPickupPlot;
  19894. }
  19895. }
  19896. }
  19897. }
  19898. }
  19899. }
  19900. }
  19901. }
  19902. }
  19903. }
  19904. }
  19905. /************************************************************************************************/
  19906. /* BETTER_BTS_AI_MOD END */
  19907. /************************************************************************************************/
  19908. if ((pBestPlot != NULL) && (pBestPickupPlot != NULL))
  19909. {
  19910. FAssert(!atPlot(pBestPlot));
  19911. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_PICKUP, pBestPickupPlot);
  19912. return true;
  19913. }
  19914. return false;
  19915. }
  19916. /************************************************************************************************/
  19917. /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
  19918. /* */
  19919. /* Naval AI */
  19920. /************************************************************************************************/
  19921. // Returns true if a mission was pushed...
  19922. bool CvUnitAI::AI_pickupStranded(UnitAITypes eUnitAI, int iMaxPath)
  19923. {
  19924. PROFILE_FUNC();
  19925. CvUnit* pBestUnit;
  19926. int iPathTurns;
  19927. int iValue;
  19928. int iBestValue;
  19929. int iLoop;
  19930. int iCount;
  19931. FAssert(cargoSpace() > 0);
  19932. if (0 == cargoSpace())
  19933. {
  19934. return false;
  19935. }
  19936. if( isBarbarian() )
  19937. {
  19938. return false;
  19939. }
  19940. iBestValue = 0;
  19941. pBestUnit = NULL;
  19942. int iI;
  19943. CvSelectionGroup* pLoopGroup = NULL;
  19944. CvUnit* pHeadUnit = NULL;
  19945. CvPlot* pLoopPlot = NULL;
  19946. CvPlot* pPickupPlot = NULL;
  19947. CvPlot* pAdjacentPlot = NULL;
  19948. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  19949. for(pLoopGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = kPlayer.nextSelectionGroup(&iLoop))
  19950. {
  19951. if( pLoopGroup->isStranded() )
  19952. {
  19953. pHeadUnit = pLoopGroup->getHeadUnit();
  19954. if( pHeadUnit == NULL )
  19955. {
  19956. continue;
  19957. }
  19958. if( (eUnitAI != NO_UNITAI) && (pHeadUnit->AI_getUnitAIType() != eUnitAI) )
  19959. {
  19960. continue;
  19961. }
  19962. pLoopPlot = pHeadUnit->plot();
  19963. if( pLoopPlot == NULL )
  19964. {
  19965. continue;
  19966. }
  19967. if( !(pLoopPlot->isCoastalLand()) && !canMoveAllTerrain() )
  19968. {
  19969. continue;
  19970. }
  19971. // Units are stranded, attempt rescue
  19972. iCount = pLoopGroup->getNumUnits();
  19973. if( 1000*iCount > iBestValue )
  19974. {
  19975. pPickupPlot = NULL;
  19976. if( atPlot(pLoopPlot) )
  19977. {
  19978. pPickupPlot = pLoopPlot;
  19979. iPathTurns = 0;
  19980. }
  19981. else if( AI_plotValid(pLoopPlot) && generatePath(pLoopPlot, 0, true, &iPathTurns) )
  19982. {
  19983. pPickupPlot = pLoopPlot;
  19984. }
  19985. else
  19986. {
  19987. for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  19988. {
  19989. pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));
  19990. if (pAdjacentPlot != NULL && atPlot(pLoopPlot))
  19991. {
  19992. pPickupPlot = pAdjacentPlot;
  19993. iPathTurns = 0;
  19994. break;
  19995. }
  19996. }
  19997. if (pPickupPlot == NULL)
  19998. {
  19999. for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  20000. {
  20001. pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));
  20002. if (pAdjacentPlot != NULL && AI_plotValid(pAdjacentPlot))
  20003. {
  20004. if( generatePath(pAdjacentPlot, 0, true, &iPathTurns) )
  20005. {
  20006. pPickupPlot = pAdjacentPlot;
  20007. break;
  20008. }
  20009. }
  20010. }
  20011. }
  20012. }
  20013. if( pPickupPlot != NULL && iPathTurns <= iMaxPath )
  20014. {
  20015. MissionAITypes eMissionAIType = MISSIONAI_PICKUP;
  20016. iCount -= GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pHeadUnit, &eMissionAIType, 1, getGroup(), iPathTurns) * cargoSpace();
  20017. iValue = 1000*iCount;
  20018. iValue /= (iPathTurns + 1);
  20019. if (iValue > iBestValue)
  20020. {
  20021. iBestValue = iValue;
  20022. pBestUnit = pHeadUnit;
  20023. }
  20024. }
  20025. }
  20026. }
  20027. }
  20028. if ((pBestUnit != NULL))
  20029. {
  20030. if( atPlot(pBestUnit->plot()) )
  20031. {
  20032. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_PICKUP, pBestUnit->plot());
  20033. return true;
  20034. }
  20035. else
  20036. {
  20037. FAssert(!atPlot(pBestUnit->plot()));
  20038. getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_PICKUP, NULL, pBestUnit);
  20039. return true;
  20040. }
  20041. }
  20042. return false;
  20043. }
  20044. /************************************************************************************************/
  20045. /* BETTER_BTS_AI_MOD END */
  20046. /************************************************************************************************/
  20047. // Returns true if a mission was pushed...
  20048. bool CvUnitAI::AI_airOffensiveCity()
  20049. {
  20050. //PROFILE_FUNC();
  20051. CvPlot* pBestPlot;
  20052. int iValue;
  20053. int iBestValue;
  20054. int iI;
  20055. FAssert(canAirAttack() || nukeRange() >= 0);
  20056. iBestValue = 0;
  20057. pBestPlot = NULL;
  20058. /********************************************************************************/
  20059. /* BETTER_BTS_AI_MOD 04/25/08 jdog5000 */
  20060. /* */
  20061. /* Air AI */
  20062. /********************************************************************************/
  20063. /* original BTS code
  20064. */
  20065. for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  20066. {
  20067. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  20068. // Limit to cities and forts, true for any city but only this team's forts
  20069. if (pLoopPlot->isCity(true, getTeam()))
  20070. {
  20071. if (pLoopPlot->getTeam() == getTeam() || (pLoopPlot->isOwned() && GET_TEAM(pLoopPlot->getTeam()).isVassal(getTeam())))
  20072. {
  20073. if (atPlot(pLoopPlot) || canMoveInto(pLoopPlot))
  20074. {
  20075. iValue = AI_airOffenseBaseValue( pLoopPlot );
  20076. if (iValue > iBestValue)
  20077. {
  20078. iBestValue = iValue;
  20079. pBestPlot = pLoopPlot;
  20080. }
  20081. }
  20082. }
  20083. }
  20084. }
  20085. if (pBestPlot != NULL)
  20086. {
  20087. if (!atPlot(pBestPlot))
  20088. {
  20089. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY);
  20090. return true;
  20091. }
  20092. }
  20093. /********************************************************************************/
  20094. /* BETTER_BTS_AI_MOD END */
  20095. /********************************************************************************/
  20096. return false;
  20097. }
  20098. /********************************************************************************/
  20099. /* BETTER_BTS_AI_MOD 04/25/10 jdog5000 */
  20100. /* */
  20101. /* Air AI */
  20102. /********************************************************************************/
  20103. // Function for ranking the value of a plot as a base for offensive air units
  20104. int CvUnitAI::AI_airOffenseBaseValue( CvPlot* pPlot )
  20105. {
  20106. if( pPlot == NULL || pPlot->area() == NULL )
  20107. {
  20108. return 0;
  20109. }
  20110. CvCity* pNearestEnemyCity = NULL;
  20111. int iRange = 0;
  20112. int iTempValue = 0;
  20113. int iOurDefense = 0;
  20114. int iOurOffense = 0;
  20115. int iEnemyOffense = 0;
  20116. int iEnemyDefense = 0;
  20117. int iDistance = 0;
  20118. CvPlot* pLoopPlot = NULL;
  20119. CvCity* pCity = pPlot->getPlotCity();
  20120. int iDefenders = pPlot->plotCount(PUF_canDefend, -1, -1, pPlot->getOwner());
  20121. int iAttackAirCount = pPlot->plotCount(PUF_canAirAttack, -1, -1, NO_PLAYER, getTeam());
  20122. iAttackAirCount += 2 * pPlot->plotCount(PUF_isUnitAIType, UNITAI_ICBM, -1, NO_PLAYER, getTeam());
  20123. if (atPlot(pPlot))
  20124. {
  20125. iAttackAirCount += canAirAttack() ? -1 : 0;
  20126. iAttackAirCount += (nukeRange() >= 0) ? -2 : 0;
  20127. }
  20128. if( pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()) )
  20129. {
  20130. iDefenders -= 1;
  20131. }
  20132. if( pCity != NULL )
  20133. {
  20134. if( pCity->getDefenseModifier(true) < 40 )
  20135. {
  20136. iDefenders -= 1;
  20137. }
  20138. if( pCity->getOccupationTimer() > 1 )
  20139. {
  20140. iDefenders -= 1;
  20141. }
  20142. }
  20143. // Consider threat from nearby enemy territory
  20144. iRange = 1;
  20145. int iBorderDanger = 0;
  20146. for (int iDX = -(iRange); iDX <= iRange; iDX++)
  20147. {
  20148. for (int iDY = -(iRange); iDY <= iRange; iDY++)
  20149. {
  20150. pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
  20151. if (pLoopPlot != NULL)
  20152. {
  20153. if (pLoopPlot->area() == pPlot->area() && pLoopPlot->isOwned())
  20154. {
  20155. iDistance = stepDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
  20156. if( pLoopPlot->getTeam() != getTeam() && !(GET_TEAM(pLoopPlot->getTeam()).isVassal(getTeam())) )
  20157. {
  20158. if( iDistance == 1 )
  20159. {
  20160. iBorderDanger++;
  20161. }
  20162. if (atWar(pLoopPlot->getTeam(), getTeam()))
  20163. {
  20164. if (iDistance == 1)
  20165. {
  20166. iBorderDanger += 2;
  20167. }
  20168. else if ((iDistance == 2) && (pLoopPlot->isRoute()))
  20169. {
  20170. iBorderDanger += 2;
  20171. }
  20172. }
  20173. }
  20174. }
  20175. }
  20176. }
  20177. }
  20178. iDefenders -= std::min(2,(iBorderDanger + 1)/3);
  20179. // Don't put more attack air units on plot than effective land defenders ... too large a risk
  20180. if (iAttackAirCount >= (iDefenders) || iDefenders <= 0)
  20181. {
  20182. return 0;
  20183. }
  20184. bool bAnyWar = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
  20185. int iValue = 0;
  20186. if( bAnyWar )
  20187. {
  20188. // Don't count assault assist, don't want to weight defending colonial coasts when homeland might be under attack
  20189. bool bAssault = (pPlot->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT) || (pPlot->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT_MASSING);
  20190. // Loop over operational range
  20191. iRange = airRange();
  20192. for (int iDX = -(iRange); iDX <= iRange; iDX++)
  20193. {
  20194. for (int iDY = -(iRange); iDY <= iRange; iDY++)
  20195. {
  20196. pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
  20197. if ((pLoopPlot != NULL && pLoopPlot->area() != NULL))
  20198. {
  20199. iDistance = plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
  20200. if( iDistance <= iRange )
  20201. {
  20202. bool bDefensive = pLoopPlot->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE;
  20203. bool bOffensive = pLoopPlot->area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE;
  20204. // Value system is based around 1 enemy military unit in our territory = 10 pts
  20205. iTempValue = 0;
  20206. if( pLoopPlot->isWater() )
  20207. {
  20208. if( pLoopPlot->isVisible(getTeam(),false) && !pLoopPlot->area()->isLake() )
  20209. {
  20210. // Defend ocean
  20211. iTempValue = 1;
  20212. if( pLoopPlot->isOwned() )
  20213. {
  20214. if( pLoopPlot->getTeam() == getTeam() )
  20215. {
  20216. iTempValue += 1;
  20217. }
  20218. else if ((pLoopPlot->getTeam() != getTeam()) && GET_TEAM(getTeam()).AI_getWarPlan(pLoopPlot->getTeam()) != NO_WARPLAN)
  20219. {
  20220. iTempValue += 1;
  20221. }
  20222. }
  20223. // Low weight for visible ships cause they will probably move
  20224. iTempValue += 2*pLoopPlot->getNumVisibleEnemyDefenders(this);
  20225. if( bAssault )
  20226. {
  20227. iTempValue *= 2;
  20228. }
  20229. }
  20230. }
  20231. else
  20232. {
  20233. if( !(pLoopPlot->isOwned()) )
  20234. {
  20235. if( iDistance < (iRange - 2) )
  20236. {
  20237. // Target enemy troops in neutral territory
  20238. iTempValue += 4*pLoopPlot->getNumVisibleEnemyDefenders(this);
  20239. }
  20240. }
  20241. else if( pLoopPlot->getTeam() == getTeam() )
  20242. {
  20243. iTempValue = 0;
  20244. if( iDistance < (iRange - 2) )
  20245. {
  20246. // Target enemy troops in our territory
  20247. iTempValue += 5*pLoopPlot->getNumVisibleEnemyDefenders(this);
  20248. if( pLoopPlot->getOwnerINLINE() == getOwnerINLINE() )
  20249. {
  20250. if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopPlot->area()) )
  20251. {
  20252. iTempValue *= 3;
  20253. }
  20254. else
  20255. {
  20256. iTempValue *= 2;
  20257. }
  20258. }
  20259. if( bDefensive )
  20260. {
  20261. iTempValue *= 2;
  20262. }
  20263. }
  20264. }
  20265. else if ((pLoopPlot->getTeam() != getTeam()) && GET_TEAM(getTeam()).AI_getWarPlan(pLoopPlot->getTeam()) != NO_WARPLAN)
  20266. {
  20267. // Attack opponents land territory
  20268. iTempValue = 3;
  20269. CvCity* pLoopCity = pLoopPlot->getPlotCity();
  20270. if (pLoopCity != NULL)
  20271. {
  20272. // Target enemy cities
  20273. iTempValue += (3*pLoopCity->getPopulation() + 30);
  20274. if( canAirBomb(pPlot) && pLoopCity->isBombardable(this) )
  20275. {
  20276. iTempValue *= 2;
  20277. }
  20278. if( pLoopPlot->area()->getTargetCity(getOwnerINLINE()) == pLoopCity )
  20279. {
  20280. iTempValue *= 2;
  20281. }
  20282. if( pLoopCity->AI_isDanger() )
  20283. {
  20284. // Multiplier for nearby troops, ours, teammate's, and any other enemy of city
  20285. iTempValue *= 3;
  20286. }
  20287. }
  20288. else
  20289. {
  20290. if( iDistance < (iRange - 2) )
  20291. {
  20292. // Support our troops in enemy territory
  20293. iTempValue += 15*pLoopPlot->getNumDefenders(getOwnerINLINE());
  20294. // Target enemy troops adjacent to our territory
  20295. if( pLoopPlot->isAdjacentTeam(getTeam(),true) )
  20296. {
  20297. iTempValue += 7*pLoopPlot->getNumVisibleEnemyDefenders(this);
  20298. }
  20299. }
  20300. // Weight resources
  20301. if (canAirBombAt(pPlot, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
  20302. {
  20303. if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
  20304. {
  20305. iTempValue += 8*std::max(2, GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(pLoopPlot->getBonusType(getTeam()))/10);
  20306. }
  20307. }
  20308. }
  20309. if( (pLoopPlot->area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) )
  20310. {
  20311. // Extra weight for enemy territory in offensive areas
  20312. iTempValue *= 2;
  20313. }
  20314. if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopPlot->area()) )
  20315. {
  20316. iTempValue *= 3;
  20317. iTempValue /= 2;
  20318. }
  20319. if( pLoopPlot->isBarbarian() )
  20320. {
  20321. iTempValue /= 2;
  20322. }
  20323. }
  20324. }
  20325. iValue += iTempValue;
  20326. }
  20327. }
  20328. }
  20329. }
  20330. // Consider available defense, direct threat to potential base
  20331. iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(pPlot,0,true,false,true);
  20332. iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pPlot,2,false,false);
  20333. if( 3*iEnemyOffense > iOurDefense || iOurDefense == 0 )
  20334. {
  20335. iValue *= iOurDefense;
  20336. iValue /= std::max(1,3*iEnemyOffense);
  20337. }
  20338. // Value forts less, they are generally riskier bases
  20339. if( pCity == NULL )
  20340. {
  20341. iValue *= 2;
  20342. iValue /= 3;
  20343. }
  20344. }
  20345. else
  20346. {
  20347. if( pPlot->getOwnerINLINE() != getOwnerINLINE() )
  20348. {
  20349. // Keep planes at home when not in real wars
  20350. return 0;
  20351. }
  20352. // If no wars, use prior logic with added value to keeping planes safe from sneak attack
  20353. if (pCity != NULL)
  20354. {
  20355. iValue = (pCity->getPopulation() + 20);
  20356. iValue += pCity->AI_cityThreat();
  20357. }
  20358. else
  20359. {
  20360. if( iDefenders > 0 )
  20361. {
  20362. iValue = (pCity != NULL) ? 0 : GET_PLAYER(getOwnerINLINE()).AI_getPlotAirbaseValue(pPlot);
  20363. iValue /= 6;
  20364. }
  20365. }
  20366. iValue += std::min(24, 3*(iDefenders - iAttackAirCount));
  20367. if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pPlot->area()) )
  20368. {
  20369. iValue *= 4;
  20370. iValue /= 3;
  20371. }
  20372. // No real enemies, check for minor civ or barbarian cities where attacks could be supported
  20373. pNearestEnemyCity = GC.getMapINLINE().findCity(pPlot->getX_INLINE(), pPlot->getY_INLINE(), NO_PLAYER, NO_TEAM, false, false, getTeam());
  20374. if (pNearestEnemyCity != NULL)
  20375. {
  20376. iDistance = plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pNearestEnemyCity->getX_INLINE(), pNearestEnemyCity->getY_INLINE());
  20377. if (iDistance > airRange())
  20378. {
  20379. iValue /= 10 * (2 + airRange());
  20380. }
  20381. else
  20382. {
  20383. iValue /= 2 + iDistance;
  20384. }
  20385. }
  20386. }
  20387. if (pPlot->getOwnerINLINE() == getOwnerINLINE())
  20388. {
  20389. // Bases in our territory better than teammate's
  20390. iValue *= 2;
  20391. }
  20392. else if( pPlot->getTeam() == getTeam() )
  20393. {
  20394. // Our team's bases are better than vassal plots
  20395. iValue *= 3;
  20396. iValue /= 2;
  20397. }
  20398. return iValue;
  20399. }
  20400. /********************************************************************************/
  20401. /* BETTER_BTS_AI_MOD END */
  20402. /********************************************************************************/
  20403. // Returns true if a mission was pushed...
  20404. bool CvUnitAI::AI_airDefensiveCity()
  20405. {
  20406. //PROFILE_FUNC();
  20407. CvCity* pCity;
  20408. CvCity* pLoopCity;
  20409. CvPlot* pBestPlot;
  20410. int iValue;
  20411. int iBestValue;
  20412. int iLoop;
  20413. FAssert(getDomainType() == DOMAIN_AIR);
  20414. FAssert(canAirDefend());
  20415. /********************************************************************************/
  20416. /* BETTER_BTS_AI_MOD 10/26/08 jdog5000 */
  20417. /* */
  20418. /* Air AI */
  20419. /********************************************************************************/
  20420. if (canAirDefend() && getDamage() == 0)
  20421. {
  20422. pCity = plot()->getPlotCity();
  20423. if (pCity != NULL)
  20424. {
  20425. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  20426. {
  20427. if ( !(pCity->AI_isAirDefended(false,+1)) )
  20428. {
  20429. // Stay if very short on planes, regardless of situation
  20430. getGroup()->pushMission(MISSION_AIRPATROL);
  20431. return true;
  20432. }
  20433. if( !(pCity->AI_isAirDefended(true,-1)) )
  20434. {
  20435. // Stay if city is threatened but not seriously threatened
  20436. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  20437. if (iEnemyOffense > 0)
  20438. {
  20439. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  20440. if( 3*iEnemyOffense < 4*iOurDefense )
  20441. {
  20442. getGroup()->pushMission(MISSION_AIRPATROL);
  20443. return true;
  20444. }
  20445. }
  20446. }
  20447. }
  20448. }
  20449. }
  20450. iBestValue = 0;
  20451. pBestPlot = NULL;
  20452. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  20453. {
  20454. if (canAirDefend(pLoopCity->plot()))
  20455. {
  20456. if (atPlot(pLoopCity->plot()) || canMoveInto(pLoopCity->plot()))
  20457. {
  20458. int iExistingAirDefenders = pLoopCity->plot()->plotCount(PUF_canAirDefend, -1, -1, pLoopCity->getOwnerINLINE(), NO_TEAM, PUF_isDomainType, DOMAIN_AIR);
  20459. if( atPlot(pLoopCity->plot()) )
  20460. {
  20461. iExistingAirDefenders -= 1;
  20462. }
  20463. int iNeedAirDefenders = pLoopCity->AI_neededAirDefenders();
  20464. if ( iNeedAirDefenders > iExistingAirDefenders )
  20465. {
  20466. iValue = pLoopCity->getPopulation() + pLoopCity->AI_cityThreat();
  20467. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(pLoopCity->plot(),0,true,false,true);
  20468. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pLoopCity->plot(),2,false,false);
  20469. iValue *= 100;
  20470. // Increase value of cities needing air defense more
  20471. iValue *= std::max(1, 3 + iNeedAirDefenders - iExistingAirDefenders);
  20472. if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopCity->area()) )
  20473. {
  20474. iValue *= 4;
  20475. iValue /= 3;
  20476. }
  20477. // Reduce value of endangered city, it may be too late to help
  20478. if (3*iEnemyOffense > iOurDefense || iOurDefense == 0)
  20479. {
  20480. iValue *= iOurDefense;
  20481. iValue /= std::max(1,3*iEnemyOffense);
  20482. }
  20483. if (iValue > iBestValue)
  20484. {
  20485. iBestValue = iValue;
  20486. pBestPlot = pLoopCity->plot();
  20487. }
  20488. }
  20489. }
  20490. }
  20491. }
  20492. if (pBestPlot != NULL && !atPlot(pBestPlot))
  20493. {
  20494. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  20495. return true;
  20496. }
  20497. /********************************************************************************/
  20498. /* BETTER_BTS_AI_MOD END */
  20499. /********************************************************************************/
  20500. return false;
  20501. }
  20502. // Returns true if a mission was pushed...
  20503. bool CvUnitAI::AI_airCarrier()
  20504. {
  20505. //PROFILE_FUNC();
  20506. CvUnit* pLoopUnit;
  20507. CvUnit* pBestUnit;
  20508. int iValue;
  20509. int iBestValue;
  20510. int iLoop;
  20511. if (getCargo() > 0)
  20512. {
  20513. return false;
  20514. }
  20515. if (isCargo())
  20516. {
  20517. if (canAirDefend())
  20518. {
  20519. getGroup()->pushMission(MISSION_AIRPATROL);
  20520. return true;
  20521. }
  20522. else
  20523. {
  20524. getGroup()->pushMission(MISSION_SKIP);
  20525. return true;
  20526. }
  20527. }
  20528. iBestValue = 0;
  20529. pBestUnit = NULL;
  20530. for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
  20531. {
  20532. if (canLoadUnit(pLoopUnit, pLoopUnit->plot()))
  20533. {
  20534. iValue = 10;
  20535. if (!(pLoopUnit->plot()->isCity()))
  20536. {
  20537. iValue += 20;
  20538. }
  20539. if (pLoopUnit->plot()->isOwned())
  20540. {
  20541. if (isEnemy(pLoopUnit->plot()->getTeam(), pLoopUnit->plot()))
  20542. {
  20543. iValue += 20;
  20544. }
  20545. }
  20546. else
  20547. {
  20548. iValue += 10;
  20549. }
  20550. iValue /= (pLoopUnit->getCargo() + 1);
  20551. if (iValue > iBestValue)
  20552. {
  20553. iBestValue = iValue;
  20554. pBestUnit = pLoopUnit;
  20555. }
  20556. }
  20557. }
  20558. if (pBestUnit != NULL)
  20559. {
  20560. if (atPlot(pBestUnit->plot()))
  20561. {
  20562. setTransportUnit(pBestUnit); // XXX is this dangerous (not pushing a mission...) XXX air units?
  20563. return true;
  20564. }
  20565. else
  20566. {
  20567. getGroup()->pushMission(MISSION_MOVE_TO, pBestUnit->getX_INLINE(), pBestUnit->getY_INLINE());
  20568. return true;
  20569. }
  20570. }
  20571. return false;
  20572. }
  20573. bool CvUnitAI::AI_missileLoad(UnitAITypes eTargetUnitAI, int iMaxOwnUnitAI, bool bStealthOnly)
  20574. {
  20575. //PROFILE_FUNC();
  20576. CvUnit* pBestUnit = NULL;
  20577. int iBestValue = 0;
  20578. int iLoop;
  20579. CvUnit* pLoopUnit;
  20580. for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
  20581. {
  20582. if (!bStealthOnly || pLoopUnit->getInvisibleType() != NO_INVISIBLE)
  20583. {
  20584. if (pLoopUnit->AI_getUnitAIType() == eTargetUnitAI)
  20585. {
  20586. if ((iMaxOwnUnitAI == -1) || (pLoopUnit->getUnitAICargo(AI_getUnitAIType()) <= iMaxOwnUnitAI))
  20587. {
  20588. if (canLoadUnit(pLoopUnit, pLoopUnit->plot()))
  20589. {
  20590. int iValue = 100;
  20591. iValue += GC.getGame().getSorenRandNum(100, "AI missile load");
  20592. iValue *= 1 + pLoopUnit->getCargo();
  20593. if (iValue > iBestValue)
  20594. {
  20595. iBestValue = iValue;
  20596. pBestUnit = pLoopUnit;
  20597. }
  20598. }
  20599. }
  20600. }
  20601. }
  20602. }
  20603. if (pBestUnit != NULL)
  20604. {
  20605. if (atPlot(pBestUnit->plot()))
  20606. {
  20607. setTransportUnit(pBestUnit); // XXX is this dangerous (not pushing a mission...) XXX air units?
  20608. return true;
  20609. }
  20610. else
  20611. {
  20612. getGroup()->pushMission(MISSION_MOVE_TO, pBestUnit->getX_INLINE(), pBestUnit->getY_INLINE());
  20613. setTransportUnit(pBestUnit);
  20614. return true;
  20615. }
  20616. }
  20617. return false;
  20618. }
  20619. // Returns true if a mission was pushed...
  20620. bool CvUnitAI::AI_airStrike()
  20621. {
  20622. //PROFILE_FUNC();
  20623. CvUnit* pDefender;
  20624. CvUnit* pInterceptor;
  20625. CvPlot* pLoopPlot;
  20626. CvPlot* pBestPlot;
  20627. int iSearchRange;
  20628. int iDamage;
  20629. int iPotentialAttackers;
  20630. int iInterceptProb;
  20631. int iValue;
  20632. int iBestValue;
  20633. int iDX, iDY;
  20634. iSearchRange = airRange();
  20635. iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (5 * m_pUnitInfo->getProductionCost()) / 6 : 0;
  20636. pBestPlot = NULL;
  20637. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  20638. {
  20639. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  20640. {
  20641. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  20642. if (pLoopPlot != NULL)
  20643. {
  20644. if (canMoveInto(pLoopPlot, true))
  20645. {
  20646. iValue = 0;
  20647. iPotentialAttackers = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);
  20648. if (pLoopPlot->isCity())
  20649. {
  20650. iPotentialAttackers += GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ASSAULT, getGroup(), 1) * 2;
  20651. }
  20652. /********************************************************************************/
  20653. /* BETTER_BTS_AI_MOD 10/13/08 jdog5000 */
  20654. /* */
  20655. /* Air AI */
  20656. /********************************************************************************/
  20657. /* original BTS code
  20658. if (pLoopPlot->isWater() || (iPotentialAttackers > 0) || pLoopPlot->isAdjacentTeam(getTeam()))
  20659. */
  20660. // Bombers will always consider striking units adjacent to this team's territory
  20661. // to soften them up for potential attack. This situation doesn't apply if this team's adjacent
  20662. // territory is water, land units won't be able to reach easily for attack
  20663. if (pLoopPlot->isWater() || (iPotentialAttackers > 0) || pLoopPlot->isAdjacentTeam(getTeam(),true))
  20664. /********************************************************************************/
  20665. /* BETTER_BTS_AI_MOD END */
  20666. /********************************************************************************/
  20667. {
  20668. pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
  20669. FAssert(pDefender != NULL);
  20670. FAssert(pDefender->canDefend());
  20671. // XXX factor in air defenses...
  20672. iDamage = airCombatDamage(pDefender);
  20673. iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));
  20674. iValue += ((((iDamage * collateralDamage()) / 100) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / 2);
  20675. iValue *= (3 + iPotentialAttackers);
  20676. iValue /= 4;
  20677. pInterceptor = bestInterceptor(pLoopPlot);
  20678. if (pInterceptor != NULL)
  20679. {
  20680. iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
  20681. iInterceptProb *= std::max(0, (100 - evasionProbability()));
  20682. iInterceptProb /= 100;
  20683. iValue *= std::max(0, 100 - iInterceptProb / 2);
  20684. iValue /= 100;
  20685. }
  20686. if (pLoopPlot->isWater())
  20687. {
  20688. iValue *= 3;
  20689. }
  20690. if (iValue > iBestValue)
  20691. {
  20692. iBestValue = iValue;
  20693. pBestPlot = pLoopPlot;
  20694. FAssert(!atPlot(pBestPlot));
  20695. }
  20696. }
  20697. }
  20698. }
  20699. }
  20700. }
  20701. if (pBestPlot != NULL)
  20702. {
  20703. FAssert(!atPlot(pBestPlot));
  20704. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  20705. return true;
  20706. }
  20707. return false;
  20708. }
  20709. /********************************************************************************/
  20710. /* BETTER_BTS_AI_MOD 9/16/08 jdog5000 */
  20711. /* */
  20712. /* Air AI */
  20713. /********************************************************************************/
  20714. // Air strike focused on weakening enemy stacks threatening our cities
  20715. // Returns true if a mission was pushed...
  20716. bool CvUnitAI::AI_defensiveAirStrike()
  20717. {
  20718. PROFILE_FUNC();
  20719. CvUnit* pDefender;
  20720. CvUnit* pInterceptor;
  20721. CvPlot* pLoopPlot;
  20722. CvPlot* pBestPlot;
  20723. int iSearchRange;
  20724. int iDamage;
  20725. int iInterceptProb;
  20726. int iValue;
  20727. int iBestValue;
  20728. int iDX, iDY;
  20729. iSearchRange = airRange();
  20730. iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (60 * m_pUnitInfo->getProductionCost()) : 0;
  20731. pBestPlot = NULL;
  20732. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  20733. {
  20734. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  20735. {
  20736. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  20737. if (pLoopPlot != NULL)
  20738. {
  20739. if (canMoveInto(pLoopPlot, true)) // Only true of plots this unit can airstrike
  20740. {
  20741. // Only attack enemy land units near our cities
  20742. if( pLoopPlot->isPlayerCityRadius(getOwnerINLINE()) && !pLoopPlot->isWater() )
  20743. {
  20744. CvCity* pClosestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), getOwnerINLINE(), getTeam(), true, false);
  20745. if( pClosestCity != NULL )
  20746. {
  20747. // City and pLoopPlot forced to be in same area, check they're still close
  20748. int iStepDist = plotDistance(pClosestCity->getX_INLINE(), pClosestCity->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
  20749. if( iStepDist < 3 )
  20750. {
  20751. iValue = 0;
  20752. pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
  20753. FAssert(pDefender != NULL);
  20754. FAssert(pDefender->canDefend());
  20755. iDamage = airCombatDamage(pDefender);
  20756. iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));
  20757. iValue += ((((iDamage * collateralDamage()) / 100) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / 2);
  20758. iValue *= GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pClosestCity->plot(),2,false,false);
  20759. iValue /= std::max(1, GET_TEAM(getTeam()).AI_getOurPlotStrength(pClosestCity->plot(),0,true,false,true));
  20760. if( iStepDist == 1 )
  20761. {
  20762. iValue *= 5;
  20763. iValue /= 4;
  20764. }
  20765. pInterceptor = bestInterceptor(pLoopPlot);
  20766. if (pInterceptor != NULL)
  20767. {
  20768. iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
  20769. iInterceptProb *= std::max(0, (100 - evasionProbability()));
  20770. iInterceptProb /= 100;
  20771. iValue *= std::max(0, 100 - iInterceptProb / 2);
  20772. iValue /= 100;
  20773. }
  20774. if (iValue > iBestValue)
  20775. {
  20776. iBestValue = iValue;
  20777. pBestPlot = pLoopPlot;
  20778. FAssert(!atPlot(pBestPlot));
  20779. }
  20780. }
  20781. }
  20782. }
  20783. }
  20784. }
  20785. }
  20786. }
  20787. if (pBestPlot != NULL)
  20788. {
  20789. FAssert(!atPlot(pBestPlot));
  20790. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  20791. return true;
  20792. }
  20793. return false;
  20794. }
  20795. // Air strike around base city
  20796. // Returns true if a mission was pushed...
  20797. bool CvUnitAI::AI_defendBaseAirStrike()
  20798. {
  20799. PROFILE_FUNC();
  20800. CvUnit* pDefender;
  20801. CvUnit* pInterceptor;
  20802. CvPlot* pLoopPlot;
  20803. CvPlot* pBestPlot;
  20804. int iDamage;
  20805. int iInterceptProb;
  20806. int iValue;
  20807. int iBestValue;
  20808. int iDX, iDY;
  20809. // Only search around base
  20810. int iSearchRange = 2;
  20811. iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (15 * m_pUnitInfo->getProductionCost()) : 0;
  20812. pBestPlot = NULL;
  20813. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  20814. {
  20815. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  20816. {
  20817. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  20818. if (pLoopPlot != NULL)
  20819. {
  20820. if (canMoveInto(pLoopPlot, true) && !pLoopPlot->isWater()) // Only true of plots this unit can airstrike
  20821. {
  20822. if( plot()->area() == pLoopPlot->area() )
  20823. {
  20824. iValue = 0;
  20825. pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
  20826. FAssert(pDefender != NULL);
  20827. FAssert(pDefender->canDefend());
  20828. iDamage = airCombatDamage(pDefender);
  20829. iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));
  20830. iValue += ((iDamage * collateralDamage()) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / (2*100);
  20831. // Weight towards stronger units
  20832. iValue *= (pDefender->currCombatStr(NULL,NULL,NULL) + 2000);
  20833. iValue /= 2000;
  20834. // Weight towards adjacent stacks
  20835. if( plotDistance(plot()->getX_INLINE(), plot()->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) == 1 )
  20836. {
  20837. iValue *= 5;
  20838. iValue /= 4;
  20839. }
  20840. pInterceptor = bestInterceptor(pLoopPlot);
  20841. if (pInterceptor != NULL)
  20842. {
  20843. iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
  20844. iInterceptProb *= std::max(0, (100 - evasionProbability()));
  20845. iInterceptProb /= 100;
  20846. iValue *= std::max(0, 100 - iInterceptProb / 2);
  20847. iValue /= 100;
  20848. }
  20849. if (iValue > iBestValue)
  20850. {
  20851. iBestValue = iValue;
  20852. pBestPlot = pLoopPlot;
  20853. FAssert(!atPlot(pBestPlot));
  20854. }
  20855. }
  20856. }
  20857. }
  20858. }
  20859. }
  20860. if (pBestPlot != NULL)
  20861. {
  20862. FAssert(!atPlot(pBestPlot));
  20863. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  20864. return true;
  20865. }
  20866. return false;
  20867. }
  20868. /********************************************************************************/
  20869. /* BETTER_BTS_AI_MOD END */
  20870. /********************************************************************************/
  20871. bool CvUnitAI::AI_airBombPlots()
  20872. {
  20873. //PROFILE_FUNC();
  20874. CvUnit* pInterceptor;
  20875. CvPlot* pLoopPlot;
  20876. CvPlot* pBestPlot;
  20877. int iSearchRange;
  20878. int iInterceptProb;
  20879. int iValue;
  20880. int iBestValue;
  20881. int iDX, iDY;
  20882. iSearchRange = airRange();
  20883. iBestValue = 0;
  20884. pBestPlot = NULL;
  20885. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  20886. {
  20887. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  20888. {
  20889. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  20890. if (pLoopPlot != NULL)
  20891. {
  20892. if (!pLoopPlot->isCity() && pLoopPlot->isOwned() && pLoopPlot != plot())
  20893. {
  20894. if (canAirBombAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
  20895. {
  20896. iValue = 0;
  20897. if (pLoopPlot->getBonusType(pLoopPlot->getTeam()) != NO_BONUS)
  20898. {
  20899. iValue += AI_pillageValue(pLoopPlot, 15);
  20900. iValue += GC.getGameINLINE().getSorenRandNum(10, "AI Air Bomb");
  20901. }
  20902. else if (isSuicide())
  20903. {
  20904. //This should only be reached when the unit is desperate to die
  20905. iValue += AI_pillageValue(pLoopPlot);
  20906. // Guided missiles lean towards destroying resource-producing tiles as opposed to improvements like Towns
  20907. if (pLoopPlot->getBonusType(pLoopPlot->getTeam()) != NO_BONUS)
  20908. {
  20909. //and even more so if it's a resource
  20910. iValue += GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(pLoopPlot->getBonusType(pLoopPlot->getTeam()));
  20911. }
  20912. }
  20913. if (iValue > 0)
  20914. {
  20915. pInterceptor = bestInterceptor(pLoopPlot);
  20916. if (pInterceptor != NULL)
  20917. {
  20918. iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
  20919. iInterceptProb *= std::max(0, (100 - evasionProbability()));
  20920. iInterceptProb /= 100;
  20921. iValue *= std::max(0, 100 - iInterceptProb / 2);
  20922. iValue /= 100;
  20923. }
  20924. if (iValue > iBestValue)
  20925. {
  20926. iBestValue = iValue;
  20927. pBestPlot = pLoopPlot;
  20928. FAssert(!atPlot(pBestPlot));
  20929. }
  20930. }
  20931. }
  20932. }
  20933. }
  20934. }
  20935. }
  20936. if (pBestPlot != NULL)
  20937. {
  20938. getGroup()->pushMission(MISSION_AIRBOMB, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  20939. return true;
  20940. }
  20941. return false;
  20942. }
  20943. bool CvUnitAI::AI_airBombDefenses()
  20944. {
  20945. //PROFILE_FUNC();
  20946. CvCity* pCity;
  20947. CvUnit* pInterceptor;
  20948. CvPlot* pLoopPlot;
  20949. CvPlot* pBestPlot;
  20950. int iSearchRange;
  20951. int iPotentialAttackers;
  20952. int iInterceptProb;
  20953. int iValue;
  20954. int iBestValue;
  20955. int iDX, iDY;
  20956. iSearchRange = airRange();
  20957. iBestValue = 0;
  20958. pBestPlot = NULL;
  20959. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  20960. {
  20961. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  20962. {
  20963. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  20964. if (pLoopPlot != NULL)
  20965. {
  20966. pCity = pLoopPlot->getPlotCity();
  20967. if (pCity != NULL)
  20968. {
  20969. iValue = 0;
  20970. if (canAirBombAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
  20971. {
  20972. iPotentialAttackers = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);
  20973. iPotentialAttackers += std::max(0, GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCity->plot(), NO_MISSIONAI, getGroup(), 2) - 4);
  20974. if (iPotentialAttackers > 1)
  20975. {
  20976. iValue += std::max(0, (std::min((pCity->getDefenseDamage() + airBombCurrRate()), GC.getMAX_CITY_DEFENSE_DAMAGE()) - pCity->getDefenseDamage()));
  20977. iValue *= 4 + iPotentialAttackers;
  20978. if (pCity->AI_isDanger())
  20979. {
  20980. iValue *= 2;
  20981. }
  20982. if (pCity == pCity->area()->getTargetCity(getOwnerINLINE()))
  20983. {
  20984. iValue *= 2;
  20985. }
  20986. }
  20987. if (iValue > 0)
  20988. {
  20989. pInterceptor = bestInterceptor(pLoopPlot);
  20990. if (pInterceptor != NULL)
  20991. {
  20992. iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
  20993. iInterceptProb *= std::max(0, (100 - evasionProbability()));
  20994. iInterceptProb /= 100;
  20995. iValue *= std::max(0, 100 - iInterceptProb / 2);
  20996. iValue /= 100;
  20997. }
  20998. if (iValue > iBestValue)
  20999. {
  21000. iBestValue = iValue;
  21001. pBestPlot = pLoopPlot;
  21002. FAssert(!atPlot(pBestPlot));
  21003. }
  21004. }
  21005. }
  21006. }
  21007. }
  21008. }
  21009. }
  21010. if (pBestPlot != NULL)
  21011. {
  21012. getGroup()->pushMission(MISSION_AIRBOMB, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  21013. return true;
  21014. }
  21015. return false;
  21016. }
  21017. bool CvUnitAI::AI_exploreAir()
  21018. {
  21019. PROFILE_FUNC();
  21020. CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
  21021. CvPlot* pBestPlot = NULL;
  21022. int iBestValue = 0;
  21023. CvPlot* pLoopPlot;
  21024. int iSearchRange;
  21025. int iValue;
  21026. int iDX, iDY;
  21027. /*
  21028. for (int iI = 0; iI < MAX_PLAYERS; iI++)
  21029. {
  21030. if (GET_PLAYER((PlayerTypes)iI).isAlive() && !GET_PLAYER((PlayerTypes)iI).isBarbarian())
  21031. {
  21032. if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
  21033. {
  21034. for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
  21035. {
  21036. if (!pLoopCity->isVisible(getTeam(), false))
  21037. {
  21038. if (canReconAt(plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
  21039. {
  21040. iValue = 1 + GC.getGame().getSorenRandNum(15, "AI explore air");
  21041. if (isEnemy(GET_PLAYER((PlayerTypes)iI).getTeam()))
  21042. {
  21043. iValue += 10;
  21044. iValue += std::min(10, pLoopCity->area()->getNumAIUnits(getOwnerINLINE(), UNITAI_ATTACK_CITY));
  21045. iValue += 10 * kPlayer.AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ASSAULT);
  21046. }
  21047. iValue *= plotDistance(getX_INLINE(), getY_INLINE(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE());
  21048. if (iValue > iBestValue)
  21049. {
  21050. iBestValue = iValue;
  21051. pBestPlot = pLoopCity->plot();
  21052. }
  21053. }
  21054. }
  21055. }
  21056. }
  21057. }
  21058. }
  21059. if (pBestPlot != NULL)
  21060. {
  21061. getGroup()->pushMission(MISSION_RECON, pBestPlot->getX(), pBestPlot->getY());
  21062. return true;
  21063. }
  21064. */
  21065. iSearchRange = airRange();
  21066. iBestValue = 0;
  21067. pBestPlot = NULL;
  21068. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  21069. {
  21070. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  21071. {
  21072. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  21073. if (pLoopPlot != NULL)
  21074. {
  21075. if (pLoopPlot != plot())
  21076. {
  21077. if (canReconAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
  21078. {
  21079. iValue = 1 + GC.getGame().getSorenRandNum(10, "AI explore air");
  21080. iValue *= plotDistance(getX_INLINE(), getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
  21081. if (pLoopPlot->isPeak())
  21082. {
  21083. iValue += 3;
  21084. }
  21085. if (!pLoopPlot->isVisible(getTeam(), false))
  21086. {
  21087. iValue += 10;
  21088. }
  21089. if (pLoopPlot->isOwned())
  21090. {
  21091. if (GET_TEAM(getTeam()).isAtWar(pLoopPlot->getTeam()))
  21092. {
  21093. iValue += 5;
  21094. }
  21095. if (pLoopPlot->getOwner() != getOwner())
  21096. {
  21097. iValue *= 2;
  21098. }
  21099. }
  21100. if (pLoopPlot->isCity())
  21101. {
  21102. iValue *= 5;
  21103. }
  21104. if (!pLoopPlot->isRevealed(getTeam(), false))
  21105. {
  21106. iValue *= 2;
  21107. }
  21108. if (iValue > iBestValue)
  21109. {
  21110. iBestValue = iValue;
  21111. pBestPlot = pLoopPlot;
  21112. }
  21113. }
  21114. }
  21115. }
  21116. }
  21117. }
  21118. if (pBestPlot != NULL)
  21119. {
  21120. FAssert(!atPlot(pBestPlot));
  21121. logBBAI(" ...recon at %d, %d", pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  21122. getGroup()->pushMission(MISSION_RECON, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  21123. return true;
  21124. }
  21125. return false;
  21126. }
  21127. // Returns true if a mission was pushed...
  21128. bool CvUnitAI::AI_nuke()
  21129. {
  21130. PROFILE_FUNC();
  21131. CvCity* pLoopCity;
  21132. CvCity* pBestCity;
  21133. int iValue;
  21134. int iBestValue;
  21135. int iLoop;
  21136. int iI;
  21137. pBestCity = NULL;
  21138. iBestValue = 0;
  21139. for (iI = 0; iI < MAX_PLAYERS; iI++)
  21140. {
  21141. if (GET_PLAYER((PlayerTypes)iI).isAlive() && !GET_PLAYER((PlayerTypes)iI).isBarbarian())
  21142. {
  21143. if (isEnemy(GET_PLAYER((PlayerTypes)iI).getTeam()))
  21144. {
  21145. if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) == ATTITUDE_FURIOUS)
  21146. {
  21147. for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
  21148. {
  21149. if (canNukeAt(plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
  21150. {
  21151. iValue = AI_nukeValue(pLoopCity);
  21152. if (iValue > iBestValue)
  21153. {
  21154. iBestValue = iValue;
  21155. pBestCity = pLoopCity;
  21156. FAssert(pBestCity->getTeam() != getTeam());
  21157. }
  21158. }
  21159. }
  21160. }
  21161. }
  21162. }
  21163. }
  21164. if (pBestCity != NULL)
  21165. {
  21166. getGroup()->pushMission(MISSION_NUKE, pBestCity->getX_INLINE(), pBestCity->getY_INLINE());
  21167. return true;
  21168. }
  21169. return false;
  21170. }
  21171. bool CvUnitAI::AI_nukeRange(int iRange)
  21172. {
  21173. CvPlot* pBestPlot = NULL;
  21174. int iBestValue = 0;
  21175. for (int iDX = -(iRange); iDX <= iRange; iDX++)
  21176. {
  21177. for (int iDY = -(iRange); iDY <= iRange; iDY++)
  21178. {
  21179. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  21180. if (pLoopPlot != NULL)
  21181. {
  21182. if (canNukeAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
  21183. {
  21184. int iValue = -99;
  21185. for (int iDX2 = -(nukeRange()); iDX2 <= nukeRange(); iDX2++)
  21186. {
  21187. for (int iDY2 = -(nukeRange()); iDY2 <= nukeRange(); iDY2++)
  21188. {
  21189. CvPlot* pLoopPlot2 = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iDX2, iDY2);
  21190. if (pLoopPlot2 != NULL)
  21191. {
  21192. int iEnemyCount = 0;
  21193. int iTeamCount = 0;
  21194. int iNeutralCount = 0;
  21195. int iDamagedEnemyCount = 0;
  21196. CLLNode<IDInfo>* pUnitNode;
  21197. CvUnit* pLoopUnit;
  21198. pUnitNode = pLoopPlot2->headUnitNode();
  21199. while (pUnitNode != NULL)
  21200. {
  21201. pLoopUnit = ::getUnit(pUnitNode->m_data);
  21202. pUnitNode = pLoopPlot2->nextUnitNode(pUnitNode);
  21203. if (!pLoopUnit->isNukeImmune())
  21204. {
  21205. if (pLoopUnit->getTeam() == getTeam())
  21206. {
  21207. iTeamCount++;
  21208. }
  21209. else if (!pLoopUnit->isInvisible(getTeam(), false))
  21210. {
  21211. if (isEnemy(pLoopUnit->getTeam()))
  21212. {
  21213. iEnemyCount++;
  21214. if (pLoopUnit->getDamage() * 2 > pLoopUnit->maxHitPoints())
  21215. {
  21216. iDamagedEnemyCount++;
  21217. }
  21218. }
  21219. else
  21220. {
  21221. iNeutralCount++;
  21222. }
  21223. }
  21224. }
  21225. }
  21226. iValue += (iEnemyCount + iDamagedEnemyCount) * (pLoopPlot2->isWater() ? 25 : 12);
  21227. iValue -= iTeamCount * 15;
  21228. iValue -= iNeutralCount * 20;
  21229. int iMultiplier = 1;
  21230. if (pLoopPlot2->getTeam() == getTeam())
  21231. {
  21232. iMultiplier = -2;
  21233. }
  21234. else if (isEnemy(pLoopPlot2->getTeam()))
  21235. {
  21236. iMultiplier = 1;
  21237. }
  21238. else if (!pLoopPlot2->isOwned())
  21239. {
  21240. iMultiplier = 0;
  21241. }
  21242. else
  21243. {
  21244. iMultiplier = -10;
  21245. }
  21246. if (pLoopPlot2->getImprovementType() != NO_IMPROVEMENT)
  21247. {
  21248. iValue += iMultiplier * 10;
  21249. }
  21250. if (pLoopPlot2->getBonusType() != NO_BONUS)
  21251. {
  21252. iValue += iMultiplier * 20;
  21253. }
  21254. if (pLoopPlot2->isCity())
  21255. {
  21256. iValue += std::max(0, iMultiplier * (-20 + 15 * pLoopPlot2->getPlotCity()->getPopulation()));
  21257. }
  21258. }
  21259. }
  21260. }
  21261. if (iValue > iBestValue)
  21262. {
  21263. iBestValue = iValue;
  21264. pBestPlot = pLoopPlot;
  21265. }
  21266. }
  21267. }
  21268. }
  21269. }
  21270. if (pBestPlot != NULL)
  21271. {
  21272. getGroup()->pushMission(MISSION_NUKE, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  21273. return true;
  21274. }
  21275. return false;
  21276. }
  21277. bool CvUnitAI::AI_trade(int iValueThreshold)
  21278. {
  21279. CvCity* pLoopCity;
  21280. CvPlot* pBestPlot;
  21281. CvPlot* pBestTradePlot;
  21282. int iPathTurns;
  21283. int iValue;
  21284. int iBestValue;
  21285. int iLoop;
  21286. int iI;
  21287. iBestValue = 0;
  21288. pBestPlot = NULL;
  21289. pBestTradePlot = NULL;
  21290. for (iI = 0; iI < MAX_PLAYERS; iI++)
  21291. {
  21292. if (GET_PLAYER((PlayerTypes)iI).isAlive())
  21293. {
  21294. for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
  21295. {
  21296. if (pLoopCity->isRevealed(getTeam(), false))
  21297. {
  21298. if (AI_plotValid(pLoopCity->plot()))
  21299. {
  21300. if (getTeam() != pLoopCity->getTeam())
  21301. {
  21302. iValue = getTradeGold(pLoopCity->plot());
  21303. if ((iValue >= iValueThreshold) && canTrade(pLoopCity->plot(), true))
  21304. {
  21305. if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
  21306. {
  21307. if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  21308. {
  21309. FAssert(iPathTurns > 0);
  21310. iValue /= (4 + iPathTurns);
  21311. if (iValue > iBestValue)
  21312. {
  21313. iBestValue = iValue;
  21314. pBestPlot = getPathEndTurnPlot();
  21315. pBestTradePlot = pLoopCity->plot();
  21316. }
  21317. }
  21318. }
  21319. }
  21320. }
  21321. }
  21322. }
  21323. }
  21324. }
  21325. }
  21326. if ((pBestPlot != NULL) && (pBestTradePlot != NULL))
  21327. {
  21328. if (atPlot(pBestTradePlot))
  21329. {
  21330. logBBAI(" %S (%d) starting Trade Mission at %d, %d", getName().GetCString(), getID(), pBestPlot->getX(), pBestPlot->getY());
  21331. getGroup()->pushMission(MISSION_TRADE);
  21332. return true;
  21333. }
  21334. else
  21335. {
  21336. FAssert(!atPlot(pBestPlot));
  21337. logBBAI(" %S (%d) moving to %d, %d for Trade Mission", getName().GetCString(), getID(), pBestPlot->getX(), pBestPlot->getY());
  21338. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  21339. return true;
  21340. }
  21341. }
  21342. return false;
  21343. }
  21344. bool CvUnitAI::AI_infiltrate()
  21345. {
  21346. PROFILE_FUNC();
  21347. CvCity* pLoopCity;
  21348. CvPlot* pBestPlot;
  21349. int iPathTurns;
  21350. int iValue;
  21351. int iBestValue;
  21352. int iLoop;
  21353. int iI;
  21354. iBestValue = 0;
  21355. pBestPlot = NULL;
  21356. if (canInfiltrate(plot()))
  21357. {
  21358. getGroup()->pushMission(MISSION_INFILTRATE);
  21359. return true;
  21360. }
  21361. for (iI = 0; iI < MAX_PLAYERS; iI++)
  21362. {
  21363. if ((GET_PLAYER((PlayerTypes)iI).isAlive()) && GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
  21364. {
  21365. for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
  21366. {
  21367. if (canInfiltrate(pLoopCity->plot()))
  21368. {
  21369. /************************************************************************************************/
  21370. /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
  21371. /* */
  21372. /* Unit AI, Efficiency */
  21373. /************************************************************************************************/
  21374. // BBAI efficiency: check area for land units before generating path
  21375. if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
  21376. {
  21377. continue;
  21378. }
  21379. iValue = getEspionagePoints(pLoopCity->plot());
  21380. if (iValue > iBestValue)
  21381. /************************************************************************************************/
  21382. /* BETTER_BTS_AI_MOD END */
  21383. /************************************************************************************************/
  21384. {
  21385. if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  21386. {
  21387. FAssert(iPathTurns > 0);
  21388. if (getPathLastNode()->m_iData1 == 0)
  21389. {
  21390. iPathTurns++;
  21391. }
  21392. iValue /= 1 + iPathTurns;
  21393. if (iValue > iBestValue)
  21394. {
  21395. iBestValue = iValue;
  21396. pBestPlot = pLoopCity->plot();
  21397. }
  21398. }
  21399. }
  21400. }
  21401. }
  21402. }
  21403. }
  21404. if ((pBestPlot != NULL))
  21405. {
  21406. if (atPlot(pBestPlot))
  21407. {
  21408. getGroup()->pushMission(MISSION_INFILTRATE);
  21409. return true;
  21410. }
  21411. else
  21412. {
  21413. FAssert(!atPlot(pBestPlot));
  21414. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  21415. getGroup()->pushMission(MISSION_INFILTRATE, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0));
  21416. return true;
  21417. }
  21418. }
  21419. return false;
  21420. }
  21421. bool CvUnitAI::AI_reconSpy(int iRange)
  21422. {
  21423. PROFILE_FUNC();
  21424. CvPlot* pLoopPlot;
  21425. int iX, iY;
  21426. CvPlot* pBestPlot = NULL;
  21427. CvPlot* pBestTargetPlot = NULL;
  21428. int iBestValue = 0;
  21429. int iSearchRange = AI_searchRange(iRange);
  21430. for (iX = -iSearchRange; iX <= iSearchRange; iX++)
  21431. {
  21432. for (iY = -iSearchRange; iY <= iSearchRange; iY++)
  21433. {
  21434. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
  21435. int iDistance = stepDistance(0, 0, iX, iY);
  21436. if ((iDistance > 0) && (pLoopPlot != NULL) && AI_plotValid(pLoopPlot))
  21437. {
  21438. int iValue = 0;
  21439. if (pLoopPlot->getPlotCity() != NULL)
  21440. {
  21441. iValue += GC.getGameINLINE().getSorenRandNum(4000, "AI Spy Scout City");
  21442. }
  21443. if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
  21444. {
  21445. iValue += GC.getGameINLINE().getSorenRandNum(1000, "AI Spy Recon Bonus");
  21446. }
  21447. for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  21448. {
  21449. CvPlot* pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));
  21450. if (pAdjacentPlot != NULL)
  21451. {
  21452. if (!pAdjacentPlot->isRevealed(getTeam(), false))
  21453. {
  21454. iValue += 500;
  21455. }
  21456. else if (!pAdjacentPlot->isVisible(getTeam(), false))
  21457. {
  21458. iValue += 200;
  21459. }
  21460. }
  21461. }
  21462. if (iValue > 0)
  21463. {
  21464. int iPathTurns;
  21465. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  21466. {
  21467. if (iPathTurns <= iRange)
  21468. {
  21469. // don't give each and every plot in range a value before generating the patch (performance hit)
  21470. iValue += GC.getGameINLINE().getSorenRandNum(250, "AI Spy Scout Best Plot");
  21471. iValue *= iDistance;
  21472. /* Can no longer perform missions after having moved
  21473. if (getPathLastNode()->m_iData2 == 1)
  21474. {
  21475. if (getPathLastNode()->m_iData1 > 0)
  21476. {
  21477. //Prefer to move and have movement remaining to perform a kill action.
  21478. iValue *= 2;
  21479. }
  21480. } */
  21481. if (iValue > iBestValue)
  21482. {
  21483. iBestValue = iValue;
  21484. pBestTargetPlot = getPathEndTurnPlot();
  21485. pBestPlot = pLoopPlot;
  21486. }
  21487. }
  21488. }
  21489. }
  21490. }
  21491. }
  21492. }
  21493. if ((pBestPlot != NULL) && (pBestTargetPlot != NULL))
  21494. {
  21495. if (atPlot(pBestTargetPlot))
  21496. {
  21497. getGroup()->pushMission(MISSION_SKIP);
  21498. return true;
  21499. }
  21500. else
  21501. {
  21502. getGroup()->pushMission(MISSION_MOVE_TO, pBestTargetPlot->getX_INLINE(), pBestTargetPlot->getY_INLINE());
  21503. getGroup()->pushMission(MISSION_SKIP);
  21504. return true;
  21505. }
  21506. }
  21507. return false;
  21508. }
  21509. /************************************************************************************************/
  21510. /* BETTER_BTS_AI_MOD 10/25/09 jdog5000 */
  21511. /* */
  21512. /* Espionage AI */
  21513. /************************************************************************************************/
  21514. /// \brief Spy decision on whether to cause revolt in besieged city
  21515. ///
  21516. /// Have spy breakdown city defenses if we have troops in position to capture city this turn.
  21517. bool CvUnitAI::AI_revoltCitySpy()
  21518. {
  21519. PROFILE_FUNC();
  21520. CvCity* pCity = plot()->getPlotCity();
  21521. FAssert(pCity != NULL);
  21522. if( pCity == NULL )
  21523. {
  21524. return false;
  21525. }
  21526. if( !(GET_TEAM(getTeam()).isAtWar(pCity->getTeam())) )
  21527. {
  21528. return false;
  21529. }
  21530. if( pCity->isDisorder() )
  21531. {
  21532. return false;
  21533. }
  21534. int iOurPower = GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(),1,false,true);
  21535. int iEnemyDefensePower = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),0,true,false);
  21536. int iEnemyPostPower = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),0,false,false);
  21537. if( iOurPower > 2*iEnemyDefensePower )
  21538. {
  21539. return false;
  21540. }
  21541. if( iOurPower < iEnemyPostPower )
  21542. {
  21543. return false;
  21544. }
  21545. if( 10*iEnemyDefensePower < 11*iEnemyPostPower )
  21546. {
  21547. return false;
  21548. }
  21549. for (int iMission = 0; iMission < GC.getNumEspionageMissionInfos(); ++iMission)
  21550. {
  21551. CvEspionageMissionInfo& kMissionInfo = GC.getEspionageMissionInfo((EspionageMissionTypes)iMission);
  21552. if ((kMissionInfo.getCityRevoltCounter() > 0) || (kMissionInfo.getPlayerAnarchyCounter() > 0))
  21553. {
  21554. if (!GET_PLAYER(getOwnerINLINE()).canDoEspionageMission((EspionageMissionTypes)iMission, pCity->getOwnerINLINE(), pCity->plot(), -1, this))
  21555. {
  21556. continue;
  21557. }
  21558. if (!espionage((EspionageMissionTypes)iMission, -1))
  21559. {
  21560. continue;
  21561. }
  21562. return true;
  21563. }
  21564. }
  21565. return false;
  21566. }
  21567. int CvUnitAI::AI_getEspionageTargetValue(CvPlot* pPlot, int iMaxPath)
  21568. {
  21569. PROFILE_FUNC();
  21570. CvTeamAI& kTeam = GET_TEAM(getTeam());
  21571. int iValue = 0;
  21572. if (pPlot->isOwned() && pPlot->getTeam() != getTeam() && !GET_TEAM(getTeam()).isVassal(pPlot->getTeam()))
  21573. {
  21574. if (AI_plotValid(pPlot))
  21575. {
  21576. CvCity* pCity = pPlot->getPlotCity();
  21577. if (pCity != NULL)
  21578. {
  21579. iValue += pCity->getPopulation();
  21580. iValue += pCity->plot()->calculateCulturePercent(getOwnerINLINE())/8;
  21581. // BBAI TODO: Should go to cities where missions will be cheaper ...
  21582. int iRand = GC.getGame().getSorenRandNum(6, "AI spy choose city");
  21583. iValue += iRand * iRand;
  21584. if( area()->getTargetCity(getOwnerINLINE()) == pCity )
  21585. {
  21586. iValue += 30;
  21587. }
  21588. if( GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pPlot, MISSIONAI_ASSAULT, getGroup()) > 0 )
  21589. {
  21590. iValue += 30;
  21591. }
  21592. // BBAI TODO: What else? If can see production, go for wonders and space race ...
  21593. }
  21594. else
  21595. {
  21596. BonusTypes eBonus = pPlot->getNonObsoleteBonusType(getTeam());
  21597. if (eBonus != NO_BONUS)
  21598. {
  21599. iValue += GET_PLAYER(pPlot->getOwnerINLINE()).AI_baseBonusVal(eBonus) - 10;
  21600. }
  21601. }
  21602. int iPathTurns;
  21603. if (generatePath(pPlot, 0, true, &iPathTurns))
  21604. {
  21605. if (iPathTurns <= iMaxPath)
  21606. {
  21607. if (kTeam.AI_getWarPlan(pPlot->getTeam()) == NO_WARPLAN)
  21608. {
  21609. iValue *= 1;
  21610. }
  21611. else if (kTeam.AI_isSneakAttackPreparing(pPlot->getTeam()))
  21612. {
  21613. iValue *= (pPlot->isCity()) ? 15 : 10;
  21614. }
  21615. else
  21616. {
  21617. iValue *= 3;
  21618. }
  21619. iValue *= 3;
  21620. iValue /= (3 + GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pPlot, MISSIONAI_ATTACK_SPY, getGroup()));
  21621. }
  21622. }
  21623. }
  21624. }
  21625. return iValue;
  21626. }
  21627. bool CvUnitAI::AI_cityOffenseSpy(int iMaxPath, CvCity* pSkipCity)
  21628. {
  21629. PROFILE_FUNC();
  21630. int iBestValue = 0;
  21631. CvPlot* pBestPlot = NULL;
  21632. for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; ++iPlayer)
  21633. {
  21634. CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iPlayer);
  21635. if (kLoopPlayer.isAlive() && kLoopPlayer.getTeam() != getTeam() && !GET_TEAM(getTeam()).isVassal(kLoopPlayer.getTeam()))
  21636. {
  21637. // Only move to cities where we will run missions
  21638. if (GET_PLAYER(getOwnerINLINE()).AI_getAttitudeWeight((PlayerTypes)iPlayer) < (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 51 : 1)
  21639. || GET_TEAM(getTeam()).AI_getWarPlan(kLoopPlayer.getTeam()) != NO_WARPLAN
  21640. || GET_TEAM(getTeam()).getBestKnownTechScorePercent() < 85 )
  21641. {
  21642. int iLoop;
  21643. for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
  21644. {
  21645. if( pLoopCity == pSkipCity )
  21646. {
  21647. continue;
  21648. }
  21649. if (pLoopCity->area() == area() || canMoveAllTerrain())
  21650. {
  21651. CvPlot* pLoopPlot = pLoopCity->plot();
  21652. if (AI_plotValid(pLoopPlot))
  21653. {
  21654. int iValue = AI_getEspionageTargetValue(pLoopPlot, iMaxPath);
  21655. if (iValue > iBestValue)
  21656. {
  21657. iBestValue = iValue;
  21658. pBestPlot = pLoopPlot;
  21659. }
  21660. }
  21661. }
  21662. }
  21663. }
  21664. }
  21665. }
  21666. if (pBestPlot != NULL)
  21667. {
  21668. if (atPlot(pBestPlot))
  21669. {
  21670. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
  21671. }
  21672. else
  21673. {
  21674. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY );
  21675. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
  21676. }
  21677. return true;
  21678. }
  21679. return false;
  21680. }
  21681. bool CvUnitAI::AI_bonusOffenseSpy(int iRange)
  21682. {
  21683. PROFILE_FUNC();
  21684. CvPlot* pBestPlot = NULL;
  21685. int iBestValue = 10;
  21686. int iSearchRange = AI_searchRange(iRange);
  21687. for (int iX = -iSearchRange; iX <= iSearchRange; iX++)
  21688. {
  21689. for (int iY = -iSearchRange; iY <= iSearchRange; iY++)
  21690. {
  21691. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
  21692. if (NULL != pLoopPlot && pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
  21693. {
  21694. if( pLoopPlot->isOwned() && pLoopPlot->getTeam() != getTeam() )
  21695. {
  21696. // Only move to plots where we will run missions
  21697. if (GET_PLAYER(getOwnerINLINE()).AI_getAttitudeWeight(pLoopPlot->getOwner()) < (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 51 : 1)
  21698. || GET_TEAM(getTeam()).AI_getWarPlan(pLoopPlot->getTeam()) != NO_WARPLAN )
  21699. {
  21700. int iValue = AI_getEspionageTargetValue(pLoopPlot, iRange);
  21701. if (iValue > iBestValue)
  21702. {
  21703. iBestValue = iValue;
  21704. pBestPlot = pLoopPlot;
  21705. }
  21706. }
  21707. }
  21708. }
  21709. }
  21710. }
  21711. if (pBestPlot != NULL)
  21712. {
  21713. if (atPlot(pBestPlot))
  21714. {
  21715. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
  21716. return true;
  21717. }
  21718. else
  21719. {
  21720. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY);
  21721. getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
  21722. return true;
  21723. }
  21724. }
  21725. return false;
  21726. }
  21727. /************************************************************************************************/
  21728. /* BETTER_BTS_AI_MOD END */
  21729. /************************************************************************************************/
  21730. //Returns true if the spy performs espionage.
  21731. bool CvUnitAI::AI_espionageSpy()
  21732. {
  21733. PROFILE_FUNC();
  21734. if (!canEspionage(plot()))
  21735. {
  21736. return false;
  21737. }
  21738. EspionageMissionTypes eBestMission = NO_ESPIONAGEMISSION;
  21739. CvPlot* pTargetPlot = NULL;
  21740. PlayerTypes eTargetPlayer = NO_PLAYER;
  21741. int iExtraData = -1;
  21742. eBestMission = GET_PLAYER(getOwnerINLINE()).AI_bestPlotEspionage(plot(), eTargetPlayer, pTargetPlot, iExtraData);
  21743. if (NO_ESPIONAGEMISSION == eBestMission)
  21744. {
  21745. return false;
  21746. }
  21747. if (!GET_PLAYER(getOwnerINLINE()).canDoEspionageMission(eBestMission, eTargetPlayer, pTargetPlot, iExtraData, this))
  21748. {
  21749. return false;
  21750. }
  21751. if (!espionage(eBestMission, iExtraData))
  21752. {
  21753. return false;
  21754. }
  21755. return true;
  21756. }
  21757. bool CvUnitAI::AI_moveToStagingCity()
  21758. {
  21759. PROFILE_FUNC();
  21760. CvCity* pLoopCity;
  21761. CvPlot* pBestPlot;
  21762. int iPathTurns;
  21763. int iValue;
  21764. int iBestValue;
  21765. int iLoop;
  21766. iBestValue = 0;
  21767. pBestPlot = NULL;
  21768. int iWarCount = 0;
  21769. TeamTypes eTargetTeam = NO_TEAM;
  21770. CvTeam& kTeam = GET_TEAM(getTeam());
  21771. for (int iI = 0; iI < MAX_TEAMS; iI++)
  21772. {
  21773. if ((iI != getTeam()) && GET_TEAM((TeamTypes)iI).isAlive())
  21774. {
  21775. if (kTeam.AI_isSneakAttackPreparing((TeamTypes)iI))
  21776. {
  21777. eTargetTeam = (TeamTypes)iI;
  21778. iWarCount++;
  21779. }
  21780. }
  21781. }
  21782. if (iWarCount > 1)
  21783. {
  21784. eTargetTeam = NO_TEAM;
  21785. }
  21786. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  21787. {
  21788. /************************************************************************************************/
  21789. /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
  21790. /* */
  21791. /* War tactics AI, Efficiency */
  21792. /************************************************************************************************/
  21793. // BBAI efficiency: check same area
  21794. if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
  21795. {
  21796. // BBAI TODO: Need some knowledge of whether this is a good city to attack from ... only get that
  21797. // indirectly from threat.
  21798. iValue = pLoopCity->AI_cityThreat();
  21799. // Have attack stacks in assault areas move to coastal cities for faster loading
  21800. if( (area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT) || (area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT_MASSING) )
  21801. {
  21802. CvArea* pWaterArea = pLoopCity->waterArea();
  21803. if( pWaterArea != NULL && GET_TEAM(getTeam()).AI_isWaterAreaRelevant(pWaterArea) )
  21804. {
  21805. // BBAI TODO: Need a better way to determine which cities should serve as invasion launch locations
  21806. // Inertia so units don't just chase transports around the map
  21807. iValue = iValue/2;
  21808. if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT )
  21809. {
  21810. // If in assault, transports may be at sea ... tend to stay where they left from
  21811. // to speed reinforcement
  21812. iValue += pLoopCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, UNITAI_ATTACK_CITY, -1, getOwnerINLINE());
  21813. }
  21814. // Attraction to cities which are serving as launch/pickup points
  21815. iValue += 3*pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_ASSAULT_SEA, -1, getOwnerINLINE());
  21816. iValue += 2*pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_ESCORT_SEA, -1, getOwnerINLINE());
  21817. iValue += 5*GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_PICKUP);
  21818. }
  21819. else
  21820. {
  21821. iValue = iValue/8;
  21822. }
  21823. }
  21824. if (iValue*200 > iBestValue)
  21825. {
  21826. /************************************************************************************************/
  21827. /* BETTER_BTS_AI_MOD END */
  21828. /************************************************************************************************/
  21829. if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  21830. {
  21831. iValue *= 1000;
  21832. iValue /= (5 + iPathTurns);
  21833. if ((pLoopCity->plot() != plot()) && pLoopCity->isVisible(eTargetTeam, false))
  21834. {
  21835. iValue /= 2;
  21836. }
  21837. if (iValue > iBestValue)
  21838. {
  21839. iBestValue = iValue;
  21840. //pBestPlot = getPathEndTurnPlot();
  21841. pBestPlot = pLoopCity->plot();
  21842. }
  21843. }
  21844. }
  21845. }
  21846. }
  21847. if (pBestPlot != NULL)
  21848. {
  21849. if (atPlot(pBestPlot))
  21850. {
  21851. getGroup()->pushMission(MISSION_SKIP);
  21852. return true;
  21853. }
  21854. else
  21855. {
  21856. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  21857. logBBAI(" ...moving to Staging City %S at %d, %d", pBestPlot->getPlotCity()->getName().GetCString(), pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  21858. return true;
  21859. }
  21860. }
  21861. return false;
  21862. }
  21863. /*
  21864. bool CvUnitAI::AI_seaRetreatFromCityDanger()
  21865. {
  21866. if (plot()->isCity(true) && GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) //prioritize getting outta there
  21867. {
  21868. if (AI_anyAttack(2, 40))
  21869. {
  21870. return true;
  21871. }
  21872. if (AI_anyAttack(4, 50))
  21873. {
  21874. return true;
  21875. }
  21876. if (AI_retreatToCity())
  21877. {
  21878. return true;
  21879. }
  21880. if (AI_safety())
  21881. {
  21882. return true;
  21883. }
  21884. }
  21885. return false;
  21886. }
  21887. bool CvUnitAI::AI_airRetreatFromCityDanger()
  21888. {
  21889. if (plot()->isCity(true))
  21890. {
  21891. CvCity* pCity = plot()->getPlotCity();
  21892. if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0 || (pCity != NULL && !pCity->AI_isDefended()))
  21893. {
  21894. if (AI_airOffensiveCity())
  21895. {
  21896. return true;
  21897. }
  21898. if (canAirDefend() && AI_airDefensiveCity())
  21899. {
  21900. return true;
  21901. }
  21902. }
  21903. }
  21904. return false;
  21905. }
  21906. bool CvUnitAI::AI_airAttackDamagedSkip()
  21907. {
  21908. if (getDamage() == 0)
  21909. {
  21910. return false;
  21911. }
  21912. bool bSkip = (currHitPoints() * 100 / maxHitPoints() < 40);
  21913. if (!bSkip)
  21914. {
  21915. int iSearchRange = airRange();
  21916. bool bSkiesClear = true;
  21917. for (int iDX = -iSearchRange; iDX <= iSearchRange && bSkiesClear; iDX++)
  21918. {
  21919. for (int iDY = -iSearchRange; iDY <= iSearchRange && bSkiesClear; iDY++)
  21920. {
  21921. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  21922. if (pLoopPlot != NULL)
  21923. {
  21924. if (bestInterceptor(pLoopPlot) != NULL)
  21925. {
  21926. bSkiesClear = false;
  21927. break;
  21928. }
  21929. }
  21930. }
  21931. }
  21932. bSkip = !bSkiesClear;
  21933. }
  21934. if (bSkip)
  21935. {
  21936. getGroup()->pushMission(MISSION_SKIP);
  21937. return true;
  21938. }
  21939. return false;
  21940. }
  21941. */
  21942. // Returns true if a mission was pushed or we should wait for another unit to bombard...
  21943. bool CvUnitAI::AI_followBombard()
  21944. {
  21945. CLLNode<IDInfo>* pUnitNode;
  21946. CvUnit* pLoopUnit;
  21947. CvPlot* pAdjacentPlot1;
  21948. CvPlot* pAdjacentPlot2;
  21949. int iI, iJ;
  21950. if (canBombard(plot()))
  21951. {
  21952. getGroup()->pushMission(MISSION_BOMBARD);
  21953. return true;
  21954. }
  21955. if (getDomainType() == DOMAIN_LAND)
  21956. {
  21957. for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  21958. {
  21959. pAdjacentPlot1 = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
  21960. if (pAdjacentPlot1 != NULL)
  21961. {
  21962. if (pAdjacentPlot1->isCity())
  21963. {
  21964. if (AI_potentialEnemy(pAdjacentPlot1->getTeam(), pAdjacentPlot1))
  21965. {
  21966. for (iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
  21967. {
  21968. pAdjacentPlot2 = plotDirection(pAdjacentPlot1->getX_INLINE(), pAdjacentPlot1->getY_INLINE(), ((DirectionTypes)iJ));
  21969. if (pAdjacentPlot2 != NULL)
  21970. {
  21971. pUnitNode = pAdjacentPlot2->headUnitNode();
  21972. while (pUnitNode != NULL)
  21973. {
  21974. pLoopUnit = ::getUnit(pUnitNode->m_data);
  21975. pUnitNode = pAdjacentPlot2->nextUnitNode(pUnitNode);
  21976. if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
  21977. {
  21978. if (pLoopUnit->canBombard(pAdjacentPlot2))
  21979. {
  21980. if (pLoopUnit->isGroupHead())
  21981. {
  21982. if (pLoopUnit->getGroup() != getGroup())
  21983. {
  21984. if (pLoopUnit->getGroup()->readyToMove())
  21985. {
  21986. return true;
  21987. }
  21988. }
  21989. }
  21990. }
  21991. }
  21992. }
  21993. }
  21994. }
  21995. }
  21996. }
  21997. }
  21998. }
  21999. }
  22000. return false;
  22001. }
  22002. // Returns true if the unit has found a potential enemy...
  22003. bool CvUnitAI::AI_potentialEnemy(TeamTypes eTeam, const CvPlot* pPlot)
  22004. {
  22005. PROFILE_FUNC();
  22006. if (getGroup()->AI_isDeclareWar(pPlot))
  22007. {
  22008. return isPotentialEnemy(eTeam, pPlot);
  22009. }
  22010. else
  22011. {
  22012. return isEnemy(eTeam, pPlot);
  22013. }
  22014. }
  22015. // Returns true if this plot needs some defense...
  22016. bool CvUnitAI::AI_defendPlot(CvPlot* pPlot)
  22017. {
  22018. CvCity* pCity;
  22019. if (!canDefend(pPlot))
  22020. {
  22021. return false;
  22022. }
  22023. pCity = pPlot->getPlotCity();
  22024. if (pCity != NULL)
  22025. {
  22026. if (pCity->getOwnerINLINE() == getOwnerINLINE())
  22027. {
  22028. if (pCity->AI_isDanger())
  22029. {
  22030. return true;
  22031. }
  22032. }
  22033. }
  22034. else
  22035. {
  22036. if (pPlot->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE()) <= ((atPlot(pPlot)) ? 1 : 0))
  22037. {
  22038. if (pPlot->plotCount(PUF_cannotDefend, -1, -1, getOwnerINLINE()) > 0)
  22039. {
  22040. return true;
  22041. }
  22042. // if (pPlot->defenseModifier(getTeam(), false) >= 50 && pPlot->isRoute() && pPlot->getTeam() == getTeam())
  22043. // {
  22044. // return true;
  22045. // }
  22046. }
  22047. }
  22048. return false;
  22049. }
  22050. int CvUnitAI::AI_pillageValue(CvPlot* pPlot, int iBonusValueThreshold)
  22051. {
  22052. CvPlot* pAdjacentPlot;
  22053. ImprovementTypes eImprovement;
  22054. BonusTypes eNonObsoleteBonus;
  22055. int iValue;
  22056. int iTempValue;
  22057. int iBonusValue;
  22058. int iI;
  22059. FAssert(getGroup()->canPillage(pPlot) || canAirBombAt(plot(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) || (getGroup()->getCargo() > 0));
  22060. if (!(pPlot->isOwned()))
  22061. {
  22062. return 0;
  22063. }
  22064. // Advanced Tactics - pillage value is 0 for own plots
  22065. if (pPlot->getOwner() == getOwner())
  22066. {
  22067. return 0;
  22068. }
  22069. // End Advanced Tactics
  22070. CLLNode<IDInfo>* pUnitNode;
  22071. CvUnit* pLoopUnit;
  22072. bool bHasEnemyRouteTroops = false;
  22073. pUnitNode = getGroup()->headUnitNode();
  22074. while (pUnitNode != NULL)
  22075. {
  22076. pLoopUnit = ::getUnit(pUnitNode->m_data);
  22077. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  22078. if (pLoopUnit->isEnemyRoute())
  22079. {
  22080. bHasEnemyRouteTroops = true;
  22081. break;
  22082. }
  22083. }
  22084. if (pPlot->getImprovementType() == NO_IMPROVEMENT && bHasEnemyRouteTroops) // loops triggered when stack is led by units without enemyroute (Stooges for example)
  22085. {
  22086. return 0;
  22087. }
  22088. iBonusValue = 0;
  22089. eNonObsoleteBonus = pPlot->getNonObsoleteBonusType(pPlot->getTeam());
  22090. if (eNonObsoleteBonus != NO_BONUS)
  22091. {
  22092. iBonusValue = (GET_PLAYER(pPlot->getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus));
  22093. }
  22094. if (iBonusValueThreshold > 0)
  22095. {
  22096. if (eNonObsoleteBonus == NO_BONUS)
  22097. {
  22098. return 0;
  22099. }
  22100. else if (iBonusValue < iBonusValueThreshold)
  22101. {
  22102. return 0;
  22103. }
  22104. }
  22105. iValue = 0;
  22106. if (getDomainType() != DOMAIN_AIR)
  22107. {
  22108. if (pPlot->isRoute() && !isEnemyRoute())
  22109. {
  22110. iValue++;
  22111. if (eNonObsoleteBonus != NO_BONUS)
  22112. {
  22113. iValue += iBonusValue * 4;
  22114. }
  22115. for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
  22116. {
  22117. pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
  22118. if (pAdjacentPlot != NULL && pAdjacentPlot->getTeam() == pPlot->getTeam())
  22119. {
  22120. if (pAdjacentPlot->isCity())
  22121. {
  22122. iValue += 10;
  22123. }
  22124. if (!(pAdjacentPlot->isRoute()))
  22125. {
  22126. if (!(pAdjacentPlot->isWater()) && !(pAdjacentPlot->isImpassable()))
  22127. {
  22128. iValue += 2;
  22129. }
  22130. }
  22131. }
  22132. }
  22133. }
  22134. }
  22135. if (pPlot->getImprovementDuration() > ((pPlot->isWater()) ? 20 : 5))
  22136. {
  22137. eImprovement = pPlot->getImprovementType();
  22138. }
  22139. else
  22140. {
  22141. eImprovement = pPlot->getRevealedImprovementType(getTeam(), false);
  22142. }
  22143. if (eImprovement != NO_IMPROVEMENT)
  22144. {
  22145. if (pPlot->getWorkingCity() != NULL)
  22146. {
  22147. iValue += (pPlot->calculateImprovementYieldChange(eImprovement, YIELD_FOOD, pPlot->getOwnerINLINE()) * 5);
  22148. iValue += (pPlot->calculateImprovementYieldChange(eImprovement, YIELD_PRODUCTION, pPlot->getOwnerINLINE()) * 4);
  22149. iValue += (pPlot->calculateImprovementYieldChange(eImprovement, YIELD_COMMERCE, pPlot->getOwnerINLINE()) * 3);
  22150. }
  22151. if (getDomainType() != DOMAIN_AIR)
  22152. {
  22153. iValue += GC.getImprovementInfo(eImprovement).getPillageGold();
  22154. // raiders
  22155. iValue += (GC.getImprovementInfo(eImprovement).getPillageGold() * GET_PLAYER(getOwnerINLINE()).getPillagingGold()) / 100;
  22156. }
  22157. if (eNonObsoleteBonus != NO_BONUS)
  22158. {
  22159. //if (GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
  22160. if (GET_PLAYER(pPlot->getOwnerINLINE()).doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus)) // K-Mod
  22161. {
  22162. iTempValue = iBonusValue * 4;
  22163. if (pPlot->isConnectedToCapital() && (pPlot->getPlotGroupConnectedBonus(pPlot->getOwnerINLINE(), eNonObsoleteBonus) == 1))
  22164. {
  22165. iTempValue *= 2;
  22166. }
  22167. iValue += iTempValue;
  22168. }
  22169. }
  22170. }
  22171. return iValue;
  22172. }
  22173. int CvUnitAI::AI_nukeValue(CvCity* pCity)
  22174. {
  22175. PROFILE_FUNC();
  22176. FAssertMsg(pCity != NULL, "City is not assigned a valid value");
  22177. for (int iI = 0; iI < MAX_TEAMS; iI++)
  22178. {
  22179. CvTeam& kLoopTeam = GET_TEAM((TeamTypes)iI);
  22180. if (kLoopTeam.isAlive() && !isEnemy((TeamTypes)iI))
  22181. {
  22182. if (isNukeVictim(pCity->plot(), ((TeamTypes)iI)))
  22183. {
  22184. // Don't start wars with neutrals
  22185. return 0;
  22186. }
  22187. }
  22188. }
  22189. int iValue = 1;
  22190. iValue += GC.getGameINLINE().getSorenRandNum((pCity->getPopulation() + 1), "AI Nuke City Value");
  22191. iValue += std::max(0, pCity->getPopulation() - 10);
  22192. iValue += ((pCity->getPopulation() * (100 + pCity->calculateCulturePercent(pCity->getOwnerINLINE()))) / 100);
  22193. iValue += -(GET_PLAYER(getOwnerINLINE()).AI_getAttitudeVal(pCity->getOwnerINLINE()) / 3);
  22194. for (int iDX = -(nukeRange()); iDX <= nukeRange(); iDX++)
  22195. {
  22196. for (int iDY = -(nukeRange()); iDY <= nukeRange(); iDY++)
  22197. {
  22198. CvPlot* pLoopPlot = plotXY(pCity->getX_INLINE(), pCity->getY_INLINE(), iDX, iDY);
  22199. if (pLoopPlot != NULL)
  22200. {
  22201. if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT)
  22202. {
  22203. iValue++;
  22204. }
  22205. if (pLoopPlot->getBonusType() != NO_BONUS)
  22206. {
  22207. iValue++;
  22208. }
  22209. }
  22210. }
  22211. }
  22212. if (!(pCity->isEverOwned(getOwnerINLINE())))
  22213. {
  22214. iValue *= 3;
  22215. iValue /= 2;
  22216. }
  22217. if (!GET_TEAM(pCity->getTeam()).isAVassal())
  22218. {
  22219. iValue *= 2;
  22220. }
  22221. if (pCity->plot()->isVisible(getTeam(), false))
  22222. {
  22223. iValue += 2 * pCity->plot()->getNumVisibleEnemyDefenders(this);
  22224. }
  22225. else
  22226. {
  22227. iValue += 6;
  22228. }
  22229. return iValue;
  22230. }
  22231. int CvUnitAI::AI_searchRange(int iRange)
  22232. {
  22233. if (iRange == 0)
  22234. {
  22235. return 0;
  22236. }
  22237. if (getDuration() > 0)
  22238. {
  22239. //iRange = getDuration();
  22240. return getDuration() * baseMoves();
  22241. }
  22242. if (flatMovementCost() || (getDomainType() == DOMAIN_SEA))
  22243. {
  22244. return (iRange * baseMoves());
  22245. }
  22246. else
  22247. {
  22248. return ((iRange + 1) * (baseMoves() + 1));
  22249. }
  22250. }
  22251. // XXX at some point test the game with and without this function...
  22252. bool CvUnitAI::AI_plotValid(CvPlot* pPlot)
  22253. {
  22254. PROFILE_FUNC();
  22255. if (m_pUnitInfo->isNoRevealMap() && willRevealByMove(pPlot))
  22256. {
  22257. return false;
  22258. }
  22259. switch (getDomainType())
  22260. {
  22261. case DOMAIN_SEA:
  22262. if (pPlot->isWater() || canMoveAllTerrain())
  22263. {
  22264. return true;
  22265. }
  22266. else if (pPlot->isFriendlyCity(*this, true) && pPlot->isCoastalLand())
  22267. {
  22268. return true;
  22269. }
  22270. break;
  22271. case DOMAIN_AIR:
  22272. FAssert(false);
  22273. break;
  22274. case DOMAIN_LAND:
  22275. if (pPlot->getArea() == getArea() || canMoveAllTerrain())
  22276. {
  22277. return true;
  22278. }
  22279. break;
  22280. case DOMAIN_IMMOBILE:
  22281. FAssert(false);
  22282. break;
  22283. default:
  22284. FAssert(false);
  22285. break;
  22286. }
  22287. return false;
  22288. }
  22289. int CvUnitAI::AI_finalOddsThreshold(CvPlot* pPlot, int iOddsThreshold)
  22290. {
  22291. PROFILE_FUNC();
  22292. CvCity* pCity;
  22293. int iFinalOddsThreshold;
  22294. iFinalOddsThreshold = iOddsThreshold;
  22295. pCity = pPlot->getPlotCity();
  22296. if (pCity != NULL)
  22297. {
  22298. if (pCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE() * 3) / 4))
  22299. {
  22300. iFinalOddsThreshold += std::max(0, (pCity->getDefenseDamage() - pCity->getLastDefenseDamage() - (GC.getDefineINT("CITY_DEFENSE_DAMAGE_HEAL_RATE") * 2)));
  22301. }
  22302. }
  22303. /************************************************************************************************/
  22304. /* BETTER_BTS_AI_MOD 03/29/10 jdog5000 */
  22305. /* */
  22306. /* War tactics AI */
  22307. /************************************************************************************************/
  22308. /* original bts code
  22309. if (pPlot->getNumVisiblePotentialEnemyDefenders(this) == 1)
  22310. {
  22311. if (pCity != NULL)
  22312. {
  22313. iFinalOddsThreshold *= 2;
  22314. iFinalOddsThreshold /= 3;
  22315. }
  22316. else
  22317. {
  22318. iFinalOddsThreshold *= 7;
  22319. iFinalOddsThreshold /= 8;
  22320. }
  22321. }
  22322. if ((getDomainType() == DOMAIN_SEA) && !getGroup()->hasCargo())
  22323. {
  22324. iFinalOddsThreshold *= 3;
  22325. iFinalOddsThreshold /= 2 + getGroup()->getNumUnits();
  22326. }
  22327. else
  22328. {
  22329. iFinalOddsThreshold *= 6;
  22330. iFinalOddsThreshold /= (3 + GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pPlot, true) + ((stepDistance(getX_INLINE(), getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) > 1) ? 1 : 0) + ((AI_isCityAIType()) ? 2 : 0));
  22331. }
  22332. */
  22333. int iDefenders = pPlot->getNumVisiblePotentialEnemyDefenders(this);
  22334. if (iDefenders = 0 && pPlot->isVisible(getTeam(), false))
  22335. {
  22336. return 1;
  22337. }
  22338. // More aggressive if only one enemy defending city
  22339. if (iDefenders == 1 && pCity != NULL)
  22340. {
  22341. iFinalOddsThreshold *= 2;
  22342. iFinalOddsThreshold /= 3;
  22343. }
  22344. if ((getDomainType() == DOMAIN_SEA) && !getGroup()->hasCargo())
  22345. {
  22346. iFinalOddsThreshold *= 3 + (iDefenders/2);
  22347. iFinalOddsThreshold /= 2 + getGroup()->getNumUnits();
  22348. }
  22349. else
  22350. {
  22351. iFinalOddsThreshold *= 6 + (iDefenders/((pCity != NULL) ? 1 : 2));
  22352. int iDivisor = 3;
  22353. iDivisor += GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pPlot, true);
  22354. iDivisor += ((stepDistance(getX_INLINE(), getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) > 1) ? getGroup()->getNumUnits() : 0);
  22355. iDivisor += (AI_isCityAIType() ? 2 : 0);
  22356. iFinalOddsThreshold /= iDivisor;
  22357. }
  22358. /************************************************************************************************/
  22359. /* BETTER_BTS_AI_MOD END */
  22360. /************************************************************************************************/
  22361. // Tholal AI - encourage attack when attackers have a numbers advantage
  22362. if (getGroup()->getNumUnits() >= (iDefenders * 4))
  22363. {
  22364. iFinalOddsThreshold /= 2;
  22365. }
  22366. // End Tholal AI
  22367. return range(iFinalOddsThreshold, 1, 99);
  22368. }
  22369. int CvUnitAI::AI_stackOfDoomExtra()
  22370. {
  22371. return ((AI_getBirthmark() % (1 + GC.getGameINLINE().getCurrentEra())) + 4);
  22372. }
  22373. bool CvUnitAI::AI_stackAttackCity(int iRange, int iPowerThreshold, bool bFollow)
  22374. {
  22375. PROFILE_FUNC();
  22376. CvPlot* pLoopPlot;
  22377. CvPlot* pBestPlot;
  22378. int iSearchRange;
  22379. int iPathTurns;
  22380. int iValue;
  22381. int iBestValue;
  22382. int iDX, iDY;
  22383. FAssert(canMove());
  22384. if (bFollow)
  22385. {
  22386. iSearchRange = 1;
  22387. }
  22388. else
  22389. {
  22390. iSearchRange = AI_searchRange(iRange);
  22391. }
  22392. iBestValue = 0;
  22393. pBestPlot = NULL;
  22394. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  22395. {
  22396. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  22397. {
  22398. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  22399. if (pLoopPlot != NULL)
  22400. {
  22401. if (AI_plotValid(pLoopPlot))
  22402. {
  22403. // Super Forts begin *AI_offense* - modified if statement so forts are attacked too
  22404. if (pLoopPlot->isCity(GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)))
  22405. //if (pLoopPlot->isCity() || (pLoopPlot->isCity(true) && pLoopPlot->isVisibleEnemyUnit(this))) - Original Code
  22406. // Super Forts end
  22407. {
  22408. if (AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
  22409. {
  22410. if (!atPlot(pLoopPlot) && ((bFollow) ? canMoveInto(pLoopPlot, /*bAttack*/ true, /*bDeclareWar*/ true) : (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= iRange))))
  22411. {
  22412. iValue = getGroup()->AI_compareStacks(pLoopPlot, /*bPotentialEnemy*/ true, /*bCheckCanAttack*/ true, /*bCheckCanMove*/ true);
  22413. if (iValue >= iPowerThreshold)
  22414. {
  22415. if (iValue > iBestValue)
  22416. {
  22417. iBestValue = iValue;
  22418. pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
  22419. FAssert(!atPlot(pBestPlot));
  22420. }
  22421. }
  22422. }
  22423. }
  22424. }
  22425. }
  22426. }
  22427. }
  22428. }
  22429. if (pBestPlot != NULL)
  22430. {
  22431. if( gUnitLogLevel >= 1 && pBestPlot->getPlotCity() != NULL )
  22432. {
  22433. logBBAI(" Stack for player %d (%S) decides to attack city %S with stack ratio %d", getOwner(), GET_PLAYER(getOwner()).getCivilizationDescription(0), pBestPlot->getPlotCity()->getName(0).GetCString(), iBestValue );
  22434. logBBAI(" City %S has defense modifier %d, %d with ignore building", pBestPlot->getPlotCity()->getName(0).GetCString(), pBestPlot->getPlotCity()->getDefenseModifier(false), pBestPlot->getPlotCity()->getDefenseModifier(true) );
  22435. }
  22436. FAssert(!atPlot(pBestPlot));
  22437. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
  22438. return true;
  22439. }
  22440. return false;
  22441. }
  22442. bool CvUnitAI::AI_moveIntoCity(int iRange)
  22443. {
  22444. PROFILE_FUNC();
  22445. CvPlot* pLoopPlot;
  22446. CvPlot* pBestPlot;
  22447. int iSearchRange = iRange;
  22448. int iPathTurns;
  22449. int iValue;
  22450. int iBestValue;
  22451. int iDX, iDY;
  22452. FAssert(canMove());
  22453. iBestValue = 0;
  22454. pBestPlot = NULL;
  22455. if (plot()->isCity())
  22456. {
  22457. return false;
  22458. }
  22459. iSearchRange = AI_searchRange(iRange);
  22460. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  22461. {
  22462. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  22463. {
  22464. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  22465. if (pLoopPlot != NULL)
  22466. {
  22467. if (AI_plotValid(pLoopPlot) && (!isEnemy(pLoopPlot->getTeam(), pLoopPlot)))
  22468. {
  22469. if (pLoopPlot->isCity() || (pLoopPlot->isCity(true)))
  22470. {
  22471. if (canMoveInto(pLoopPlot, false) && (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= 1)))
  22472. {
  22473. iValue = 1;
  22474. if (pLoopPlot->getPlotCity() != NULL)
  22475. {
  22476. iValue += pLoopPlot->getPlotCity()->getPopulation();
  22477. }
  22478. if (iValue > iBestValue)
  22479. {
  22480. iBestValue = iValue;
  22481. pBestPlot = getPathEndTurnPlot();
  22482. FAssert(!atPlot(pBestPlot));
  22483. }
  22484. }
  22485. }
  22486. }
  22487. }
  22488. }
  22489. }
  22490. if (pBestPlot != NULL)
  22491. {
  22492. FAssert(!atPlot(pBestPlot));
  22493. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  22494. return true;
  22495. }
  22496. return false;
  22497. }
  22498. //bolsters the culture of the weakest city.
  22499. //returns true if a mission is pushed.
  22500. bool CvUnitAI::AI_artistCultureVictoryMove()
  22501. {
  22502. bool bGreatWork = false;
  22503. bool bJoin = true;
  22504. /************************************************************************************************/
  22505. /* BETTER_BTS_AI_MOD 03/08/10 jdog5000 */
  22506. /* */
  22507. /* Victory Strategy AI */
  22508. /************************************************************************************************/
  22509. if (!(GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE1)))
  22510. {
  22511. return false;
  22512. }
  22513. if (GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE3))
  22514. {
  22515. //Great Work
  22516. bGreatWork = true;
  22517. }
  22518. /************************************************************************************************/
  22519. /* BETTER_BTS_AI_MOD END */
  22520. /************************************************************************************************/
  22521. int iCultureCitiesNeeded = GC.getGameINLINE().culturalVictoryNumCultureCities();
  22522. FAssertMsg(iCultureCitiesNeeded > 0, "CultureVictory Strategy should not be true");
  22523. CvCity* pLoopCity;
  22524. CvPlot* pBestPlot;
  22525. CvCity* pBestCity;
  22526. SpecialistTypes eBestSpecialist;
  22527. int iLoop, iValue, iBestValue;
  22528. pBestPlot = NULL;
  22529. eBestSpecialist = NO_SPECIALIST;
  22530. pBestCity = NULL;
  22531. iBestValue = 0;
  22532. iLoop = 0;
  22533. int iTargetCultureRank = iCultureCitiesNeeded;
  22534. while (iTargetCultureRank > 0 && pBestCity == NULL)
  22535. {
  22536. for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
  22537. {
  22538. /************************************************************************************************/
  22539. /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
  22540. /* */
  22541. /* Unit AI, Efficiency */
  22542. /************************************************************************************************/
  22543. // BBAI efficiency: check same area
  22544. if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
  22545. /************************************************************************************************/
  22546. /* BETTER_BTS_AI_MOD END */
  22547. /************************************************************************************************/
  22548. {
  22549. // instead of commerce rate rank should use the culture on tile...
  22550. if (pLoopCity->findCommerceRateRank(COMMERCE_CULTURE) == iTargetCultureRank)
  22551. {
  22552. // if the city is a fledgling, probably building culture, try next higher city
  22553. if (pLoopCity->getCultureLevel() < 2)
  22554. {
  22555. break;
  22556. }
  22557. // if we cannot path there, try the next higher culture city
  22558. if (!generatePath(pLoopCity->plot(), 0, true))
  22559. {
  22560. break;
  22561. }
  22562. pBestCity = pLoopCity;
  22563. pBestPlot = pLoopCity->plot();
  22564. if (bGreatWork)
  22565. {
  22566. if (canGreatWork(pBestPlot))
  22567. {
  22568. break;
  22569. }
  22570. }
  22571. for (int iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
  22572. {
  22573. if (canJoin(pBestPlot, ((SpecialistTypes)iI)))
  22574. {
  22575. iValue = pLoopCity->AI_specialistValue(((SpecialistTypes)iI), pLoopCity->AI_avoidGrowth(), false);
  22576. if (iValue > iBestValue)
  22577. {
  22578. iBestValue = iValue;
  22579. eBestSpecialist = ((SpecialistTypes)iI);
  22580. }
  22581. }
  22582. }
  22583. if (eBestSpecialist == NO_SPECIALIST)
  22584. {
  22585. bJoin = false;
  22586. if (canGreatWork(pBestPlot))
  22587. {
  22588. bGreatWork = true;
  22589. break;
  22590. }
  22591. bGreatWork = false;
  22592. }
  22593. break;
  22594. }
  22595. }
  22596. }
  22597. iTargetCultureRank--;
  22598. }
  22599. FAssertMsg(bGreatWork || bJoin, "This wasn't a Great Artist");
  22600. if (pBestCity == NULL)
  22601. {
  22602. //should try to airlift there...
  22603. return false;
  22604. }
  22605. if (atPlot(pBestPlot))
  22606. {
  22607. if (bGreatWork)
  22608. {
  22609. getGroup()->pushMission(MISSION_GREAT_WORK);
  22610. return true;
  22611. }
  22612. if (bJoin)
  22613. {
  22614. getGroup()->pushMission(MISSION_JOIN, eBestSpecialist);
  22615. return true;
  22616. }
  22617. FAssert(false);
  22618. return false;
  22619. }
  22620. else
  22621. {
  22622. FAssert(!atPlot(pBestPlot));
  22623. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  22624. return true;
  22625. }
  22626. }
  22627. bool CvUnitAI::AI_poach()
  22628. {
  22629. CvPlot* pLoopPlot;
  22630. int iX, iY;
  22631. int iBestPoachValue = 0;
  22632. CvPlot* pBestPoachPlot = NULL;
  22633. TeamTypes eBestPoachTeam = NO_TEAM;
  22634. /*
  22635. if (!GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI))
  22636. {
  22637. return false;
  22638. }
  22639. */
  22640. if (GET_TEAM(getTeam()).getNumMembers() > 1)
  22641. {
  22642. return false;
  22643. }
  22644. int iNoPoachRoll = GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_WORKER);
  22645. iNoPoachRoll += GET_PLAYER(getOwnerINLINE()).getNumCities();
  22646. iNoPoachRoll = std::max(0, (iNoPoachRoll - 1) / 2);
  22647. if (GC.getGameINLINE().getSorenRandNum(iNoPoachRoll, "AI Poach") > 0)
  22648. {
  22649. return false;
  22650. }
  22651. if (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0)
  22652. {
  22653. return false;
  22654. }
  22655. FAssert(canAttack());
  22656. int iRange = 1;
  22657. //Look for a unit which is non-combat
  22658. //and has a capture unit type
  22659. for (iX = -iRange; iX <= iRange; iX++)
  22660. {
  22661. for (iY = -iRange; iY <= iRange; iY++)
  22662. {
  22663. if (iX != 0 && iY != 0)
  22664. {
  22665. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
  22666. if ((pLoopPlot != NULL) && (pLoopPlot->getTeam() != getTeam()) && pLoopPlot->isVisible(getTeam(), false))
  22667. {
  22668. int iPoachCount = 0;
  22669. int iDefenderCount = 0;
  22670. CvUnit* pPoachUnit = NULL;
  22671. CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
  22672. while (pUnitNode != NULL)
  22673. {
  22674. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  22675. pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
  22676. if ((pLoopUnit->getTeam() != getTeam())
  22677. && GET_TEAM(getTeam()).canDeclareWar(pLoopUnit->getTeam()))
  22678. {
  22679. if (!pLoopUnit->canDefend())
  22680. {
  22681. if (pLoopUnit->getCaptureUnitType(getCivilizationType()) != NO_UNIT)
  22682. {
  22683. iPoachCount++;
  22684. pPoachUnit = pLoopUnit;
  22685. }
  22686. }
  22687. else
  22688. {
  22689. iDefenderCount++;
  22690. }
  22691. }
  22692. }
  22693. if (pPoachUnit != NULL)
  22694. {
  22695. if (iDefenderCount == 0)
  22696. {
  22697. int iValue = iPoachCount * 100;
  22698. iValue -= iNoPoachRoll * 25;
  22699. if (iValue > iBestPoachValue)
  22700. {
  22701. iBestPoachValue = iValue;
  22702. pBestPoachPlot = pLoopPlot;
  22703. eBestPoachTeam = pPoachUnit->getTeam();
  22704. }
  22705. }
  22706. }
  22707. }
  22708. }
  22709. }
  22710. }
  22711. if (pBestPoachPlot != NULL)
  22712. {
  22713. if( gUnitLogLevel >= 3 )
  22714. {
  22715. logBBAI(" Stack (led by %d, size %d) poaching (%d, %d)", getID(), getGroup()->getNumUnits(), pBestPoachPlot->getX(), pBestPoachPlot->getY());
  22716. }
  22717. //No war roll.
  22718. if (!GET_TEAM(getTeam()).AI_performNoWarRolls(eBestPoachTeam))
  22719. {
  22720. GET_TEAM(getTeam()).declareWar(eBestPoachTeam, true, WARPLAN_LIMITED);
  22721. FAssert(!atPlot(pBestPoachPlot));
  22722. getGroup()->pushMission(MISSION_MOVE_TO, pBestPoachPlot->getX_INLINE(), pBestPoachPlot->getY_INLINE(), MOVE_DIRECT_ATTACK);
  22723. return true;
  22724. }
  22725. }
  22726. return false;
  22727. }
  22728. /************************************************************************************************/
  22729. /* BETTER_BTS_AI_MOD 03/31/10 jdog5000 */
  22730. /* */
  22731. /* War tactics AI */
  22732. /************************************************************************************************/
  22733. bool CvUnitAI::AI_choke(int iRange, bool bDefensive)
  22734. {
  22735. PROFILE_FUNC();
  22736. int iPercentDefensive;
  22737. {
  22738. int iDefCount = 0;
  22739. CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
  22740. CvUnit* pLoopUnit = NULL;
  22741. while (pUnitNode != NULL)
  22742. {
  22743. pLoopUnit = ::getUnit(pUnitNode->m_data);
  22744. iDefCount += pLoopUnit->noDefensiveBonus() ? 0 : 1;
  22745. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  22746. }
  22747. iPercentDefensive = 100 * iDefCount / getGroup()->getNumUnits();
  22748. }
  22749. CvPlot* pBestPlot = 0;
  22750. CvPlot* pEndTurnPlot = 0;
  22751. int iBestValue = 0;
  22752. for (int iX = -iRange; iX <= iRange; iX++)
  22753. {
  22754. for (int iY = -iRange; iY <= iRange; iY++)
  22755. {
  22756. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
  22757. if (pLoopPlot && isEnemy(pLoopPlot->getTeam()) && !pLoopPlot->isVisibleEnemyUnit(this))
  22758. {
  22759. int iPathTurns;
  22760. if (pLoopPlot->getWorkingCity() && generatePath(pLoopPlot, 0, true, &iPathTurns))
  22761. {
  22762. FAssert(pLoopPlot->getWorkingCity()->getTeam() == pLoopPlot->getTeam());
  22763. //int iValue = (bDefensive ? pLoopPlot->defenseModifier(getTeam(), false) : -15);
  22764. int iValue = bDefensive ? pLoopPlot->defenseModifier(getTeam(), false) - 15 : 0; // K-Mod
  22765. if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
  22766. {
  22767. iValue = GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(pLoopPlot->getBonusType(), 0);
  22768. }
  22769. iValue += pLoopPlot->getYield(YIELD_PRODUCTION) * 9; // was 10
  22770. iValue += pLoopPlot->getYield(YIELD_FOOD) * 12; // was 10
  22771. iValue += pLoopPlot->getYield(YIELD_COMMERCE) * 5;
  22772. if (atPlot(pLoopPlot) && getGroup()->canPillage(pLoopPlot))
  22773. {
  22774. iValue += AI_pillageValue(pLoopPlot, 0) / (bDefensive ? 2 : 1);
  22775. }
  22776. if (iValue > 0)
  22777. {
  22778. iValue *= (bDefensive ? 25 : 50) + iPercentDefensive * pLoopPlot->defenseModifier(getTeam(), false) / 100;
  22779. if (bDefensive)
  22780. {
  22781. // for defensive, we care a lot about path turns
  22782. iValue *= 10;
  22783. iValue /= std::max(1, iPathTurns);
  22784. }
  22785. else
  22786. {
  22787. // otherwise we just want to block as many tiles as possible
  22788. iValue *= 10;
  22789. iValue /= std::max(1, pLoopPlot->getNumDefenders(getOwnerINLINE()) + (pLoopPlot == plot() ? 0 : getGroup()->getNumUnits()));
  22790. }
  22791. if (iValue > iBestValue)
  22792. {
  22793. pBestPlot = pLoopPlot;
  22794. pEndTurnPlot = getPathEndTurnPlot();
  22795. iBestValue = iValue;
  22796. }
  22797. }
  22798. }
  22799. }
  22800. }
  22801. }
  22802. if (pBestPlot)
  22803. {
  22804. FAssert(pBestPlot->getWorkingCity());
  22805. CvPlot* pChokedCityPlot = pBestPlot->getWorkingCity()->plot();
  22806. if (atPlot(pBestPlot))
  22807. {
  22808. FAssert(atPlot(pEndTurnPlot));
  22809. if (plot()->getImprovementType() != NO_IMPROVEMENT || !isEnemyRoute())
  22810. {
  22811. if (getGroup()->canPillage(plot()))
  22812. getGroup()->pushMission(MISSION_PILLAGE);
  22813. else
  22814. getGroup()->pushMission(MISSION_SKIP);
  22815. }
  22816. else
  22817. {
  22818. getGroup()->pushMission(MISSION_SKIP);
  22819. }
  22820. return true;
  22821. }
  22822. else
  22823. {
  22824. FAssert(!atPlot(pEndTurnPlot));
  22825. getGroup()->pushMission(MISSION_MOVE_TO, pEndTurnPlot->getX(), pEndTurnPlot->getY());
  22826. return true;
  22827. }
  22828. }
  22829. return false;
  22830. }
  22831. /************************************************************************************************/
  22832. /* BETTER_BTS_AI_MOD END */
  22833. /************************************************************************************************/
  22834. bool CvUnitAI::AI_solveBlockageProblem(CvPlot* pDestPlot, bool bDeclareWar)
  22835. {
  22836. PROFILE_FUNC();
  22837. FAssert(pDestPlot != NULL);
  22838. if (pDestPlot != NULL)
  22839. {
  22840. FAStarNode* pStepNode;
  22841. CvPlot* pSourcePlot = plot();
  22842. if (gDLL->getFAStarIFace()->GeneratePath(&GC.getStepFinder(), pSourcePlot->getX_INLINE(), pSourcePlot->getY_INLINE(), pDestPlot->getX_INLINE(), pDestPlot->getY_INLINE(), false, 0, true))
  22843. {
  22844. pStepNode = gDLL->getFAStarIFace()->GetLastNode(&GC.getStepFinder());
  22845. while (pStepNode != NULL)
  22846. {
  22847. CvPlot* pStepPlot = GC.getMapINLINE().plotSorenINLINE(pStepNode->m_iX, pStepNode->m_iY);
  22848. if (canMoveOrAttackInto(pStepPlot) && generatePath(pStepPlot, 0, true))
  22849. {
  22850. if (bDeclareWar && pStepNode->m_pPrev != NULL)
  22851. {
  22852. CvPlot* pPlot = GC.getMapINLINE().plotSorenINLINE(pStepNode->m_pPrev->m_iX, pStepNode->m_pPrev->m_iY);
  22853. if (pPlot->getTeam() != NO_TEAM)
  22854. {
  22855. if (!canMoveInto(pPlot, true, true))
  22856. {
  22857. if (!isPotentialEnemy(pPlot->getTeam(), pPlot))
  22858. {
  22859. CvTeamAI& kTeam = GET_TEAM(getTeam());
  22860. if (kTeam.canDeclareWar(pPlot->getTeam()))
  22861. {
  22862. WarPlanTypes eWarPlan = WARPLAN_LIMITED;
  22863. WarPlanTypes eExistingWarPlan = kTeam.AI_getWarPlan(pDestPlot->getTeam());
  22864. if (eExistingWarPlan != NO_WARPLAN)
  22865. {
  22866. if ((eExistingWarPlan == WARPLAN_TOTAL) || (eExistingWarPlan == WARPLAN_PREPARING_TOTAL))
  22867. {
  22868. eWarPlan = WARPLAN_TOTAL;
  22869. }
  22870. if (!kTeam.isAtWar(pDestPlot->getTeam()))
  22871. {
  22872. kTeam.AI_setWarPlan(pDestPlot->getTeam(), NO_WARPLAN);
  22873. }
  22874. }
  22875. kTeam.AI_setWarPlan(pPlot->getTeam(), eWarPlan, true);
  22876. /************************************************************************************************/
  22877. /* BETTER_BTS_AI_MOD 03/29/10 jdog5000 */
  22878. /* */
  22879. /* War tactics AI */
  22880. /************************************************************************************************/
  22881. /* original bts code
  22882. return (AI_targetCity());
  22883. */
  22884. return (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2));
  22885. /************************************************************************************************/
  22886. /* BETTER_BTS_AI_MOD END */
  22887. /************************************************************************************************/
  22888. }
  22889. }
  22890. }
  22891. }
  22892. }
  22893. if (pStepPlot->isVisibleEnemyUnit(this))
  22894. {
  22895. FAssert(canAttack());
  22896. CvPlot* pBestPlot = pStepPlot;
  22897. //To prevent puppeteering attempt to barge through
  22898. //if quite close
  22899. if (getPathLastNode()->m_iData2 > 3)
  22900. {
  22901. pBestPlot = getPathEndTurnPlot();
  22902. }
  22903. FAssert(!atPlot(pBestPlot));
  22904. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_DIRECT_ATTACK);
  22905. return true;
  22906. }
  22907. }
  22908. pStepNode = pStepNode->m_pParent;
  22909. }
  22910. }
  22911. }
  22912. return false;
  22913. }
  22914. int CvUnitAI::AI_calculatePlotWorkersNeeded(CvPlot* pPlot, BuildTypes eBuild)
  22915. {
  22916. int iBuildTime = pPlot->getBuildTime(eBuild) - pPlot->getBuildProgress(eBuild);
  22917. int iWorkRate = workRate(true);
  22918. if (iWorkRate <= 0)
  22919. {
  22920. FAssert(false);
  22921. return 1;
  22922. }
  22923. int iTurns = iBuildTime / iWorkRate;
  22924. if (iBuildTime > (iTurns * iWorkRate))
  22925. {
  22926. iTurns++;
  22927. }
  22928. int iNeeded = std::max(1, (iTurns + 2) / 3);
  22929. if (pPlot->getBonusType() != NO_BONUS)
  22930. {
  22931. iNeeded *= 2;
  22932. }
  22933. return iNeeded;
  22934. }
  22935. bool CvUnitAI::AI_canGroupWithAIType(UnitAITypes eUnitAI) const
  22936. {
  22937. if (eUnitAI != AI_getUnitAIType())
  22938. {
  22939. switch (eUnitAI)
  22940. {
  22941. case (UNITAI_ATTACK_CITY):
  22942. if (plot()->isCity() && (GC.getGame().getGameTurn() - plot()->getPlotCity()->getGameTurnAcquired()) <= 1)
  22943. {
  22944. return false;
  22945. }
  22946. break;
  22947. /*************************************************************************************************/
  22948. /** BETTER AI (first city) Sephi **/
  22949. /** **/
  22950. /** **/
  22951. /*************************************************************************************************/
  22952. case (UNITAI_SETTLE):
  22953. if (GC.getGame().getGameTurn()<10)
  22954. {
  22955. return false;
  22956. }
  22957. break;
  22958. /*************************************************************************************************/
  22959. /** END **/
  22960. /*************************************************************************************************/
  22961. default:
  22962. break;
  22963. }
  22964. }
  22965. return true;
  22966. }
  22967. bool CvUnitAI::AI_allowGroup(const CvUnit* pUnit, UnitAITypes eUnitAI) const
  22968. {
  22969. CvSelectionGroup* pGroup = pUnit->getGroup();
  22970. CvPlot* pPlot = pUnit->plot();
  22971. /*************************************************************************************************/
  22972. /** BETTER AI (Group with Conquest stack) Sephi **/
  22973. /*************************************************************************************************/
  22974. CvUnit* tempUnit=getGroup()->getHeadUnit();
  22975. if (tempUnit!=NULL)
  22976. {
  22977. if (tempUnit->AI_getGroupflag()==GROUPFLAG_CONQUEST || tempUnit->AI_getUnitAIType()==UNITAI_HERO)
  22978. {
  22979. if (pUnit == this)
  22980. {
  22981. return false;
  22982. }
  22983. if (!pUnit->isGroupHead())
  22984. {
  22985. return false;
  22986. }
  22987. if (pGroup == getGroup())
  22988. {
  22989. return false;
  22990. }
  22991. if (pUnit->isCargo())
  22992. {
  22993. return false;
  22994. }
  22995. //FfH: Added by Kael 08/18/2008
  22996. if ((plot() != pPlot) && (pPlot->isVisibleEnemyUnit((PlayerTypes)getOwnerINLINE())))
  22997. {
  22998. return false;
  22999. }
  23000. //FfH: End Add
  23001. switch (pGroup->AI_getMissionAIType())
  23002. {
  23003. case MISSIONAI_GUARD_CITY:
  23004. // do not join groups that are guarding cities
  23005. // intentional fallthrough
  23006. case MISSIONAI_LOAD_SETTLER:
  23007. case MISSIONAI_LOAD_ASSAULT:
  23008. case MISSIONAI_LOAD_SPECIAL:
  23009. // do not join groups that are loading into transports (we might not fit and get stuck in loop forever)
  23010. return false;
  23011. break;
  23012. default:
  23013. break;
  23014. }
  23015. if (!canJoinGroup(pPlot, pGroup))
  23016. {
  23017. return false;
  23018. }
  23019. if (eUnitAI == UNITAI_ASSAULT_SEA)
  23020. {
  23021. if (!pGroup->hasCargo())
  23022. {
  23023. return false;
  23024. }
  23025. }
  23026. if (pUnit->getInvisibleType() != NO_INVISIBLE)
  23027. {
  23028. if (getInvisibleType() == NO_INVISIBLE)
  23029. {
  23030. return false;
  23031. }
  23032. }
  23033. if (tempUnit->AI_getGroupflag()==GROUPFLAG_CONQUEST)
  23034. {
  23035. if (!pUnit->getGroup()->getHeadUnit())
  23036. {
  23037. return false;
  23038. }
  23039. else if (pUnit->getGroup()->getHeadUnit()->AI_getGroupflag()!=GROUPFLAG_CONQUEST)
  23040. {
  23041. return false;
  23042. }
  23043. }
  23044. return true;
  23045. }
  23046. }
  23047. /*************************************************************************************************/
  23048. /** END **/
  23049. /*************************************************************************************************/
  23050. if (pUnit == this)
  23051. {
  23052. return false;
  23053. }
  23054. if (!pUnit->isGroupHead())
  23055. {
  23056. return false;
  23057. }
  23058. if (pGroup == getGroup())
  23059. {
  23060. return false;
  23061. }
  23062. if (pUnit->isCargo())
  23063. {
  23064. return false;
  23065. }
  23066. // if (pUnit->AI_getUnitAIType() != eUnitAI)
  23067. if (eUnitAI != UNITAI_UNKNOWN && pUnit->AI_getUnitAIType() != eUnitAI)
  23068. {
  23069. return false;
  23070. }
  23071. //FfH: Added by Kael 08/18/2008
  23072. if ((plot() != pPlot) && (pPlot->isVisibleEnemyUnit((PlayerTypes)getOwnerINLINE())))
  23073. {
  23074. return false;
  23075. }
  23076. //FfH: End Add
  23077. switch (pGroup->AI_getMissionAIType())
  23078. {
  23079. case MISSIONAI_GUARD_CITY:
  23080. // do not join groups that are guarding cities
  23081. // intentional fallthrough
  23082. case MISSIONAI_LOAD_SETTLER:
  23083. case MISSIONAI_LOAD_ASSAULT:
  23084. case MISSIONAI_LOAD_SPECIAL:
  23085. // do not join groups that are loading into transports (we might not fit and get stuck in loop forever)
  23086. return false;
  23087. break;
  23088. // ALN - Barbs shouldn't go after a group already joining another group
  23089. case MISSIONAI_GROUP:
  23090. if (isBarbarian())
  23091. {
  23092. return false;
  23093. }
  23094. default:
  23095. break;
  23096. }
  23097. if (pGroup->getActivityType() == ACTIVITY_HEAL)
  23098. {
  23099. // do not attempt to join groups which are healing this turn
  23100. // (healing is cleared every turn for automated groups, so we know we pushed a heal this turn)
  23101. return false;
  23102. }
  23103. if (!canJoinGroup(pPlot, pGroup))
  23104. {
  23105. return false;
  23106. }
  23107. if (eUnitAI == UNITAI_SETTLE)
  23108. {
  23109. /************************************************************************************************/
  23110. /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
  23111. /* */
  23112. /* Unit AI, Efficiency */
  23113. /************************************************************************************************/
  23114. //if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pPlot, 3) > 0)
  23115. if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(pPlot, 3)) // Tholal NOte - Why is this here?
  23116. {
  23117. //return false;
  23118. }
  23119. /************************************************************************************************/
  23120. /* BETTER_BTS_AI_MOD END */
  23121. /************************************************************************************************/
  23122. }
  23123. else if (eUnitAI == UNITAI_ASSAULT_SEA)
  23124. {
  23125. if (!pGroup->hasCargo())
  23126. {
  23127. return false;
  23128. }
  23129. }
  23130. if ((getGroup()->getHeadUnitAI() == UNITAI_CITY_DEFENSE))
  23131. {
  23132. if (plot()->isCity() && (plot()->getTeam() == getTeam()) && plot()->getBestDefender(getOwnerINLINE())->getGroup() == getGroup())
  23133. {
  23134. return false;
  23135. }
  23136. }
  23137. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  23138. {
  23139. CvPlot* pTargetPlot = pGroup->AI_getMissionAIPlot();
  23140. if (pTargetPlot != NULL)
  23141. {
  23142. if (pTargetPlot->isOwned())
  23143. {
  23144. if (isPotentialEnemy(pTargetPlot->getTeam(), pTargetPlot))
  23145. {
  23146. //Do not join groups which have debarked on an offensive mission
  23147. return false;
  23148. }
  23149. }
  23150. }
  23151. }
  23152. if (pUnit->getInvisibleType() != NO_INVISIBLE)
  23153. {
  23154. if (getInvisibleType() == NO_INVISIBLE)
  23155. {
  23156. return false;
  23157. }
  23158. }
  23159. return true;
  23160. }
  23161. void CvUnitAI::read(FDataStreamBase* pStream)
  23162. {
  23163. CvUnit::read(pStream);
  23164. uint uiFlag=0;
  23165. pStream->Read(&uiFlag); // flags for expansion
  23166. pStream->Read(&m_iBirthmark);
  23167. /*************************************************************************************************/
  23168. /** BETTER AI (New Functions Definition) Sephi **/
  23169. /*************************************************************************************************/
  23170. pStream->Read(&m_bAllowedPermDefense);
  23171. pStream->Read(&m_bPermanentSummon);
  23172. pStream->Read(&m_bSuicideSummon);
  23173. pStream->Read(&m_iGroupflag);
  23174. /*************************************************************************************************/
  23175. /** END **/
  23176. /*************************************************************************************************/
  23177. pStream->Read((int*)&m_eUnitAIType);
  23178. pStream->Read(&m_iAutomatedAbortTurn);
  23179. }
  23180. void CvUnitAI::write(FDataStreamBase* pStream)
  23181. {
  23182. CvUnit::write(pStream);
  23183. uint uiFlag=0;
  23184. pStream->Write(uiFlag); // flag for expansion
  23185. pStream->Write(m_iBirthmark);
  23186. /*************************************************************************************************/
  23187. /** BETTER AI (New Functions Definition) Sephi **/
  23188. /*************************************************************************************************/
  23189. pStream->Write(m_bAllowedPermDefense);
  23190. pStream->Write(m_bPermanentSummon);
  23191. pStream->Write(m_bSuicideSummon);
  23192. pStream->Write(m_iGroupflag);
  23193. /*************************************************************************************************/
  23194. /** END **/
  23195. /*************************************************************************************************/
  23196. pStream->Write(m_eUnitAIType);
  23197. pStream->Write(m_iAutomatedAbortTurn);
  23198. }
  23199. // Private Functions...
  23200. //FfH: Added by Kael 09/19/2007
  23201. void CvUnitAI::AI_summonAttackMove()
  23202. {
  23203. PROFILE_FUNC();
  23204. // Floating Eyes
  23205. if (getDomainType() == DOMAIN_AIR)
  23206. {
  23207. if (canRecon(plot()))
  23208. {
  23209. if (AI_exploreAir())
  23210. {
  23211. return;
  23212. }
  23213. else
  23214. {
  23215. getGroup()->pushMission(MISSION_SKIP);
  23216. return;
  23217. }
  23218. }
  23219. }
  23220. bool bBombard = (bombardRate() > 0);
  23221. bool bCollateral = (getUnitInfo().isExplodeInCombat() || (collateralDamage() > 0));
  23222. if (getDuration() > 0)
  23223. {
  23224. if (bBombard)
  23225. {
  23226. if (AI_bombardCity())
  23227. {
  23228. return;
  23229. }
  23230. // check for distant bombard targets
  23231. CvCity* pTargetCity = NULL;
  23232. pTargetCity = AI_pickTargetCity(0, getDuration(), true);
  23233. if( pTargetCity != NULL )
  23234. {
  23235. if( AI_goToTargetCity(0, (getDuration() - 1), pTargetCity) )
  23236. {
  23237. if (AI_bombardCity())
  23238. {
  23239. return;
  23240. }
  23241. return;
  23242. }
  23243. }
  23244. }
  23245. if (AI_anyAttack(getDuration(), (bCollateral ? 0 : 25)))
  23246. {
  23247. return;
  23248. }
  23249. }
  23250. else
  23251. {
  23252. if (AI_anyAttack(baseMoves(), (bCollateral ? 0: 10)))
  23253. {
  23254. return;
  23255. }
  23256. }
  23257. if (AI_patrol())
  23258. {
  23259. return;
  23260. }
  23261. if (AI_retreatToCity())
  23262. {
  23263. return;
  23264. }
  23265. getGroup()->pushMission(MISSION_SKIP);
  23266. return;
  23267. }
  23268. //FfH: End Add
  23269. /*************************************************************************************************/
  23270. /** BETTER AI (New Functions) Sephi **/
  23271. /** **/
  23272. /** **/
  23273. /*************************************************************************************************/
  23274. int CvUnitAI::AI_getGroupflag() const
  23275. {
  23276. return m_iGroupflag;
  23277. }
  23278. void CvUnitAI::AI_setGroupflag(int newflag)
  23279. {
  23280. m_iGroupflag=newflag;
  23281. }
  23282. // Chooses the Groupflag for AI Units in CvUnit::DoTurn()
  23283. void CvUnitAI::AI_chooseGroupflag()
  23284. {
  23285. CvPlayerAI &kPlayer = GET_PLAYER(getOwnerINLINE());
  23286. if( AI_getGroupflag() != GROUPFLAG_NONE)
  23287. {
  23288. return;
  23289. }
  23290. //Don't Choose a Groupflag if we haven't already built a city
  23291. if (kPlayer.getNumCities() == 0)
  23292. {
  23293. return;
  23294. }
  23295. if (isInvisibleFromPromotion())
  23296. {
  23297. return;
  23298. }
  23299. if (getDuration() > 0)
  23300. {
  23301. AI_setGroupflag(GROUPFLAG_SUICIDE_SUMMON);
  23302. return;
  23303. }
  23304. if (isHiddenNationality())
  23305. {
  23306. AI_setGroupflag(GROUPFLAG_HNGROUP);
  23307. return;
  23308. }
  23309. bool bWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
  23310. switch (AI_getUnitAIType())
  23311. {
  23312. case UNITAI_MAGE:
  23313. AI_setGroupflag(GROUPFLAG_PERMDEFENSE);
  23314. return;
  23315. break;
  23316. case UNITAI_HERO:
  23317. AI_setGroupflag(GROUPFLAG_HERO);
  23318. return;
  23319. break;
  23320. case UNITAI_WARWIZARD:
  23321. AI_setGroupflag(GROUPFLAG_CONQUEST);
  23322. return;
  23323. break;
  23324. case UNITAI_CITY_DEFENSE:
  23325. case UNITAI_CITY_COUNTER:
  23326. AI_setGroupflag(GROUPFLAG_PERMDEFENSE);
  23327. return;
  23328. break;
  23329. case UNITAI_ATTACK_CITY:
  23330. case UNITAI_COUNTER:
  23331. AI_setGroupflag(GROUPFLAG_CONQUEST);
  23332. return;
  23333. break;
  23334. case UNITAI_ATTACK:
  23335. AI_setGroupflag(GROUPFLAG_PATROL);
  23336. return;
  23337. break;
  23338. default:
  23339. break;
  23340. }
  23341. //Svartalfar Kidnap
  23342. // ToDo - better code for this
  23343. CivilizationTypes iSvartal=(CivilizationTypes)GC.getInfoTypeForString("CIVILIZATION_SVARTALFAR");
  23344. if (iSvartal != NO_CIVILIZATION && getCivilizationType() == iSvartal)
  23345. {
  23346. UnitTypes iHunter = (UnitTypes)GC.getInfoTypeForString("UNIT_HUNTER");
  23347. if(iHunter != NO_UNIT && getUnitType() == iHunter)
  23348. {
  23349. if(kPlayer.countGroupFlagUnits(GROUPFLAG_SVARTALFAR_KIDNAP) == 0)
  23350. {
  23351. AI_setGroupflag(GROUPFLAG_SVARTALFAR_KIDNAP);
  23352. return;
  23353. }
  23354. }
  23355. }
  23356. if ((GET_TEAM(getTeam()).getAtWarCount(true) > 0)
  23357. || bWarPlan
  23358. || (bombardRate() > 0)
  23359. || isRangedCollateral())
  23360. {
  23361. AI_setGroupflag(GROUPFLAG_CONQUEST);
  23362. if (AI_getUnitAIType() != UNITAI_MEDIC)
  23363. {
  23364. int iAttackCityCount = kPlayer.AI_totalAreaUnitAIs(plot()->area(), UNITAI_ATTACK_CITY);
  23365. int iAttackCount = kPlayer.AI_totalAreaUnitAIs(plot()->area(), UNITAI_ATTACK);
  23366. if ((iAttackCount * 2) > iAttackCityCount)
  23367. {
  23368. AI_setUnitAIType(UNITAI_ATTACK_CITY);
  23369. }
  23370. }
  23371. return;
  23372. }
  23373. bool bDanger = (kPlayer.AI_getAnyPlotDanger(plot(), 3, false));
  23374. if (bDanger)
  23375. {
  23376. AI_setGroupflag(GROUPFLAG_PATROL);
  23377. return;
  23378. }
  23379. if(isUnitAllowedPermDefense())
  23380. {
  23381. AI_setGroupflag(GROUPFLAG_PERMDEFENSE);
  23382. return;
  23383. }
  23384. getGroup()->pushMission(MISSION_SKIP);
  23385. return;
  23386. }
  23387. //Returns true if the Unit can be set to City Defense
  23388. bool CvUnitAI::isUnitAllowedPermDefense()
  23389. {
  23390. CvUnitInfo& kUnitInfo = GC.getUnitInfo(getUnitType());
  23391. if (getDomainType() != DOMAIN_LAND)
  23392. {
  23393. return false;
  23394. }
  23395. if (kUnitInfo.getCombat() > kUnitInfo.getCombatDefense())
  23396. {
  23397. return false;
  23398. }
  23399. if (getDuration()>0)
  23400. {
  23401. return false;
  23402. }
  23403. /*
  23404. if (isPermanentSummon())
  23405. {
  23406. return false;
  23407. }
  23408. */
  23409. if (noDefensiveBonus())
  23410. {
  23411. return false;
  23412. }
  23413. if (isHiddenNationality())
  23414. {
  23415. return false;
  23416. }
  23417. switch (AI_getUnitAIType())
  23418. {
  23419. case UNITAI_SETTLE:
  23420. case UNITAI_WORKER:
  23421. case UNITAI_HERO:
  23422. case UNITAI_TERRAFORMER:
  23423. case UNITAI_MANA_UPGRADE:
  23424. case UNITAI_WARWIZARD:
  23425. case UNITAI_MISSIONARY:
  23426. case UNITAI_ANIMAL:
  23427. case UNITAI_PROPHET:
  23428. case UNITAI_ARTIST:
  23429. case UNITAI_SCIENTIST:
  23430. case UNITAI_GENERAL:
  23431. case UNITAI_MERCHANT:
  23432. case UNITAI_ENGINEER:
  23433. case UNITAI_SETTLER_SEA:
  23434. case UNITAI_WORKER_SEA:
  23435. case UNITAI_ATTACK_SEA:
  23436. case UNITAI_RESERVE_SEA:
  23437. case UNITAI_ESCORT_SEA:
  23438. case UNITAI_ASSAULT_SEA:
  23439. case UNITAI_MISSIONARY_SEA:
  23440. case UNITAI_SPY_SEA:
  23441. case UNITAI_PIRATE_SEA:
  23442. case UNITAI_INQUISITOR:
  23443. case UNITAI_FEASTING:
  23444. return false;
  23445. break;
  23446. default:
  23447. break;
  23448. }
  23449. if (kUnitInfo.getTier() > 3)
  23450. return false;
  23451. return m_bAllowedPermDefense;
  23452. }
  23453. // Returns true if a mission was pushed...
  23454. bool CvUnitAI::AI_groupheal(int iDamagePercent, int iMaxPath)
  23455. {
  23456. PROFILE_FUNC();
  23457. CLLNode<IDInfo>* pEntityNode;
  23458. std::vector<CvUnit*> aeDamagedUnits;
  23459. CvSelectionGroup* pGroup;
  23460. CvUnit* pLoopUnit;
  23461. int iTotalDamage;
  23462. int iTotalHitpoints;
  23463. int iHurtUnitCount;
  23464. if (plot()->getFeatureType() != NO_FEATURE)
  23465. {
  23466. if (GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() != 0)
  23467. {
  23468. //Pass through
  23469. //(actively seeking a safe spot may result in unit getting stuck)
  23470. if (!plot()->isCity() && AI_retreatToCity(false,false,1))
  23471. {
  23472. return true;
  23473. }
  23474. return false;
  23475. }
  23476. }
  23477. //FfH: Added by Kael 10/01/2007 (so the AI won't try to sit and heal in areas where they cant heal)
  23478. if (healRate(plot()) <= 0)
  23479. {
  23480. if (!plot()->isCity() && AI_retreatToCity(false,false,1))
  23481. {
  23482. return true;
  23483. }
  23484. return false;
  23485. }
  23486. //FfH: End Add
  23487. pGroup = getGroup();
  23488. if (iDamagePercent == 0)
  23489. {
  23490. iDamagePercent = 10;
  23491. }
  23492. iMaxPath = std::min(iMaxPath, 1);
  23493. pEntityNode = getGroup()->headUnitNode();
  23494. iTotalDamage = 0;
  23495. iTotalHitpoints = 0;
  23496. iHurtUnitCount = 0;
  23497. while (pEntityNode != NULL)
  23498. {
  23499. pLoopUnit = ::getUnit(pEntityNode->m_data);
  23500. FAssert(pLoopUnit != NULL);
  23501. pEntityNode = pGroup->nextUnitNode(pEntityNode);
  23502. int iDamageThreshold = (pLoopUnit->maxHitPoints() * iDamagePercent) / 100;
  23503. if (pLoopUnit->getDamage() > iDamageThreshold)
  23504. {
  23505. iHurtUnitCount++;
  23506. }
  23507. iTotalDamage += pLoopUnit->getDamage();
  23508. iTotalHitpoints += pLoopUnit->maxHitPoints();
  23509. }
  23510. if (iHurtUnitCount*3>pGroup->getNumUnits())
  23511. {
  23512. if (!plot()->isCity() && AI_retreatToCity(false,false,1))
  23513. {
  23514. return true;
  23515. }
  23516. if(canHeal(plot()))
  23517. {
  23518. pGroup->pushMission(MISSION_HEAL);
  23519. return true;
  23520. }
  23521. }
  23522. return false;
  23523. }
  23524. void CvUnitAI::AI_feastingmove()
  23525. {
  23526. if( gUnitLogLevel >= 2 )
  23527. {
  23528. logBBAI(" %S (unit %d) starting feastingMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
  23529. }
  23530. FAssertMsg(isVampire(), "Feasters are expected to be Vampires");
  23531. CvCity* pCity = plot()->getPlotCity();
  23532. CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
  23533. // Tholal ToDo: move this into python? - Hardcode
  23534. if ((pCity != NULL) && !isHasCasted())
  23535. {
  23536. if (pCity->angryPopulation() > 0 || pCity->unhealthyPopulation(false) > 1)
  23537. {
  23538. if (pCity->getPopulation() > 9 || pCity->foodDifference() < 0)
  23539. {
  23540. if (canCast(GC.getDefineINT("SPELL_FEAST"),false))
  23541. {
  23542. cast(GC.getDefineINT("SPELL_FEAST"));
  23543. }
  23544. //getGroup()->pushMission(MISSION_SKIP);
  23545. //return;
  23546. if( gUnitLogLevel > 2 ) logBBAI(" ...Unit %S (%d) making opportunistic feast at %S", getName().GetCString(), getID(), pCity->getName().GetCString());
  23547. }
  23548. }
  23549. }
  23550. /*
  23551. if (!isVampire() || !isAlive())
  23552. {
  23553. //TODO - change this to a choose groupflag call then return
  23554. if (AI_getUnitAIType() == UNITAI_FEASTING)
  23555. {
  23556. AI_setGroupflag(GROUPFLAG_CONQUEST);
  23557. AI_setUnitAIType(UNITAI_ATTACK_CITY);
  23558. getGroup()->pushMission(MISSION_SKIP);
  23559. }
  23560. return;
  23561. }
  23562. */
  23563. // TODO: Change this to Feast odds - higher if in peactime, more angry/unhealthy, larger cities
  23564. int iNeededFeasters = std::max(1,(kPlayer.getNumCities() / 3));
  23565. if (AI_getGroupflag() == GROUPFLAG_CONQUEST || AI_getGroupflag() == GROUPFLAG_PATROL)
  23566. {
  23567. if (kPlayer.AI_totalUnitAIs(UNITAI_FEASTING) < iNeededFeasters)
  23568. {
  23569. if ((getLevel() < 6) && (AI_getUnitAIType() != UNITAI_HERO))
  23570. {
  23571. //joinGroup(NULL);
  23572. AI_setGroupflag(GROUPFLAG_NONE);
  23573. AI_setUnitAIType(UNITAI_FEASTING);
  23574. //getGroup()->pushMission(MISSION_SKIP);
  23575. }
  23576. }
  23577. }
  23578. if (AI_getUnitAIType() == UNITAI_FEASTING)
  23579. {
  23580. // High-level Feasters should head into combat
  23581. // TODO - check for warplans
  23582. if (getLevel() > 8)
  23583. {
  23584. AI_setGroupflag(GROUPFLAG_CONQUEST);
  23585. AI_setUnitAIType(UNITAI_ATTACK_CITY);
  23586. getGroup()->pushMission(MISSION_SKIP);
  23587. return;
  23588. }
  23589. else
  23590. {
  23591. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  23592. CvCity* pLoopCity;
  23593. CvCity* pBestCity;
  23594. CvPlot* pBestPlot;
  23595. int iValue;
  23596. int iBestValue;
  23597. int iLoop;
  23598. int iPathTurns;
  23599. iBestValue = 0;
  23600. pBestCity = NULL;
  23601. iValue = 0;
  23602. // Feasters should work alone
  23603. if (getGroup()->getNumUnits() > 1)
  23604. {
  23605. joinGroup(NULL);
  23606. }
  23607. for (pLoopCity = kPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kPlayer.nextCity(&iLoop))
  23608. {
  23609. if (pLoopCity->getPopulation() > 3)
  23610. {
  23611. if (pLoopCity->angryPopulation() > 0 || pLoopCity->unhealthyPopulation() > 2 )
  23612. {
  23613. if( generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns) )
  23614. {
  23615. iValue += pLoopCity->getPopulation() * 2;
  23616. iValue += pLoopCity->angryPopulation() * 10;
  23617. iValue += pLoopCity->unhealthyPopulation() * 2;
  23618. iValue += -(pLoopCity->foodDifference() * 5);
  23619. iValue -= getLevel();
  23620. iValue -= iPathTurns * 4;
  23621. iValue = std::max(0, iValue);
  23622. if (iValue > iBestValue)
  23623. {
  23624. iBestValue = iValue;
  23625. pBestCity = pLoopCity;
  23626. }
  23627. }
  23628. }
  23629. }
  23630. }
  23631. if (pBestCity != NULL)
  23632. {
  23633. pBestPlot = pBestCity->plot();
  23634. if (pBestPlot != NULL)
  23635. {
  23636. if (atPlot(pBestPlot))
  23637. {
  23638. if (canCast(GC.getDefineINT("SPELL_FEAST"),false))
  23639. {
  23640. cast(GC.getDefineINT("SPELL_FEAST"));
  23641. }
  23642. getGroup()->pushMission(MISSION_SKIP);
  23643. return;
  23644. }
  23645. else
  23646. {
  23647. if( gUnitLogLevel > 2 ) logBBAI(" ....moving to %d, %d to Feast", pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  23648. FAssert(!atPlot(pBestPlot));
  23649. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
  23650. return;
  23651. }
  23652. }
  23653. }
  23654. else
  23655. {
  23656. if (AI_anyAttack(2, 80))
  23657. {
  23658. return;
  23659. }
  23660. if (!plot()->isCity())
  23661. {
  23662. if (AI_guardCity())
  23663. {
  23664. return;
  23665. }
  23666. if (AI_retreatToCity())
  23667. {
  23668. return;
  23669. }
  23670. }
  23671. else
  23672. {
  23673. AI_setGroupflag(GROUPFLAG_CONQUEST);
  23674. AI_setUnitAIType(UNITAI_ATTACK_CITY);
  23675. getGroup()->pushMission(MISSION_SKIP);
  23676. return;
  23677. }
  23678. }
  23679. }
  23680. }
  23681. getGroup()->pushMission(MISSION_SKIP);
  23682. return;
  23683. }
  23684. void CvUnitAI::AI_PatrolMove()
  23685. {
  23686. bool bFollow=false;
  23687. int iMinStack=1;
  23688. int iBestValue=-1;
  23689. CvPlot* pBestPlot=NULL;
  23690. bool bAtWar = (GET_TEAM(getTeam()).getAtWarCount(true) > 0);
  23691. bool bHero = false;
  23692. bool bWizard = false;
  23693. switch (AI_getUnitAIType())
  23694. {
  23695. case UNITAI_HERO:
  23696. bHero = true;
  23697. break;
  23698. case UNITAI_WARWIZARD:
  23699. bWizard = true;
  23700. break;
  23701. default:
  23702. break;
  23703. }
  23704. bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
  23705. bool bAnyWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
  23706. bool bFinancialTrouble = GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble();
  23707. bool bInCity = plot()->isCity();
  23708. if( gUnitLogLevel >= 2 )
  23709. {
  23710. logBBAI(" Stack %d (led by %S (%d), size %d) starting PatrolMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  23711. }
  23712. // lfgr 05/2020: Slightly hacky, to ensure the first/only remaining city is defended no matter what.
  23713. if( GET_PLAYER( getOwnerINLINE() ).getNumCities() == 1 ) {
  23714. if( AI_guardCityMinDefender( true ) ) { // Search for the city
  23715. if( gUnitLogLevel >= 3 ) {logBBAI( " ... defends the only, (otherwise) undefended city!" );}
  23716. return;
  23717. }
  23718. }
  23719. // Heroes and Casters should seek larger groups
  23720. if (bHero || bWizard)
  23721. {
  23722. if (bAtWar || bAnyWarPlan)
  23723. {
  23724. AI_setGroupflag(GROUPFLAG_CONQUEST);
  23725. }
  23726. if (getGroup()->getNumUnits() < ((getLevel() / 2) +1))
  23727. {
  23728. /*
  23729. if (AI_groupMergeRange(UNITAI_ATTACK, 10, false, true, false))
  23730. {
  23731. return;
  23732. }
  23733. */
  23734. if (AI_group(UNITAI_ATTACK))
  23735. {
  23736. if( gUnitLogLevel >= 3 ) {logBBAI( " ... hero/caster group with attack stack" );}
  23737. return;
  23738. }
  23739. if (AI_moveToStagingCity())
  23740. {
  23741. if( gUnitLogLevel >= 3 ) {logBBAI( " ... hero/caster moving to staging city" );}
  23742. return;
  23743. }
  23744. }
  23745. }
  23746. if( getGroup()->getNumUnits() > 5 || bFinancialTrouble)
  23747. {
  23748. if (bAnyWarPlan)
  23749. {
  23750. if (getGroup()->getNumUnits() > ((GET_PLAYER(getOwnerINLINE()).getNumCities() + 1) * 3))
  23751. {
  23752. if( gUnitLogLevel >= 3 ) {logBBAI(" ...switching to GROUPFLAG_CONQUEST");}
  23753. AI_setGroupflag(GROUPFLAG_CONQUEST);
  23754. return;
  23755. }
  23756. }
  23757. if (bAtWar)
  23758. {
  23759. UnitAITypes eGroupAI = getGroup()->getHeadUnitAI();
  23760. if( eGroupAI == AI_getUnitAIType() )
  23761. {
  23762. if( plot()->getOwnerINLINE() == getOwnerINLINE() && !bDanger )
  23763. {
  23764. // Should never have attack city group lead by attack unit
  23765. if( getGroup()->countNumUnitAIType(UNITAI_ATTACK_CITY) > 0 )
  23766. {
  23767. getGroup()->AI_separateAI(UNITAI_ATTACK_CITY); // will change group
  23768. // Since ATTACK can try to join ATTACK_CITY again, need these units to
  23769. // take a break to let ATTACK_CITY group move and avoid hang
  23770. getGroup()->pushMission(MISSION_SKIP);
  23771. return;
  23772. }
  23773. }
  23774. }
  23775. }
  23776. }
  23777. if( AI_guardFortMinDefender() ) {
  23778. if( gUnitLogLevel >= 3 ) {logBBAI( " ... guard fort on same plot" );}
  23779. return;
  23780. }
  23781. // Jobs for small patrols
  23782. if (getGroup()->getNumUnits() <= 3)// && !bAtWar)
  23783. {
  23784. if( gUnitLogLevel >= 3 ) logBBAI(" ...checking small group options");
  23785. if (plot()->getOwnerINLINE() != getOwnerINLINE())
  23786. {
  23787. //if( gUnitLogLevel >= 3 ) logBBAI(" ...looking for Settlers to group with");
  23788. if (AI_group(UNITAI_SETTLE, 5, -1, -1, false, false, false, 0, true))
  23789. {
  23790. if( gUnitLogLevel >= 3 ) logBBAI(" ...grouping with Settler in foreign territory");
  23791. return;
  23792. }
  23793. }
  23794. if (AI_cityAttack(1, 75))
  23795. {
  23796. if( gUnitLogLevel >= 3 ) logBBAI(" ...opportunistic city attack");
  23797. return;
  23798. }
  23799. if (AI_pickupEquipment(3))
  23800. {
  23801. if( gUnitLogLevel >= 3 ) logBBAI(" ...picking up equipment");
  23802. return;
  23803. }
  23804. if (AI_anyAttack(1, (bInCity ? 60 : 80)))
  23805. {
  23806. return;
  23807. }
  23808. if (!bDanger)
  23809. {
  23810. int iAttackRange = ((plot()->getOwner() == getOwner()) ? 3: 2);
  23811. if (AI_anyAttack(iAttackRange,90))
  23812. {
  23813. return;
  23814. }
  23815. }
  23816. if (AI_exploreLair(1))
  23817. {
  23818. return;
  23819. }
  23820. if (AI_exploreLairSea(1))
  23821. {
  23822. return;
  23823. }
  23824. }
  23825. if (!bHero)
  23826. {
  23827. if ((GET_TEAM(getTeam()).getAtWarCount(false) == 0) || (!bDanger || !bInCity))
  23828. {
  23829. if (AI_group(UNITAI_SETTLE, 3, -1, -1, false, false, false, 3, false))
  23830. {
  23831. return;
  23832. }
  23833. }
  23834. }
  23835. if (AI_groupMergeRange(UNITAI_HERO, 0, true, true))
  23836. {
  23837. if( gUnitLogLevel >= 3 ) logBBAI(" ...merging with UNITAI_HERO");
  23838. getGroup()->pushMission(MISSION_SKIP);
  23839. return;
  23840. }
  23841. if (AI_groupMergeRange(UNITAI_ATTACK, 0, true, true))
  23842. {
  23843. if( gUnitLogLevel >= 3 ) logBBAI(" ...merging with UNITAI_ATTACK");
  23844. getGroup()->pushMission(MISSION_SKIP);
  23845. return;
  23846. }
  23847. // this should be in the AI_guardcity function
  23848. if (plot()->isCity() && plot()->getOwner() == getOwner() && bDanger)
  23849. {
  23850. if (plot()->getPlotCity()->AI_neededDefenders() >= plot()->getNumDefenders(getOwnerINLINE()))
  23851. {
  23852. logBBAI(" ...staying to guard city");
  23853. getGroup()->pushMission(MISSION_SKIP);
  23854. return;
  23855. }
  23856. }
  23857. // Attack choking units
  23858. if( plot()->getOwnerINLINE() == getOwnerINLINE() && bDanger )
  23859. {
  23860. int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
  23861. int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
  23862. if( iOurDefense < 3*iEnemyOffense )
  23863. {
  23864. if (AI_guardCity(true))
  23865. {
  23866. if( gUnitLogLevel > 3 ) logBBAI(" ...guarding city");
  23867. return;
  23868. }
  23869. }
  23870. if( iOurDefense > 2*iEnemyOffense )
  23871. {
  23872. if (AI_anyAttack(2, 55))
  23873. {
  23874. return;
  23875. }
  23876. }
  23877. if (AI_groupMergeRange(UNITAI_ATTACK, 2, true, true, false))
  23878. {
  23879. return;
  23880. }
  23881. /*
  23882. if( iOurDefense > 2*iEnemyOffense )
  23883. {
  23884. if (AI_anyAttack(2, 30))
  23885. {
  23886. return;
  23887. }
  23888. }
  23889. */
  23890. }
  23891. // Guard a city we're in if it needs it
  23892. if (AI_guardCity(true))
  23893. {
  23894. if( gUnitLogLevel > 3 ) logBBAI(" ...Patrol - Guard City 1");
  23895. return;
  23896. }
  23897. if (GC.getLeaderHeadInfo(GET_PLAYER(getOwnerINLINE()).getPersonalityType()).getMaxWarRand() < 75)
  23898. {
  23899. if (AI_poach())
  23900. {
  23901. if( gUnitLogLevel > 3 ) logBBAI(" ...poaching");
  23902. return;
  23903. }
  23904. }
  23905. if( !(plot()->isOwned()) )
  23906. {
  23907. // Group with settler after naval drop
  23908. if( AI_groupMergeRange(UNITAI_SETTLE, 2, true, false, false) )
  23909. {
  23910. return;
  23911. }
  23912. }
  23913. if( !(plot()->isOwned()) || (plot()->getOwnerINLINE() == getOwnerINLINE()) )
  23914. {
  23915. if( area()->getCitiesPerPlayer(getOwnerINLINE()) > GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(area(), UNITAI_CITY_DEFENSE) )
  23916. {
  23917. // Defend colonies in new world
  23918. if (AI_guardCity(true, true, 3))
  23919. {
  23920. return;
  23921. }
  23922. }
  23923. }
  23924. if (AI_heal(30, 1))
  23925. {
  23926. if( gUnitLogLevel > 3 ) logBBAI(" ...healing");
  23927. return;
  23928. }
  23929. if (AI_stackAttackCity(3, 140))
  23930. {
  23931. logBBAI(" ...Stack Attack City");
  23932. return;
  23933. }
  23934. if (!bDanger && !bHero && !bAtWar)
  23935. {
  23936. if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 3, true))
  23937. {
  23938. return;
  23939. }
  23940. if (AI_group(UNITAI_SETTLE, 4, -1, -1, false, false, false, 3, true))
  23941. {
  23942. return;
  23943. }
  23944. }
  23945. if( AI_guardFortMinDefender( true ) ) {
  23946. if( gUnitLogLevel >= 3 ) {logBBAI( " ... guarding undefended fort" );}
  23947. return;
  23948. }
  23949. if (AI_guardCityAirlift())
  23950. {
  23951. return;
  23952. }
  23953. if (AI_guardCity(false, true, 1))
  23954. {
  23955. return;
  23956. }
  23957. //join any city attacks in progress
  23958. if (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE())
  23959. {
  23960. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
  23961. {
  23962. return;
  23963. }
  23964. }
  23965. AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
  23966. if (plot()->isCity())
  23967. {
  23968. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  23969. {
  23970. if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
  23971. {
  23972. if (AI_offensiveAirlift())
  23973. {
  23974. return;
  23975. }
  23976. }
  23977. }
  23978. }
  23979. if (bDanger)
  23980. {
  23981. if (AI_cityAttack(1, 65))
  23982. {
  23983. return;
  23984. }
  23985. if (AI_anyAttack(1, 65))
  23986. {
  23987. return;
  23988. }
  23989. if (collateralDamage() > 0 || getUnitInfo().isExplodeInCombat())
  23990. {
  23991. if (AI_anyAttack(1, 45, 3))
  23992. {
  23993. return;
  23994. }
  23995. }
  23996. }
  23997. if (AI_pickupEquipment(3))
  23998. {
  23999. return;
  24000. }
  24001. if (!isHuman())
  24002. {
  24003. if (AI_exploreLair(6))
  24004. {
  24005. return;
  24006. }
  24007. }
  24008. if (!noDefensiveBonus())
  24009. {
  24010. if (AI_guardCity(false, false))
  24011. {
  24012. return;
  24013. }
  24014. }
  24015. if (!bDanger)
  24016. {
  24017. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  24018. {
  24019. bool bAssault = ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_MASSING) || (eAreaAIType == AREAAI_ASSAULT_ASSIST));
  24020. if ( bAssault )
  24021. {
  24022. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  24023. {
  24024. return;
  24025. }
  24026. }
  24027. if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, -1, 1, MOVE_SAFE_TERRITORY, 3))
  24028. {
  24029. return;
  24030. }
  24031. bool bLandWar = GET_PLAYER(getOwnerINLINE()).AI_isLandWar(area());
  24032. if (!bLandWar)
  24033. {
  24034. // Fill transports before starting new one, but not just full of our unit ai
  24035. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
  24036. {
  24037. return;
  24038. }
  24039. // Pick new transport which has space for other unit ai types to join
  24040. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, 2, -1, -1, MOVE_SAFE_TERRITORY, 4))
  24041. {
  24042. return;
  24043. }
  24044. }
  24045. if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) > 0)
  24046. {
  24047. getGroup()->pushMission(MISSION_SKIP);
  24048. return;
  24049. }
  24050. }
  24051. }
  24052. // Allow larger groups if outside territory
  24053. if( getGroup()->getNumUnits() < 5 )
  24054. {
  24055. if( plot()->isOwned() && GET_TEAM(getTeam()).isAtWar(plot()->getTeam()) )
  24056. {
  24057. if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, true))
  24058. {
  24059. return;
  24060. }
  24061. }
  24062. }
  24063. if (AI_goody(3))
  24064. {
  24065. return;
  24066. }
  24067. if (AI_anyAttack(1, 70))
  24068. {
  24069. return;
  24070. }
  24071. if (bDanger)
  24072. {
  24073. if (AI_pillageRange(1, 20))
  24074. {
  24075. return;
  24076. }
  24077. if (AI_cityAttack(1, 55))
  24078. {
  24079. return;
  24080. }
  24081. if (AI_anyAttack(1, 55))
  24082. {
  24083. return;
  24084. }
  24085. if (AI_pillageRange(3, 20))
  24086. {
  24087. return;
  24088. }
  24089. if( getGroup()->getNumUnits() < 4 )
  24090. {
  24091. if (AI_choke(1))
  24092. {
  24093. return;
  24094. }
  24095. if (AI_groupMergeRange(UNITAI_ATTACK, 2, true, true, true))
  24096. {
  24097. return;
  24098. }
  24099. }
  24100. if (AI_cityAttack(4, 80))
  24101. {
  24102. return;
  24103. }
  24104. if (AI_anyAttack(2, 60))
  24105. {
  24106. return;
  24107. }
  24108. }
  24109. if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
  24110. {
  24111. if (AI_heal())
  24112. {
  24113. return;
  24114. }
  24115. }
  24116. if (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
  24117. {
  24118. if (getGroup()->getNumUnits() > 1)
  24119. {
  24120. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12))
  24121. {
  24122. return;
  24123. }
  24124. }
  24125. }
  24126. else if( area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE )
  24127. {
  24128. if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0)
  24129. {
  24130. //if (getGroup()->getNumUnits() >= GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getBarbarianInitialDefenders())
  24131. if (getGroup()->getNumUnits() >= 5)
  24132. {
  24133. if (AI_goToTargetBarbCity(10))
  24134. {
  24135. return;
  24136. }
  24137. }
  24138. }
  24139. }
  24140. if (AI_guardCity(false, true, 3))
  24141. {
  24142. return;
  24143. }
  24144. if (AI_protect(35, 5))
  24145. {
  24146. return;
  24147. }
  24148. if (AI_offensiveAirlift())
  24149. {
  24150. return;
  24151. }
  24152. if (!bDanger && (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE))
  24153. {
  24154. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  24155. {
  24156. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
  24157. {
  24158. return;
  24159. }
  24160. if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) && !(getGroup()->isHasPathToAreaEnemyCity(false)) )
  24161. {
  24162. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  24163. {
  24164. return;
  24165. }
  24166. }
  24167. }
  24168. }
  24169. if (AI_defend())
  24170. {
  24171. if( gUnitLogLevel > 3 ) logBBAI(" ...AI_defend");
  24172. return;
  24173. }
  24174. if (AI_travelToUpgradeCity())
  24175. {
  24176. if( gUnitLogLevel > 3 ) logBBAI(" ...travelling to upgrade city");
  24177. return;
  24178. }
  24179. if( getGroup()->isStranded() )
  24180. {
  24181. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  24182. {
  24183. if( gUnitLogLevel > 3 ) logBBAI(" ...loading on ship due to Stranded status");
  24184. return;
  24185. }
  24186. }
  24187. if( !bDanger && !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
  24188. {
  24189. // If no other desireable actions, wait for pickup
  24190. if( gUnitLogLevel > 3 ) logBBAI(" ...waiting for pickup");
  24191. getGroup()->pushMission(MISSION_SKIP);
  24192. return;
  24193. }
  24194. // switch to Conquest if we're at war and can't find anything to do
  24195. if (getGroup()->getNumUnits() == 1)
  24196. {
  24197. if (bAtWar || bAnyWarPlan)
  24198. {
  24199. AI_setGroupflag(GROUPFLAG_CONQUEST);
  24200. if( gUnitLogLevel > 3 ) logBBAI(" ...switching to GROUPFLAG_CONQUEST");
  24201. //AI_setUnitAIType(UNITAI_ATTACK_CITY);
  24202. return;
  24203. }
  24204. if (AI_group(UNITAI_ATTACK, 5))
  24205. {
  24206. return;
  24207. }
  24208. }
  24209. if( getGroup()->getNumUnits() < 4 )
  24210. {
  24211. if (AI_patrol())
  24212. {
  24213. if( gUnitLogLevel > 3 ) logBBAI(" ...patrolling");
  24214. return;
  24215. }
  24216. }
  24217. if (AI_retreatToCity())
  24218. {
  24219. return;
  24220. }
  24221. if (AI_safety())
  24222. {
  24223. return;
  24224. }
  24225. if( gUnitLogLevel > 3 ) logBBAI(" ...ERROR? NOTHING TO DO!");
  24226. getGroup()->pushMission(MISSION_SKIP);
  24227. return;
  24228. }
  24229. void CvUnitAI::AI_HiddenNationalityMove()
  24230. {
  24231. if( gUnitLogLevel >= 2 )
  24232. {
  24233. logBBAI(" Stack %d (led by %S (%d), size %d) starting HiddenNationalityMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  24234. }
  24235. if (!isHiddenNationality())
  24236. {
  24237. AI_setGroupflag(GROUPFLAG_NONE);
  24238. return;
  24239. }
  24240. /*
  24241. if (isAnimal())
  24242. {
  24243. if (!isInvisible(getTeam(), false))
  24244. {
  24245. setHasPromotion((PromotionTypes)GC.getDefineINT("HIDDEN_NATIONALITY_PROMOTION"), false);
  24246. return;
  24247. }
  24248. }
  24249. */
  24250. if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL"))
  24251. {
  24252. if (AI_getUnitAIType() != UNITAI_PIRATE_SEA)
  24253. {
  24254. AI_setUnitAIType(UNITAI_PIRATE_SEA);
  24255. }
  24256. AI_pirateSeaMove();
  24257. return;
  24258. }
  24259. else
  24260. {
  24261. AI_attackMove();
  24262. return;
  24263. }
  24264. getGroup()->pushMission(MISSION_SKIP);
  24265. return;
  24266. }
  24267. // look around for sea lairs to explore
  24268. bool CvUnitAI::AI_exploreLairSea(int iRange)
  24269. {
  24270. if (GET_TEAM(getTeam()).isBarbarianAlly())
  24271. {
  24272. return false;
  24273. }
  24274. int iValue = 0;
  24275. int iBestValue = 0;
  24276. int iPathTurns;
  24277. CvCity* pNearestCity;
  24278. CvPlot* pBestPlot = NULL;
  24279. for (int iX = -iRange; iX <= iRange; iX++)
  24280. {
  24281. for (int iY = -iRange; iY <= iRange; iY++)
  24282. {
  24283. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
  24284. if (pLoopPlot != NULL)
  24285. {
  24286. if (pLoopPlot->isWater())
  24287. {
  24288. if ( pLoopPlot->isRevealed(getTeam(), false) || pLoopPlot->isAdjacentRevealed(getTeam()) )
  24289. {
  24290. if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT)
  24291. {
  24292. if ((GC.getImprovementInfo((ImprovementTypes)pLoopPlot->getImprovementType()).isExploreTarget()))
  24293. {
  24294. if (!pLoopPlot->isVisibleEnemyDefender(this))
  24295. {
  24296. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  24297. {
  24298. if (iPathTurns <= iRange)
  24299. {
  24300. iValue = 20 + getLevel();
  24301. iValue /= (iPathTurns + 1);
  24302. if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).isUnique())
  24303. {
  24304. // Tholal ToDo - make this less hardcoded and scale by game speed
  24305. if (GC.getGameINLINE().getElapsedGameTurns() > ((20 * 100) / GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAITrainPercent()))
  24306. {
  24307. iValue += 2 * getLevel();
  24308. }
  24309. if (pLoopPlot->isOwned())
  24310. {
  24311. // cant explore unique lairs in other player's territory
  24312. if (pLoopPlot->getOwner() != getOwner())
  24313. {
  24314. iValue = 0;
  24315. }
  24316. // dont explore lairs in our territory that offer up free bonuses
  24317. // TODO - allow exploration after we have the tech and units to build the proper improvement
  24318. else if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).getBonusConvert() != NO_BONUS)
  24319. {
  24320. iValue = 0;
  24321. }
  24322. }
  24323. }
  24324. pNearestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
  24325. if (pNearestCity != NULL)
  24326. {
  24327. // avoid opening lairs near our team if they are lightly defended or its early in the game
  24328. if (pNearestCity->getTeam() == getTeam())
  24329. {
  24330. if (!pNearestCity->AI_isDefended() || (GET_PLAYER(getOwnerINLINE()).getNumCities() == 1))
  24331. {
  24332. iValue = 0;
  24333. }
  24334. }
  24335. }
  24336. if (iValue > iBestValue)
  24337. {
  24338. pBestPlot = pLoopPlot;
  24339. }
  24340. }
  24341. }
  24342. }
  24343. }
  24344. }
  24345. }
  24346. }
  24347. }
  24348. }
  24349. }
  24350. if (pBestPlot != NULL)
  24351. {
  24352. if (atPlot(pBestPlot))
  24353. {
  24354. int ispell = chooseSpell();
  24355. if (ispell != NO_SPELL)
  24356. {
  24357. cast(ispell);
  24358. }
  24359. getGroup()->pushMission(MISSION_SKIP);
  24360. return true;
  24361. }
  24362. else
  24363. {
  24364. if( gUnitLogLevel > 2 ) logBBAI(" ....moving to %d, %d to explore Sea Lair", pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  24365. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_2);
  24366. return true;
  24367. }
  24368. }
  24369. return false;
  24370. }
  24371. // look around for lairs to explore
  24372. bool CvUnitAI::AI_exploreLair(int iRange)
  24373. {
  24374. if (GET_TEAM(getTeam()).isBarbarianAlly())
  24375. {
  24376. return false;
  24377. }
  24378. if (GET_PLAYER(getOwnerINLINE()).getNumCities() == 0)
  24379. {
  24380. return false;
  24381. }
  24382. int iValue = 0;
  24383. int iBestValue = 0;
  24384. int iPathTurns;
  24385. CvCity* pNearestCity;
  24386. CvPlot* pBestPlot = NULL;
  24387. for (int iX = -iRange; iX <= iRange; iX++)
  24388. {
  24389. for (int iY = -iRange; iY <= iRange; iY++)
  24390. {
  24391. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
  24392. if (pLoopPlot != NULL)
  24393. {
  24394. if ( pLoopPlot->isRevealed(getTeam(), false) || pLoopPlot->isAdjacentRevealed(getTeam()) )
  24395. {
  24396. if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT)
  24397. {
  24398. if ((GC.getImprovementInfo((ImprovementTypes)pLoopPlot->getImprovementType()).isExploreTarget()))
  24399. {
  24400. if (!pLoopPlot->isVisibleEnemyDefender(this))
  24401. {
  24402. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  24403. {
  24404. if (iPathTurns <= iRange)
  24405. {
  24406. iValue = 20 + getLevel();
  24407. iValue /= (iPathTurns + 1);
  24408. if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).isUnique())
  24409. {
  24410. // Tholal ToDo - make this less hardcoded and scale by game speed
  24411. if (GC.getGameINLINE().getElapsedGameTurns() > ((20 * 100) / GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAITrainPercent()))
  24412. {
  24413. iValue += 2 * getLevel();
  24414. }
  24415. if (pLoopPlot->isOwned())
  24416. {
  24417. // cant explore unique lairs in other player's territory
  24418. if (pLoopPlot->getOwner() != getOwner())
  24419. {
  24420. iValue = 0;
  24421. }
  24422. // dont explore lairs in our territory that offer up free bonuses
  24423. // TODO - allow exploration after we have the tech and units to build the proper improvement
  24424. else if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).getBonusConvert() != NO_BONUS)
  24425. {
  24426. iValue = 0;
  24427. }
  24428. }
  24429. }
  24430. pNearestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
  24431. if (pNearestCity != NULL)
  24432. {
  24433. // avoid opening lairs near our team if they are lightly defended or its early in the game
  24434. if (pNearestCity->getTeam() == getTeam())
  24435. {
  24436. if (!pNearestCity->AI_isDefended() || (GET_PLAYER(getOwnerINLINE()).getNumCities() == 1))
  24437. {
  24438. iValue = 0;
  24439. }
  24440. }
  24441. }
  24442. if (iValue > iBestValue)
  24443. {
  24444. pBestPlot = pLoopPlot;
  24445. }
  24446. }
  24447. }
  24448. }
  24449. }
  24450. }
  24451. }
  24452. }
  24453. }
  24454. }
  24455. if (pBestPlot != NULL)
  24456. {
  24457. if (atPlot(pBestPlot))
  24458. {
  24459. int ispell = chooseSpell();
  24460. if (ispell != NO_SPELL)
  24461. {
  24462. cast(ispell);
  24463. }
  24464. getGroup()->pushMission(MISSION_SKIP);
  24465. return true;
  24466. }
  24467. else
  24468. {
  24469. if( gUnitLogLevel > 2 ) logBBAI(" ....moving to %d, %d to explore Lair", pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
  24470. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_2);
  24471. return true;
  24472. }
  24473. }
  24474. return false;
  24475. }
  24476. //Look around for equipment
  24477. bool CvUnitAI::AI_pickupEquipment(int iRange)
  24478. {
  24479. CvUnit* pLoopUnit;
  24480. CvUnit* pBestUnit = NULL;
  24481. CvPlot* pBestPlot;
  24482. int iValue = 0;
  24483. int iBestValue = iRange + 1;
  24484. int iLoop;
  24485. int iPathTurns;
  24486. CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
  24487. if (getMoves() > 1)
  24488. {
  24489. iRange ++;
  24490. }
  24491. // First, look for our equipment and treasure
  24492. for (pLoopUnit = kPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = kPlayer.nextUnit(&iLoop))
  24493. {
  24494. if (pLoopUnit->getUnitInfo().isObject())
  24495. {
  24496. if (generatePath(pLoopUnit->plot(), 0, true, &iPathTurns))
  24497. {
  24498. if (iPathTurns <= iRange)
  24499. {
  24500. iValue = iPathTurns;
  24501. if (iValue < iBestValue)
  24502. {
  24503. iBestValue = iValue;
  24504. pBestUnit = pLoopUnit;
  24505. }
  24506. }
  24507. }
  24508. }
  24509. }
  24510. if (pBestUnit != NULL)
  24511. {
  24512. if( gUnitLogLevel >= 3 )
  24513. {
  24514. logBBAI("Player %d Unit %d (%S's %S) picking up %S\n", getOwnerINLINE(), getID(), GET_PLAYER(getOwnerINLINE()).getName(), getName().GetCString(), pBestUnit->getName().GetCString());
  24515. }
  24516. pBestPlot = pBestUnit->plot();
  24517. if (atPlot(pBestPlot))
  24518. {
  24519. int ispell = chooseSpell();
  24520. if (ispell != NO_SPELL)
  24521. {
  24522. cast(ispell);
  24523. }
  24524. getGroup()->pushMission(MISSION_SKIP);
  24525. return true;
  24526. }
  24527. else
  24528. {
  24529. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_2);
  24530. return true;
  24531. }
  24532. }
  24533. // TODO - look for ENEMY equipment nearby
  24534. /*
  24535. CvPlot* pBestPlot = NULL;
  24536. for (int iX = -iRange; iX <= iRange; iX++)
  24537. {
  24538. for (int iY = -iRange; iY <= iRange; iY++)
  24539. {
  24540. CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
  24541. if (pLoopPlot != NULL)
  24542. {
  24543. if (pLoopPlot->isVisibleEnemy(GET_TEAM(getTeam())))
  24544. {
  24545. }
  24546. }
  24547. }
  24548. }
  24549. */
  24550. return false;
  24551. }
  24552. void CvUnitAI::AI_ConquestMove()
  24553. {
  24554. CvSelectionGroup* pLoopSelectionGroup;
  24555. CvUnit* pBestUnit;
  24556. CvPlot* pLoopPlot;
  24557. //CvPlot* pBestPlot;
  24558. int iPathTurns;
  24559. //int iDX, iDY;
  24560. int iLoop;
  24561. int iValue;
  24562. int iBestValue;
  24563. //int iSearchRange;
  24564. bool bFollow=false;
  24565. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  24566. AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
  24567. //bool bLandWar = !isBarbarian() && ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
  24568. bool bLandWar = !isBarbarian() && kPlayer.AI_isLandWar(area());
  24569. bool bAssault = !isBarbarian() && ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) || (eAreaAIType == AREAAI_ASSAULT_MASSING));
  24570. bool bTurtle = kPlayer.AI_isDoStrategy(AI_STRATEGY_TURTLE);
  24571. bool bAlert1 = kPlayer.AI_isDoStrategy(AI_STRATEGY_ALERT1);
  24572. bool bIgnoreFaster = false;
  24573. if( gUnitLogLevel >= 2 )
  24574. {
  24575. logBBAI(" Stack %d (led by %S (%d), size %d) starting ConquestMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
  24576. }
  24577. if (kPlayer.AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
  24578. {
  24579. if (!bAssault && area()->getCitiesPerPlayer(getOwnerINLINE()) > 0)
  24580. {
  24581. bIgnoreFaster = true;
  24582. }
  24583. }
  24584. bool bFinancialTrouble = kPlayer.AI_isFinancialTrouble();
  24585. //int bStackSize = getGroup()->getNumUnits();
  24586. //bool bLargeGroup = (bStackSize > (kPlayer.getNumCities() *6));
  24587. bool bHero = false;
  24588. bool bWizard = false;
  24589. switch (AI_getUnitAIType())
  24590. {
  24591. case UNITAI_HERO:
  24592. bHero = true;
  24593. break;
  24594. case UNITAI_WARWIZARD:
  24595. bWizard = true;
  24596. break;
  24597. case UNITAI_RESERVE:
  24598. AI_setUnitAIType(UNITAI_ATTACK_CITY);
  24599. break;
  24600. case UNITAI_ATTACK:
  24601. if ((getLevel() > 4)
  24602. || (kPlayer.AI_getNumAIUnits(UNITAI_ATTACK) > (kPlayer.getNumCities() * (bLandWar ? 2 : 4)))
  24603. || (kPlayer.AI_getNumAIUnits(UNITAI_ATTACK_CITY) < kPlayer.getNumCities()))
  24604. {
  24605. AI_setUnitAIType(UNITAI_ATTACK_CITY);
  24606. break;
  24607. }
  24608. default:
  24609. break;
  24610. }
  24611. if (isHiddenNationality() || isInvisibleFromPromotion())
  24612. {
  24613. if (!bHero && !bWizard)
  24614. {
  24615. AI_setGroupflag(GROUPFLAG_NONE);
  24616. joinGroup(NULL);
  24617. AI_setUnitAIType(UNITAI_ATTACK);
  24618. getGroup()->pushMission(MISSION_SKIP);
  24619. return;
  24620. }
  24621. }
  24622. if (AI_getGroupflag() != GROUPFLAG_CONQUEST)
  24623. {
  24624. AI_setGroupflag(GROUPFLAG_CONQUEST);
  24625. }
  24626. bool bInCity = plot()->isCity();
  24627. if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
  24628. {
  24629. if ((getGroup()->getNumUnits() == 1) && (getDamage() > 0))
  24630. {
  24631. if (AI_heal())
  24632. {
  24633. return;
  24634. }
  24635. }
  24636. if (AI_leaveAttack(1, 70, 175))
  24637. {
  24638. return;
  24639. }
  24640. if( bIgnoreFaster )
  24641. {
  24642. // BBAI TODO: split out slow units ... will need to test to make sure this doesn't cause loops
  24643. }
  24644. if (AI_guardCity(false)) // note. this will eject a unit to defend the city rather then using the whole group
  24645. {
  24646. if( gUnitLogLevel >= 3 ){logBBAI(" ...guarding city on plot");}
  24647. return;
  24648. }
  24649. if (bAssault)
  24650. {
  24651. if (AI_offensiveAirlift())
  24652. {
  24653. return;
  24654. }
  24655. }
  24656. }
  24657. // Opportunistic attacks
  24658. if (getGroup()->getNumUnits() == 1 && !bHero && !bWizard)
  24659. {
  24660. if (AI_anyAttack(1, 80))
  24661. {
  24662. return;
  24663. }
  24664. if (AI_anyAttack(2, 90))
  24665. {
  24666. return;
  24667. }
  24668. }
  24669. // Heroes and Casters should seek larger groups
  24670. if (bHero || bWizard)
  24671. {
  24672. //if (getGroup()->getNumUnits() < ((getLevel() / 2) +1))
  24673. {
  24674. if (AI_pickupEquipment(3))
  24675. {
  24676. return;
  24677. }
  24678. /*
  24679. int iRange = 0;
  24680. if (plot()->getOwner() == getOwner())
  24681. {
  24682. iRange = 5;
  24683. }
  24684. else
  24685. {
  24686. iRange = 10;
  24687. }
  24688. if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) == 0)
  24689. {
  24690. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, iRange, false, true, false))
  24691. {
  24692. return;
  24693. }
  24694. }
  24695. if (AI_moveToStagingCity())
  24696. {
  24697. return;
  24698. }
  24699. */
  24700. }
  24701. }
  24702. else // Mainly affects Clan and the units they get from their World Spell
  24703. {
  24704. if (getGroup()->isStranded() && (getLevel() < 3) && bFinancialTrouble)
  24705. {
  24706. logBBAI(" Killing %S (delayed) -- disbanded because stranded and financial trouble (Unit %d - plot: %d, %d)",
  24707. getName().GetCString(), getID(), getX(), getY());
  24708. kill(true);
  24709. return;
  24710. }
  24711. }
  24712. bool bHuntBarbs = false;
  24713. if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0 && !GET_TEAM(getTeam()).isBarbarianAlly())
  24714. {
  24715. if ((eAreaAIType != AREAAI_OFFENSIVE) && (eAreaAIType != AREAAI_DEFENSIVE) && !bAlert1 && !bTurtle)
  24716. {
  24717. bHuntBarbs = true;
  24718. }
  24719. }
  24720. bool bReadyToAttack = false;
  24721. if( !bTurtle )
  24722. {
  24723. bReadyToAttack = ((getGroup()->getNumUnits() >= ((bHuntBarbs) ? 3 : AI_stackOfDoomExtra())));
  24724. }
  24725. if (AI_guardCity(false, false))
  24726. {
  24727. return;
  24728. }
  24729. //ToDo - better incorporation of this section into rest of code
  24730. iValue = 0;
  24731. iBestValue = 0;
  24732. if (plot()->getOwnerINLINE() == getOwnerINLINE() && !isCargo())
  24733. {
  24734. iBestValue = getGroup()->getNumUnits();
  24735. pBestUnit = NULL;
  24736. //if (getGroup()->getNumUnits() == 1)
  24737. {
  24738. if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) == 0)
  24739. {
  24740. for(pLoopSelectionGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopSelectionGroup != NULL; pLoopSelectionGroup = kPlayer.nextSelectionGroup(&iLoop))
  24741. {
  24742. if (pLoopSelectionGroup->getHeadUnit() != NULL)
  24743. {
  24744. if (pLoopSelectionGroup->getHeadUnit()->AI_getGroupflag() == GROUPFLAG_CONQUEST)
  24745. {
  24746. if (pLoopSelectionGroup != getGroup() && !pLoopSelectionGroup->getHeadUnit()->isCargo())
  24747. {
  24748. pLoopPlot = pLoopSelectionGroup->getHeadUnit()->plot();
  24749. if (AI_plotValid(pLoopPlot))
  24750. {
  24751. if (!isEnemy(pLoopPlot->getTeam()))
  24752. {
  24753. if (AI_allowGroup(pLoopSelectionGroup->getHeadUnit(), UNITAI_UNKNOWN))
  24754. {
  24755. if (!(pLoopPlot->isVisibleEnemyUnit(this)))
  24756. {
  24757. if ((getGroup()->getNumUnits() == 1) ||
  24758. atPlot(pLoopPlot))
  24759. {
  24760. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  24761. {
  24762. iValue = 10 * pLoopSelectionGroup->getHeadUnit()->getLevel();
  24763. iValue += pLoopSelectionGroup->getNumUnits();
  24764. if (pLoopSelectionGroup->getHeadUnit()->AI_getUnitAIType() == UNITAI_HERO)
  24765. {
  24766. iValue *= 2;
  24767. }
  24768. if (pLoopSelectionGroup->getHeadUnit()->isAvatarOfCivLeader())
  24769. {
  24770. iValue *= 5;
  24771. }
  24772. if (atPlot(pLoopPlot))
  24773. {
  24774. iValue *= 2;
  24775. }
  24776. else
  24777. {
  24778. iValue /= (iPathTurns + 1);
  24779. }
  24780. if (iValue > iBestValue)
  24781. {
  24782. iBestValue = iValue;
  24783. pBestUnit = pLoopSelectionGroup->getHeadUnit();
  24784. }
  24785. }
  24786. }
  24787. }
  24788. }
  24789. }
  24790. }
  24791. }
  24792. }
  24793. }
  24794. }
  24795. }
  24796. if (pBestUnit != NULL)
  24797. {
  24798. if (atPlot(pBestUnit->plot()))
  24799. {
  24800. if (getGroup()->getNumUnits() == 1)
  24801. {
  24802. if( gUnitLogLevel >= 3 )
  24803. {
  24804. logBBAI(" ...joining group %d on plot", pBestUnit->getGroup());
  24805. }
  24806. joinGroup(pBestUnit->getGroup());
  24807. return;
  24808. }
  24809. else
  24810. {
  24811. if( gUnitLogLevel >= 3 )
  24812. {
  24813. logBBAI(" ...merging into group %d on plot", pBestUnit->getGroup());
  24814. }
  24815. getGroup()->mergeIntoGroup(pBestUnit->getGroup());
  24816. return;
  24817. }
  24818. }
  24819. else
  24820. {
  24821. if( gUnitLogLevel >= 2 )
  24822. {
  24823. logBBAI(" ...moving to merge group");
  24824. }
  24825. getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
  24826. return;
  24827. }
  24828. }
  24829. }
  24830. /*
  24831. else
  24832. {
  24833. bool bMerge = false;
  24834. pBestUnit = NULL;
  24835. for(pLoopSelectionGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopSelectionGroup != NULL; pLoopSelectionGroup = kPlayer.nextSelectionGroup(&iLoop))
  24836. {
  24837. if (pLoopSelectionGroup->getHeadUnit() != NULL)
  24838. {
  24839. if (pLoopSelectionGroup->getHeadUnit()->AI_getGroupflag()==GROUPFLAG_CONQUEST)
  24840. {
  24841. if (pLoopSelectionGroup != getGroup() && !pLoopSelectionGroup->getHeadUnit()->isCargo())
  24842. {
  24843. CvPlot* pPlot = pLoopSelectionGroup->getHeadUnit()->plot();
  24844. if (AI_plotValid(pPlot))
  24845. {
  24846. if (!isEnemy(pPlot->getTeam()))
  24847. {
  24848. if (!(pPlot->isVisibleEnemyUnit(this)))
  24849. {
  24850. if (AI_allowGroup(pLoopSelectionGroup->getHeadUnit(), UNITAI_UNKNOWN))
  24851. {
  24852. if (generatePath(pPlot, 0, true, &iPathTurns))
  24853. {
  24854. if (pLoopSelectionGroup->getNumUnits() > (getGroup()->getNumUnits() * 2))
  24855. {
  24856. if (iPathTurns < 5)
  24857. {
  24858. bMerge = true;
  24859. pBestUnit = pLoopSelectionGroup->getHeadUnit();
  24860. break;
  24861. }
  24862. }
  24863. }
  24864. }
  24865. }
  24866. }
  24867. }
  24868. }
  24869. }
  24870. }
  24871. }
  24872. if (bMerge)
  24873. {
  24874. if (atPlot(pBestUnit->plot()))
  24875. {
  24876. getGroup()->mergeIntoGroup(pBestUnit->getGroup());
  24877. return;
  24878. }
  24879. else
  24880. {
  24881. getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
  24882. return;
  24883. }
  24884. }
  24885. }
  24886. */
  24887. }
  24888. bool bAtWar = isEnemy(plot()->getTeam());
  24889. // Look for local threats - mainly meant to deal with early barbarian or HN threats
  24890. bool bDanger = (kPlayer.AI_getAnyPlotDanger(plot(), 3, false));
  24891. if( bReadyToAttack )
  24892. {
  24893. // Check that stack has units which can capture cities
  24894. bReadyToAttack = false;
  24895. int iCityCaptureCount = 0;
  24896. CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
  24897. while (pUnitNode != NULL && !bReadyToAttack)
  24898. {
  24899. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  24900. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  24901. if( !pLoopUnit->isOnlyDefensive() )
  24902. {
  24903. if( !(pLoopUnit->isNoCapture()) && (pLoopUnit->combatLimit() >= 100) )
  24904. {
  24905. iCityCaptureCount++;
  24906. if( iCityCaptureCount > 5 || 3*iCityCaptureCount > getGroup()->getNumUnits() )
  24907. {
  24908. bReadyToAttack = true;
  24909. }
  24910. }
  24911. }
  24912. }
  24913. }
  24914. CvCity* pTargetCity = NULL;
  24915. if (bReadyToAttack)
  24916. {
  24917. //if (AI_cityAttack(1, 80, true))
  24918. if (AI_stackAttackCity(1, 160, true))
  24919. {
  24920. if( gUnitLogLevel >= 3 )
  24921. {
  24922. logBBAI(" ...making opportunistic city attack");
  24923. }
  24924. return;
  24925. }
  24926. }
  24927. if (AI_guardCity(false, false))
  24928. {
  24929. /*
  24930. if( bReadyToAttack && (eAreaAIType != AREAAI_DEFENSIVE))
  24931. {
  24932. CvSelectionGroup* pOldGroup = getGroup();
  24933. pOldGroup->AI_separateNonAI(UNITAI_ATTACK_CITY);
  24934. }
  24935. */
  24936. return;
  24937. }
  24938. if (AI_groupMergeRange(UNITAI_HERO, 0, false, true, bIgnoreFaster))
  24939. {
  24940. logBBAI(" ...merging with hero unit");
  24941. return;
  24942. }
  24943. if (AI_groupMergeRange(UNITAI_WARWIZARD, 0, false, true, bIgnoreFaster))
  24944. {
  24945. logBBAI(" ...merging with wizard unit");
  24946. return;
  24947. }
  24948. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 0, true, true, bIgnoreFaster))
  24949. {
  24950. logBBAI(" ...merging with attack city unit");
  24951. return;
  24952. }
  24953. // BBAI TODO: Find some way of reliably targetting nearby cities with less defense ...
  24954. pTargetCity = AI_pickTargetCity(0, MAX_INT, bHuntBarbs);
  24955. if( pTargetCity != NULL && (getGroup()->getNumUnits() > 1))
  24956. {
  24957. if( gUnitLogLevel >= 3 ) logBBAI(" ...trying to assault target city");
  24958. int iStepDistToTarget = stepDistance(pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), getX_INLINE(), getY_INLINE());
  24959. //int iAttackRatio = std::max(100, GC.getBBAI_ATTACK_CITY_STACK_RATIO());
  24960. int iAttackRatio = 150; //Todo - find better way to come up with an AttackRatio - should vary based on situation
  24961. // loop through units. Add level Subtract if melee or collateral or explodeincombat. Add if mage or UNITAI_HERO
  24962. int iComparePostBombard = 0;
  24963. // AI gets a 1-tile sneak peak to compensate for lack of memory
  24964. if( iStepDistToTarget <= 2 || pTargetCity->isVisible(getTeam(),false) )
  24965. {
  24966. iComparePostBombard = getGroup()->AI_compareStacks(pTargetCity->plot(), true, true, true);
  24967. int iDefenseModifier = pTargetCity->getDefenseModifier(true);
  24968. int iBombardTurns = getGroup()->getBombardTurns(pTargetCity);
  24969. iDefenseModifier *= std::max(0, 20 - iBombardTurns);
  24970. iDefenseModifier /= 20;
  24971. iComparePostBombard *= 100 + std::max(0, iDefenseModifier);
  24972. iComparePostBombard /= 100;
  24973. }
  24974. logBBAI(" ...iComparePostBombard = %d", iComparePostBombard);
  24975. if( iStepDistToTarget <= 2 )
  24976. {
  24977. if( iComparePostBombard < iAttackRatio )
  24978. {
  24979. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
  24980. {
  24981. return;
  24982. }
  24983. int iOurOffense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),1,false,false,true);
  24984. int iEnemyOffense = kPlayer.AI_getEnemyPlotStrength(pTargetCity->plot(),2,false,false);
  24985. // If in danger, seek defensive ground
  24986. if( 4*iOurOffense < 3*iEnemyOffense)
  24987. {
  24988. if( AI_choke(1, true) )
  24989. {
  24990. logBBAI(" ...choking %S due to troop presence in city", pTargetCity->getName().GetCString());
  24991. return;
  24992. }
  24993. }
  24994. }
  24995. if (iStepDistToTarget == 1)
  24996. {
  24997. // temp hack - Tholal ToDo: need to figure out why the AI is reluctant to attack empty cities
  24998. logBBAI(" ...next to target city...");
  24999. if (pTargetCity->plot()->getNumDefenders(pTargetCity->getOwner()) == 0)
  25000. {
  25001. logBBAI(" ...target city is empty!");
  25002. getGroup()->pushMission(MISSION_MOVE_TO, pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), MOVE_DIRECT_ATTACK);
  25003. return;
  25004. }
  25005. // If next to target city and we would attack after bombarding down defenses,
  25006. // or if defenses have crept up past half
  25007. if( (iComparePostBombard >= iAttackRatio) || (pTargetCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE() * 1) / 2)) )
  25008. {
  25009. logBBAI(" ...considering attack/bombard...");
  25010. if( (iComparePostBombard < std::max(150, GC.getDefineINT("BBAI_SKIP_BOMBARD_MIN_STACK_RATIO"))) )
  25011. {
  25012. // Tholal Note: this section wasn't doing much useful
  25013. // Move to good tile to attack from unless we're way more powerful
  25014. /*
  25015. if (plot()->defenseModifier(getTeam(), false) <= 0)
  25016. {
  25017. if( AI_goToTargetCity(0,1,pTargetCity) )
  25018. {
  25019. return;
  25020. }
  25021. }
  25022. */
  25023. }
  25024. // Bombard may skip if stack is powerful enough
  25025. if (AI_bombardCity())
  25026. {
  25027. logBBAI(" ...bombarding city");
  25028. return;
  25029. }
  25030. //stack attack
  25031. if (getGroup()->getNumUnits() > 1)
  25032. {
  25033. // BBAI TODO: What is right ratio?
  25034. //if (AI_stackAttackCity(1, iAttackRatio, true))
  25035. //if (AI_cityAttack(1, iAttackRatio, true))
  25036. if (AI_stackAttackCity(1, iAttackRatio, true))
  25037. {
  25038. logBBAI(" ...stack attacking city");
  25039. return;
  25040. }
  25041. }
  25042. // If not strong enough alone, merge if another stack is nearby
  25043. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
  25044. {
  25045. logBBAI(" ...merging with another group");
  25046. return;
  25047. }
  25048. if( getGroup()->getNumUnits() == 1 )
  25049. {
  25050. if( AI_cityAttack(1, 70) )
  25051. {
  25052. logBBAI(" ...solo city attack");
  25053. return;
  25054. }
  25055. }
  25056. }
  25057. }
  25058. }
  25059. if( iComparePostBombard < iAttackRatio && GET_TEAM(getTeam()).isAtWar(pTargetCity->getTeam()))
  25060. {
  25061. // If not strong enough, pillage around target city without exposing ourselves
  25062. if( AI_pillageRange(0) )
  25063. {
  25064. logBBAI(" ...pillaging");
  25065. return;
  25066. }
  25067. if( AI_anyAttack(1, 80, 0, false) )
  25068. {
  25069. logBBAI(" ...AI_anyttack");
  25070. return;
  25071. }
  25072. if (AI_heal(30, 1))
  25073. {
  25074. logBBAI(" ...healing");
  25075. return;
  25076. }
  25077. // Pillage around enemy city
  25078. if( AI_pillageAroundCity(pTargetCity, 11, 3) )
  25079. {
  25080. logBBAI(" ...pillage around city 1\n");
  25081. return;
  25082. }
  25083. if( AI_pillageAroundCity(pTargetCity, 0, 5) )
  25084. {
  25085. logBBAI(" ...pillage around city 2\n");
  25086. return;
  25087. }
  25088. if (getGroup()->getNumUnits() > pTargetCity->plot()->getNumDefenders(pTargetCity->getOwner()))
  25089. {
  25090. if( AI_choke(1) )
  25091. {
  25092. if( gUnitLogLevel >= 3 )
  25093. {
  25094. logBBAI(" ...choking %S ", pTargetCity->getName().GetCString());
  25095. }
  25096. return;
  25097. }
  25098. }
  25099. if (!pTargetCity->isVisible(getTeam(),false))
  25100. {
  25101. if (AI_goToTargetCity(0, 10, pTargetCity))
  25102. {
  25103. logBBAI(" ...moving to scout target city (%S)", pTargetCity->getName().GetCString());
  25104. return;
  25105. }
  25106. }
  25107. }
  25108. else
  25109. {
  25110. if( AI_goToTargetCity(0,6,pTargetCity) )
  25111. {
  25112. logBBAI(" ...moving to target city (%S)", pTargetCity->getName().GetCString());
  25113. return;
  25114. }
  25115. }
  25116. // Tholal Note - seems that sometimes we have to force the AI to attack their targets
  25117. // Note: This section can cause the AI to declare War before stack is near borders
  25118. if (iComparePostBombard >= 120)
  25119. {
  25120. if (GET_TEAM(getTeam()).isAtWar(pTargetCity->getTeam()) || plot()->isAdjacentPlayer(pTargetCity->getOwner()))
  25121. {
  25122. if( AI_goToTargetCity(MOVE_THROUGH_ENEMY, 10 ,pTargetCity) )
  25123. {
  25124. if( gUnitLogLevel >= 3 )
  25125. {
  25126. logBBAI(" ...moving to direct attack %S", pTargetCity->getName().GetCString());
  25127. }
  25128. return;
  25129. }
  25130. }
  25131. else
  25132. {
  25133. if( AI_goToTargetCity(0, 10 ,pTargetCity) )
  25134. {
  25135. if( gUnitLogLevel >= 3 )
  25136. {
  25137. logBBAI(" ...moving to attack %S", pTargetCity->getName().GetCString());
  25138. }
  25139. return;
  25140. }
  25141. }
  25142. }
  25143. }
  25144. if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
  25145. {
  25146. return;
  25147. }
  25148. if (AI_heal(30, 1))
  25149. {
  25150. return;
  25151. }
  25152. // BBAI TODO: Stack v stack combat ... definitely want to do in own territory, but what about enemy territory?
  25153. if (collateralDamage() > 0 && plot()->getOwnerINLINE() == getOwnerINLINE()) // note: this requires that the group leader has collateralDamage; doesnt check whole stack
  25154. {
  25155. if (AI_anyAttack(1, 45, 3, false))
  25156. {
  25157. return;
  25158. }
  25159. if( !bReadyToAttack )
  25160. {
  25161. if (AI_anyAttack(1, 25, 5, false))
  25162. {
  25163. return;
  25164. }
  25165. }
  25166. }
  25167. if (AI_anyAttack(1, 60, 0, false))
  25168. {
  25169. return;
  25170. }
  25171. if (bAtWar && (getGroup()->getNumUnits() <= 2))
  25172. {
  25173. if (AI_pillageRange(3, 11))
  25174. {
  25175. logBBAI(" ...pillage3 \n");
  25176. return;
  25177. }
  25178. if (AI_pillageRange(1))
  25179. {
  25180. logBBAI(" ...pillage 4 \n");
  25181. return;
  25182. }
  25183. }
  25184. bHuntBarbs = false;
  25185. if ((area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0) && !GET_TEAM(getTeam()).isBarbarianAlly())
  25186. {
  25187. if ((area()->getAreaAIType(getTeam()) != AREAAI_OFFENSIVE) && (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE))
  25188. {
  25189. bHuntBarbs = true;
  25190. }
  25191. }
  25192. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  25193. {
  25194. if (!bLandWar)
  25195. {
  25196. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  25197. {
  25198. return;
  25199. }
  25200. }
  25201. if( bReadyToAttack )
  25202. {
  25203. // Wait for units about to join our group
  25204. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  25205. int iJoiners = kPlayer.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
  25206. if( (iJoiners*5) > getGroup()->getNumUnits() )
  25207. {
  25208. getGroup()->pushMission(MISSION_SKIP);
  25209. return;
  25210. }
  25211. }
  25212. else
  25213. {
  25214. if (eAreaAIType == AREAAI_DEFENSIVE)
  25215. {
  25216. // Use smaller attack city stacks on defenses
  25217. if (AI_guardCity(false, true, 3))
  25218. {
  25219. return;
  25220. }
  25221. }
  25222. if( bTurtle )
  25223. {
  25224. if (AI_guardCity(false, true, 7))
  25225. {
  25226. return;
  25227. }
  25228. }
  25229. int iTargetCount = kPlayer.AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
  25230. if ((iTargetCount * 5) > getGroup()->getNumUnits())
  25231. {
  25232. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  25233. int iJoiners = kPlayer.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
  25234. if( (iJoiners*5) > getGroup()->getNumUnits() )
  25235. {
  25236. getGroup()->pushMission(MISSION_SKIP);
  25237. return;
  25238. }
  25239. if (AI_moveToStagingCity())
  25240. {
  25241. return;
  25242. }
  25243. }
  25244. }
  25245. }
  25246. if (AI_heal(50, 3))
  25247. {
  25248. return;
  25249. }
  25250. if (!bAtWar)
  25251. {
  25252. if (AI_heal())
  25253. {
  25254. return;
  25255. }
  25256. if ((getGroup()->getNumUnits() == 1) && (getTeam() != plot()->getTeam()))
  25257. {
  25258. if (AI_retreatToCity())
  25259. {
  25260. return;
  25261. }
  25262. }
  25263. }
  25264. if (!bReadyToAttack && !noDefensiveBonus())
  25265. {
  25266. if (AI_guardCity(false, false))
  25267. {
  25268. return;
  25269. }
  25270. }
  25271. bool bAnyWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
  25272. if (bReadyToAttack)
  25273. {
  25274. if (bHuntBarbs || pTargetCity == NULL)
  25275. {
  25276. if (AI_goToTargetBarbCity((bAnyWarPlan ? 7 : 15)))
  25277. {
  25278. return;
  25279. }
  25280. }
  25281. else if (bLandWar && pTargetCity != NULL && (getGroup()->getNumUnits() > 1))
  25282. {
  25283. // Before heading out, check whether to wait to allow unit upgrades
  25284. if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
  25285. {
  25286. if( !(kPlayer.AI_isFinancialTrouble()) )
  25287. {
  25288. // Check if stack has units which can upgrade
  25289. int iNeedUpgradeCount = 0;
  25290. CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
  25291. while (pUnitNode != NULL)
  25292. {
  25293. CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
  25294. pUnitNode = getGroup()->nextUnitNode(pUnitNode);
  25295. if( pLoopUnit->getUpgradeCity(false) != NULL )
  25296. {
  25297. iNeedUpgradeCount++;
  25298. if( (2 * iNeedUpgradeCount) > getGroup()->getNumUnits()) // was 8
  25299. {
  25300. if (getGroup()->getNumUnits() < (kPlayer.getNumCities() * 8))
  25301. {
  25302. if( gUnitLogLevel >= 3 )
  25303. {
  25304. logBBAI(" ...waiting for upgrades. Groupsize: %d (potential upgrades: %d)\n", getGroup()->getNumUnits(), iNeedUpgradeCount);
  25305. }
  25306. getGroup()->pushMission(MISSION_SKIP);
  25307. return;
  25308. }
  25309. }
  25310. }
  25311. }
  25312. }
  25313. }
  25314. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 5, pTargetCity))
  25315. {
  25316. return;
  25317. }
  25318. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 2, 2))
  25319. {
  25320. return;
  25321. }
  25322. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 8, pTargetCity))
  25323. {
  25324. return;
  25325. }
  25326. // Load stack if walking will take a long time
  25327. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 3))
  25328. {
  25329. return;
  25330. }
  25331. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12, pTargetCity))
  25332. {
  25333. return;
  25334. }
  25335. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 7))
  25336. {
  25337. return;
  25338. }
  25339. if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, MAX_INT, pTargetCity))
  25340. {
  25341. return;
  25342. }
  25343. if (bAnyWarPlan)
  25344. {
  25345. CvCity* pTargetCity = area()->getTargetCity(getOwnerINLINE());
  25346. if (pTargetCity != NULL)
  25347. {
  25348. if( gUnitLogLevel >= 3 ) logBBAI(" ...%S, %d blockage problem", getName().GetCString(), getID());
  25349. if (AI_solveBlockageProblem(pTargetCity->plot(), (GET_TEAM(getTeam()).getAtWarCount(true) == 0)))
  25350. {
  25351. return;
  25352. }
  25353. }
  25354. }
  25355. }
  25356. }
  25357. else
  25358. {
  25359. int iTargetCount = kPlayer.AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
  25360. if( ((iTargetCount * 4) > getGroup()->getNumUnits()) || ((getGroup()->getNumUnits() + iTargetCount) >= (bHuntBarbs ? 5 : AI_stackOfDoomExtra())) )
  25361. {
  25362. MissionAITypes eMissionAIType = MISSIONAI_GROUP;
  25363. int iJoiners = kPlayer.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
  25364. if( (iJoiners*6) > getGroup()->getNumUnits() )
  25365. {
  25366. getGroup()->pushMission(MISSION_SKIP);
  25367. return;
  25368. }
  25369. if (AI_safety())
  25370. {
  25371. return;
  25372. }
  25373. }
  25374. if ((bombardRate() > 0) && noDefensiveBonus())
  25375. {
  25376. // BBAI Notes: Add this stack lead by bombard unit to stack probably not lead by a bombard unit
  25377. // BBAI TODO: Some sense of minimum stack size? Can have big stack moving 10 turns to merge with tiny stacks
  25378. if (AI_group(UNITAI_ATTACK_CITY, -1, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ false))
  25379. {
  25380. return;
  25381. }
  25382. }
  25383. else
  25384. {
  25385. if (AI_group(UNITAI_ATTACK_CITY, AI_stackOfDoomExtra() * 2, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ false))
  25386. {
  25387. return;
  25388. }
  25389. }
  25390. }
  25391. if (plot()->getOwnerINLINE() == getOwnerINLINE() && bLandWar)
  25392. {
  25393. if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) )
  25394. {
  25395. // if no land path to enemy cities, try getting there another way
  25396. if (AI_offensiveAirlift())
  25397. {
  25398. return;
  25399. }
  25400. if( pTargetCity != NULL )
  25401. {
  25402. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
  25403. {
  25404. return;
  25405. }
  25406. }
  25407. }
  25408. }
  25409. if (AI_moveToStagingCity())
  25410. {
  25411. return;
  25412. }
  25413. if (AI_offensiveAirlift())
  25414. {
  25415. return;
  25416. }
  25417. if (AI_guardFort(true))
  25418. {
  25419. return;
  25420. }
  25421. if (AI_travelToUpgradeCity())
  25422. {
  25423. return;
  25424. }
  25425. if (AI_retreatToCity())
  25426. {
  25427. return;
  25428. }
  25429. if( getGroup()->isStranded() )
  25430. {
  25431. if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
  25432. {
  25433. return;
  25434. }
  25435. if( !isHuman() && plot()->isCoastalLand() && kPlayer.AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
  25436. {
  25437. // If no other desireable actions, wait for pickup
  25438. getGroup()->pushMission(MISSION_SKIP);
  25439. return;
  25440. }
  25441. if (AI_patrol())
  25442. {
  25443. return;
  25444. }
  25445. }
  25446. if (AI_safety())
  25447. {
  25448. return;
  25449. }
  25450. getGroup()->pushMission(MISSION_SKIP);
  25451. return;
  25452. }
  25453. void CvUnitAI::AI_heromove()
  25454. {
  25455. if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL"))
  25456. {
  25457. if (isHiddenNationality())
  25458. {
  25459. AI_setUnitAIType(UNITAI_PIRATE_SEA);
  25460. return;
  25461. }
  25462. else
  25463. {
  25464. AI_setUnitAIType(UNITAI_ATTACK_SEA);
  25465. return;
  25466. }
  25467. }
  25468. if (AI_heal())
  25469. {
  25470. return;
  25471. }
  25472. if (getUnitClassType()==GC.getDefineINT("UNITCLASS_GOVANNON"))
  25473. {
  25474. if (AI_Govannonmove())
  25475. {
  25476. return;
  25477. }
  25478. getGroup()->pushMission(MISSION_SKIP);
  25479. return;
  25480. }
  25481. if (getUnitClassType()==GC.getDefineINT("UNITCLASS_LOKI"))
  25482. {
  25483. if (AI_Lokimove())
  25484. {
  25485. return;
  25486. }
  25487. getGroup()->pushMission(MISSION_SKIP);
  25488. return;
  25489. }
  25490. if (getUnitClassType()==GC.getDefineINT("UNITCLASS_RANTINE"))
  25491. {
  25492. if (GET_TEAM(getTeam()).isBarbarianAlly() && getLevel() < 8)
  25493. {
  25494. if (AI_Rantinemove())
  25495. {
  25496. return;
  25497. }
  25498. }
  25499. AI_setGroupflag(GROUPFLAG_CONQUEST);
  25500. getGroup()->pushMission(MISSION_SKIP);
  25501. return;
  25502. }
  25503. if (getGroup()->getNumUnits() > 1)
  25504. {
  25505. joinGroup(NULL);
  25506. }
  25507. if ((GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0) || isAvatarOfCivLeader())
  25508. {
  25509. AI_setGroupflag(GROUPFLAG_CONQUEST);
  25510. }
  25511. else
  25512. {
  25513. AI_setGroupflag(GROUPFLAG_PATROL);
  25514. }
  25515. getGroup()->pushMission(MISSION_SKIP);
  25516. return;
  25517. }
  25518. bool CvUnitAI::AI_Govannonmove()
  25519. {
  25520. if (GC.getDefineINT("SPELL_TEACH_SPELLCASTING") != -1)
  25521. {
  25522. if (canCast(GC.getDefineINT("SPELL_TEACH_SPELLCASTING"),false))
  25523. cast(GC.getDefineINT("SPELL_TEACH_SPELLCASTING"));
  25524. int iBestValue=0, iValue;
  25525. int iLoop;
  25526. int iPathTurns;
  25527. CvSelectionGroup* pLoopSelectionGroup;
  25528. CvUnit* pBestUnit=NULL;
  25529. for(pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).firstSelectionGroup(&iLoop); pLoopSelectionGroup != NULL; pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).nextSelectionGroup(&iLoop))
  25530. {
  25531. if (pLoopSelectionGroup->getHeadUnit() != NULL)
  25532. {
  25533. if (pLoopSelectionGroup!=getGroup())
  25534. {
  25535. CvPlot* pPlot = pLoopSelectionGroup->getHeadUnit()->plot();
  25536. if (AI_plotValid(pPlot))
  25537. {
  25538. if (pPlot->getOwnerINLINE()==getOwnerINLINE() && pPlot!=plot())
  25539. {
  25540. if (!(pPlot->isVisibleEnemyUnit(this)))
  25541. {
  25542. if (GC.getGameINLINE().getSorenRandNum(100, "GovannonScores")<10)
  25543. {
  25544. if (generatePath(pPlot, 0, true, &iPathTurns))
  25545. {
  25546. iValue = pLoopSelectionGroup->getNumUnits()/(iPathTurns+1);
  25547. if (iValue >= iBestValue)
  25548. {
  25549. iBestValue = iValue;
  25550. pBestUnit = pLoopSelectionGroup->getHeadUnit();
  25551. }
  25552. }
  25553. }
  25554. }
  25555. }
  25556. }
  25557. }
  25558. }
  25559. }
  25560. if (pBestUnit!=NULL)
  25561. {
  25562. if (atPlot(pBestUnit->plot()))
  25563. {
  25564. //Spell
  25565. return false;
  25566. }
  25567. else if (generatePath(pBestUnit->plot(), 0, true, &iPathTurns))
  25568. {
  25569. //getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, NO_MISSIONAI, NULL, pBestUnit);
  25570. getGroup()->pushMission(MISSION_MOVE_TO, pBestUnit->getX_INLINE(), pBestUnit->getY_INLINE(), MOVE_DIRECT_ATTACK);
  25571. return true;
  25572. }
  25573. }
  25574. }
  25575. return false;
  25576. }
  25577. bool CvUnitAI::AI_Lokimove()
  25578. {
  25579. logBBAI(" %S (unit %d) starting LokiMove", getName().GetCString(), getID());
  25580. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  25581. bool bFinancialTrouble = kPlayer.AI_isFinancialTrouble();
  25582. if (getGroup()->getNumUnits() > 1)
  25583. {
  25584. logBBAI(" ...leaving group");
  25585. joinGroup(NULL);
  25586. }
  25587. // HARDCODE!
  25588. if (plot()->isCity())
  25589. {
  25590. if (!bFinancialTrouble && plot()->getPlotCity()->getCulture(plot()->getPlotCity()->getOwnerINLINE())==0)
  25591. {
  25592. if (canCast(GC.getDefineINT("SPELL_DISRUPT"),false))
  25593. cast(GC.getDefineINT("SPELL_DISRUPT"));
  25594. }
  25595. else
  25596. {
  25597. if (plot()->getOwnerINLINE() == getOwnerINLINE())
  25598. {
  25599. int ispell = chooseSpell();
  25600. if (ispell != NO_SPELL)
  25601. {
  25602. cast(ispell);
  25603. }
  25604. }
  25605. else
  25606. {
  25607. if (canCast(GC.getDefineINT("SPELL_ENTERTAIN"),false))
  25608. cast(GC.getDefineINT("SPELL_ENTERTAIN"));
  25609. }
  25610. }
  25611. }
  25612. CvCity* pLoopCity;
  25613. int iLoop = 0;
  25614. int iPathTurns;
  25615. CvPlot* pBestPlot = NULL;
  25616. int iValue = 0;
  25617. int iBestValue = 0;
  25618. // find a target city - preference given to high population cities (for Entertain) and zero culture cities (for Disrupt)
  25619. for (int iI = 0; iI < MAX_PLAYERS; iI++)
  25620. {
  25621. if (GET_PLAYER((PlayerTypes)iI).isAlive())
  25622. {
  25623. //don't target teammates or vassals
  25624. if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam() && !GET_TEAM(GET_PLAYER((PlayerTypes)iI).getTeam()).isVassal(getTeam()))
  25625. {
  25626. for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
  25627. {
  25628. if (kPlayer.AI_deduceCitySite(pLoopCity))
  25629. {
  25630. if (!GET_TEAM(getTeam()).isAtWar(pLoopCity->getTeam()))
  25631. {
  25632. if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
  25633. {
  25634. iValue = pLoopCity->getPopulation();
  25635. if (pLoopCity->getCulture(pLoopCity->getOwnerINLINE())==0)
  25636. {
  25637. if (pLoopCity->plot()->isAdjacentPlayer(getOwner()))
  25638. {
  25639. iValue *= 10;
  25640. }
  25641. else
  25642. {
  25643. iValue *= 2;
  25644. }
  25645. }
  25646. iValue /= iPathTurns;
  25647. if (iValue > iBestValue)
  25648. {
  25649. iBestValue = iValue;
  25650. pBestPlot = pLoopCity->plot();
  25651. }
  25652. }
  25653. }
  25654. }
  25655. }
  25656. }
  25657. }
  25658. }
  25659. if (pBestPlot != NULL)
  25660. {
  25661. logBBAI(" ...targeting %S (value: %d)", pBestPlot->getPlotCity()->getName().GetCString(), iBestValue);
  25662. if (atPlot(pBestPlot))
  25663. {
  25664. logBBAI(" ...at target city");
  25665. getGroup()->pushMission(MISSION_SKIP);
  25666. return true;
  25667. }
  25668. else
  25669. {
  25670. logBBAI(" ...moving to target city");
  25671. getGroup()->pushMission(MISSION_MOVE_TO,pBestPlot->getX_INLINE(),pBestPlot->getY_INLINE(),MOVE_THROUGH_ENEMY);
  25672. return true;
  25673. }
  25674. }
  25675. if (AI_exploreRange(5))
  25676. {
  25677. logBBAI(" ...exploring");
  25678. return true;
  25679. }
  25680. if (AI_retreatToCity())
  25681. {
  25682. return true;
  25683. }
  25684. if (AI_safety())
  25685. {
  25686. return true;
  25687. }
  25688. return false;
  25689. }
  25690. bool CvUnitAI::AI_Rantinemove()
  25691. {
  25692. //ToDo - figure out why this grouping code isn't working anymore - for now, just skip it
  25693. //if (getGroup()->getNumUnits()<4)
  25694. if (2 < 1)
  25695. {
  25696. if (!(plot()->isCity() && plot()->getOwnerINLINE()==getOwnerINLINE()))
  25697. {
  25698. if (AI_retreatToCity())
  25699. {
  25700. return true;
  25701. }
  25702. }
  25703. int iSearchRange=5;
  25704. int icount=0;
  25705. int iDX, iDY;
  25706. CvPlot* pLoopPlot;
  25707. CvUnit* pLoopUnit;
  25708. int iPathTurns;
  25709. CLLNode<IDInfo>* pUnitNode;
  25710. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  25711. {
  25712. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  25713. {
  25714. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  25715. if (pLoopPlot != NULL)
  25716. {
  25717. if (pLoopPlot->getOwnerINLINE()==getOwnerINLINE())
  25718. {
  25719. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  25720. {
  25721. pUnitNode = pLoopPlot->headUnitNode();
  25722. while (pUnitNode != NULL)
  25723. {
  25724. pLoopUnit = ::getUnit(pUnitNode->m_data);
  25725. pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
  25726. if (pLoopUnit)
  25727. {
  25728. if (!(pLoopUnit->getGroup()->getHeadUnit()==pLoopUnit) || pLoopUnit->getGroup()->getNumUnits()==1)
  25729. {
  25730. if (pLoopUnit->AI_getUnitAIType()==UNITAI_COUNTER && pLoopUnit->AI_getGroupflag()==GROUPFLAG_PATROL)
  25731. {
  25732. if(pLoopUnit->getGroup()->getHeadUnit()!=pLoopUnit || pLoopUnit->getGroup()->getNumUnits()==1)
  25733. {
  25734. if(pLoopUnit->atPlot(plot()))
  25735. {
  25736. pLoopUnit->joinGroup(NULL);
  25737. pLoopUnit->AI_setGroupflag(GROUPFLAG_NONE);
  25738. pLoopUnit->AI_setUnitAIType(UNITAI_ATTACK);
  25739. pLoopUnit->joinGroup(getGroup());
  25740. return false;
  25741. }
  25742. else
  25743. {
  25744. //pLoopUnit->getGroup()->pushMission(MISSION_MOVE_TO_UNIT, getOwnerINLINE(), getID(), 0, false, false, MISSIONAI_GROUP, NULL, this);
  25745. pLoopUnit->getGroup()->pushMission(MISSION_MOVE_TO, getX_INLINE(), getY_INLINE(), MOVE_DIRECT_ATTACK);
  25746. return true;
  25747. }
  25748. }
  25749. }
  25750. }
  25751. }
  25752. }
  25753. }
  25754. }
  25755. }
  25756. }
  25757. }
  25758. }
  25759. else
  25760. {
  25761. CvCity* pLoopCity;
  25762. CvCity* pBestCity = NULL;
  25763. int iLoop;
  25764. int iSearchRange=8;
  25765. int icount=0;
  25766. int iPathTurns;
  25767. int iValue = 0;
  25768. int iBestValue = 0;
  25769. CvPlot* pBestPlot = NULL;
  25770. if (plot()->isCity())
  25771. {
  25772. if (canCast(GC.getDefineINT("SPELL_CONVERT_CITY_RANTINE"),false))
  25773. cast(GC.getDefineINT("SPELL_CONVERT_CITY_RANTINE"));
  25774. }
  25775. //ToDo: figure out how to load Rantine into a boat
  25776. for (pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).nextCity(&iLoop))
  25777. {
  25778. if (AI_plotValid(pLoopCity->plot()))
  25779. {
  25780. if (pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam()))
  25781. {
  25782. if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
  25783. {
  25784. iValue = (pLoopCity->getPopulation() * 10);
  25785. if ((pLoopCity->plot())->isAdjacentPlayer(getOwnerINLINE(), false))
  25786. {
  25787. iValue *= 3;
  25788. }
  25789. iValue /= (iPathTurns + 1);
  25790. if (iValue > iBestValue)
  25791. {
  25792. iBestValue = iValue;
  25793. pBestCity = pLoopCity;
  25794. }
  25795. }
  25796. }
  25797. }
  25798. }
  25799. if (pBestCity != NULL)
  25800. {
  25801. pBestPlot = pBestCity->plot();
  25802. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
  25803. return true;
  25804. }
  25805. }
  25806. return false;
  25807. }
  25808. void CvUnitAI::AI_upgrademanaMove()
  25809. {
  25810. logBBAI(" %S (unit %d), starting AI_upgrademanaMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
  25811. if (GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_TOWERMASTERY1))
  25812. {
  25813. if (GET_PLAYER(getOwnerINLINE()).countOwnedBonuses((BonusTypes)GC.getDefineINT("BONUSCLASS_MANA_RAW")) == 1)
  25814. {
  25815. if (GET_PLAYER(getOwnerINLINE()).countOwnedBonuses((BonusTypes)GC.getInfoTypeForString("BONUS_MANA_METAMAGIC")) == 0)
  25816. {
  25817. if( gUnitLogLevel > 2 ) logBBAI(" ...reserving a raw mana for Metamagic");
  25818. if (plot()->isCity())
  25819. {
  25820. if( gUnitLogLevel > 3 ) logBBAI(" ...fortifying in city");
  25821. getGroup()->pushMission(MISSION_FORTIFY);
  25822. return;
  25823. }
  25824. else
  25825. {
  25826. if( gUnitLogLevel > 3 ) logBBAI(" ...retreating to city");
  25827. if (AI_retreatToCity())
  25828. return;
  25829. }
  25830. }
  25831. }
  25832. }
  25833. bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
  25834. if (bDanger)
  25835. {
  25836. if (AI_retreatToCity())
  25837. {
  25838. return;
  25839. }
  25840. }
  25841. if (AI_heal())
  25842. {
  25843. return;
  25844. }
  25845. int iValue = 0;
  25846. int iBestValue = 0;
  25847. int iPathTurns;
  25848. bool bBonusRawMana = false;
  25849. bool bBonusMana = false;
  25850. //int iRange = 15;
  25851. CvPlot* pBestPlot = NULL;
  25852. BuildTypes eBuild = NO_BUILD;
  25853. BuildTypes eBestBuild = NO_BUILD;
  25854. CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
  25855. //ToDo - keep one spare raw mana node if we have more than X mana and are pursuing Tower victory (for metamagic node)
  25856. bool bReadytoBuild = false;
  25857. // loop through plots in range
  25858. // ToDo - make this a map search?
  25859. /*
  25860. for (int iX = -iRange; iX <= iRange; iX++)
  25861. {
  25862. for (int iY = -iRange; iY <= iRange; iY++)
  25863. {
  25864. */
  25865. {
  25866. for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  25867. {
  25868. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  25869. //CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
  25870. if (pLoopPlot != NULL)
  25871. {
  25872. if ( pLoopPlot->getOwner() == getOwner())
  25873. {
  25874. if (!pLoopPlot->isVisibleEnemyDefender(this) && !kPlayer.AI_getAnyPlotDanger(pLoopPlot))
  25875. {
  25876. if (pLoopPlot->getBonusType() != NO_BONUS)
  25877. {
  25878. bBonusRawMana = false;
  25879. bBonusMana = false;
  25880. // HARDCODE - should have some sort of global variable to let the AI know about mana - XML tag?
  25881. //if (GC.getBonusInfo(pLoopPlot->getBonusType()).getBonusClassType() == GC.getDefineINT("BONUSCLASS_MANA"))
  25882. if (GC.getBonusInfo(pLoopPlot->getBonusType()).isMana())
  25883. {
  25884. // check to make sure we don't check existing nodes
  25885. if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT)
  25886. {
  25887. bBonusMana = true;
  25888. }
  25889. else
  25890. {
  25891. if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).getBonusConvert() == NO_BONUS)
  25892. {
  25893. bBonusMana = true;
  25894. }
  25895. }
  25896. }
  25897. // HARDCODE
  25898. if (GC.getBonusInfo(pLoopPlot->getBonusType()).getBonusClassType() == GC.getDefineINT("BONUSCLASS_MANA_RAW"))
  25899. {
  25900. bBonusRawMana = true;
  25901. }
  25902. if (bBonusMana || bBonusRawMana)
  25903. {
  25904. // found mana, now check path
  25905. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  25906. {
  25907. // we can reach the mana, now make sure we have a build
  25908. bool bFoundBuild = false;
  25909. for (int iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
  25910. {
  25911. eBuild = ((BuildTypes)iJ);
  25912. if (canBuild(pLoopPlot, eBuild))
  25913. {
  25914. bFoundBuild = true;
  25915. break;
  25916. }
  25917. }
  25918. if (bFoundBuild)
  25919. {
  25920. iValue = 100 / (iPathTurns +1);
  25921. if (iValue > iBestValue)
  25922. {
  25923. pBestPlot = pLoopPlot;
  25924. iBestValue = iValue;
  25925. }
  25926. }
  25927. }
  25928. }
  25929. }
  25930. }
  25931. }
  25932. }
  25933. }
  25934. }
  25935. if (pBestPlot != NULL)
  25936. {
  25937. if (atPlot(pBestPlot))
  25938. {
  25939. if (isHasCasted()) // casting blocks mana builds
  25940. {
  25941. getGroup()->pushMission(MISSION_FORTIFY);
  25942. return;
  25943. }
  25944. iBestValue = 0;
  25945. eBestBuild = NO_BUILD;
  25946. // loop through various builds and find the best one
  25947. for (int iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
  25948. {
  25949. eBuild = ((BuildTypes)iJ);
  25950. if (canBuild(plot(), eBuild))
  25951. {
  25952. // we have to first get the improvement, then find out what mana this node will be converted to
  25953. ImprovementTypes eImprovement = (ImprovementTypes)GC.getBuildInfo(eBuild).getImprovement();
  25954. BonusTypes eNewBonus = (BonusTypes)GC.getImprovementInfo(eImprovement).getBonusConvert();
  25955. iValue = kPlayer.AI_bonusVal(eNewBonus) + 1;
  25956. if( gUnitLogLevel >= 3 )
  25957. {
  25958. logBBAI(" %S mana value: %d\n", GC.getBuildInfo((BuildTypes)eBuild).getDescription(), iValue);
  25959. }
  25960. if (iValue > iBestValue)
  25961. {
  25962. iBestValue = iValue;
  25963. eBestBuild = eBuild;
  25964. }
  25965. }
  25966. }
  25967. if (eBestBuild != NO_BUILD)
  25968. {
  25969. if( gUnitLogLevel >= 2 )
  25970. {
  25971. logBBAI(" %S (unit %d) building %S with value of %d at plot %d, %d", getName().GetCString(), getID(), GC.getBuildInfo((BuildTypes)eBestBuild).getDescription(), iBestValue, plot()->getX(), plot()->getY());
  25972. }
  25973. getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, false, false, MISSIONAI_BUILD, plot());
  25974. return;
  25975. }
  25976. }
  25977. else
  25978. {
  25979. if( gUnitLogLevel >= 3 )
  25980. {
  25981. logBBAI(" ...moving to mana node at plot %d, %d", pBestPlot->getX(), pBestPlot->getY());
  25982. }
  25983. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_2);
  25984. return;
  25985. }
  25986. }
  25987. CyUnit* pyUnit1 = new CyUnit(this);
  25988. CyArgsList argsList1;
  25989. argsList1.add(gDLL->getPythonIFace()->makePythonObject(pyUnit1)); // pass in unit class
  25990. long lResult=0;
  25991. gDLL->getPythonIFace()->callFunction(PYGameModule, "AI_Mage_UPGRADE_MANA", argsList1.makeFunctionArgs(), &lResult);
  25992. delete pyUnit1; // python fxn must not hold on to this pointer
  25993. if (lResult == 1)
  25994. {
  25995. getGroup()->pushMission(MISSION_SKIP);
  25996. return;
  25997. }
  25998. if (AI_moveIntoCity(5))
  25999. {
  26000. return;
  26001. }
  26002. if (AI_retreatToCity())
  26003. {
  26004. return;
  26005. }
  26006. if (AI_safety())
  26007. {
  26008. return;
  26009. }
  26010. getGroup()->pushMission(MISSION_SKIP);
  26011. return;
  26012. }
  26013. // this is called every turn once in DoTurnUnitsPre()
  26014. // Tholal note - lots of hardcode
  26015. void CvUnitAI::AI_mageCast()
  26016. {
  26017. CvCity* pCity;
  26018. pCity=this->plot()->getPlotCity();
  26019. // War Spells
  26020. if (canCast(GC.getInfoTypeForString("SPELL_REPAIR"),false))
  26021. {
  26022. cast(GC.getInfoTypeForString("SPELL_REPAIR"));
  26023. }
  26024. if (canCast(GC.getInfoTypeForString("SPELL_RUST"),false))
  26025. {
  26026. cast(GC.getInfoTypeForString("SPELL_RUST"));
  26027. }
  26028. if (canCast(GC.getInfoTypeForString("SPELL_SLOW"),false))
  26029. {
  26030. cast(GC.getInfoTypeForString("SPELL_SLOW"));
  26031. }
  26032. // Spells to permanently improve new Units
  26033. if (GET_PLAYER(getOwnerINLINE()).getCivilizationType() == GC.getInfoTypeForString("CIVILIZATION_BALSERAPHS"))
  26034. if (canCast(GC.getInfoTypeForString("SPELL_MUTATION"),false))
  26035. cast(GC.getInfoTypeForString("SPELL_MUTATION"));
  26036. if (canCast(GC.getInfoTypeForString("SPELL_FLAMING_ARROWS"),false))
  26037. cast(GC.getInfoTypeForString("SPELL_FLAMING_ARROWS"));
  26038. if (canCast(GC.getInfoTypeForString("SPELL_ENCHANTED_BLADE"),false))
  26039. cast(GC.getInfoTypeForString("SPELL_ENCHANTED_BLADE"));
  26040. // Spells to permanently improve the City
  26041. if (canCast(GC.getInfoTypeForString("SPELL_WALL_OF_STONE"),false))
  26042. if (pCity->getNumBuilding((BuildingTypes)GC.getInfoTypeForString("BUILDING_WALL_OF_STONE")) == 0)
  26043. cast(GC.getInfoTypeForString("SPELL_WALL_OF_STONE"));
  26044. if (canCast(GC.getInfoTypeForString("SPELL_INSPIRATION"),false))
  26045. if (pCity->getNumBuilding((BuildingTypes)GC.getInfoTypeForString("BUILDING_INSPIRATION")) == 0)
  26046. cast(GC.getInfoTypeForString("SPELL_INSPIRATION"));
  26047. if (canCast(GC.getInfoTypeForString("SPELL_HOPE"),false))
  26048. if (pCity->getNumBuilding((BuildingTypes)GC.getInfoTypeForString("BUILDING_HOPE")) == 0)
  26049. cast(GC.getInfoTypeForString("SPELL_HOPE"));
  26050. // Spells to boost the Garrison Units
  26051. if (canCast(GC.getInfoTypeForString("SPELL_DANCE_OF_BLADES"),false))
  26052. cast(GC.getInfoTypeForString("SPELL_DANCE_OF_BLADES"));
  26053. if (canCast(GC.getInfoTypeForString("SPELL_BLUR"),false))
  26054. cast(GC.getInfoTypeForString("SPELL_BLUR"));
  26055. }
  26056. // MNAI - modified so that this function is used by the AI to keep its defensive Adept units spread out to different cities
  26057. bool CvUnitAI::AI_mageMove()
  26058. {
  26059. // short-circuit this function for barbarians unless we're playing with the Raging Barbarians option
  26060. if (isBarbarian() && !GC.getGameINLINE().isOption(GAMEOPTION_RAGING_BARBARIANS))
  26061. {
  26062. return false;
  26063. }
  26064. if( gUnitLogLevel > 2 ) logBBAI(" ...checking MageMove()", getID());
  26065. if (getUnitCombatType() != GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
  26066. {
  26067. AI_setUnitAIType(UNITAI_ATTACK_CITY);
  26068. AI_setGroupflag(GROUPFLAG_CONQUEST);
  26069. return true;
  26070. }
  26071. else if (GC.getUnitInfo(getUnitType()).getTier() > 2)
  26072. {
  26073. if( gUnitLogLevel > 2 ) logBBAI(" ...switching to WarWizard");
  26074. AI_setUnitAIType(UNITAI_WARWIZARD);
  26075. AI_setGroupflag(GROUPFLAG_CONQUEST);
  26076. return true;
  26077. }
  26078. if (plot()->plotCount(PUF_isUnitAIType, UNITAI_MAGE, -1, NO_PLAYER, getTeam()) > 1)
  26079. {
  26080. if( gUnitLogLevel > 2 ) logBBAI(" ...current location is too crowded");
  26081. CvCity* pLoopCity;
  26082. CvCity* pBestCity = NULL;
  26083. int iValue = 0;
  26084. int iBestValue = 0;
  26085. int iLoop;
  26086. for (pLoopCity = GET_PLAYER(getOwner()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwner()).nextCity(&iLoop))
  26087. {
  26088. if (pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_MAGE, -1, NO_PLAYER, getTeam()) == 0)
  26089. {
  26090. int iPathTurns;
  26091. if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
  26092. {
  26093. iValue = (pLoopCity->getPopulation() * 10) / (iPathTurns + 1);
  26094. if (pLoopCity->isCapital())
  26095. {
  26096. iValue *= 2;
  26097. }
  26098. if (iValue > iBestValue)
  26099. {
  26100. iBestValue = iValue;
  26101. pBestCity = pLoopCity;
  26102. }
  26103. }
  26104. }
  26105. }
  26106. if (pBestCity != NULL)
  26107. {
  26108. if (!atPlot(pBestCity->plot()))
  26109. {
  26110. if( gUnitLogLevel > 2 ) logBBAI(" ....Mage moving to %S (%d, %d)", pBestCity->getName().GetCString(), pBestCity->plot()->getX_INLINE(), pBestCity->plot()->getY_INLINE());
  26111. getGroup()->pushMission(MISSION_MOVE_TO, pBestCity->plot()->getX_INLINE(), pBestCity->plot()->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
  26112. return true;
  26113. }
  26114. }
  26115. }
  26116. return false;
  26117. }
  26118. void CvUnitAI::AI_terraformerMove() // lfgr 03/2021: Tweaked
  26119. {
  26120. if( gUnitLogLevel >= 3)
  26121. {
  26122. logBBAI(" %S (Unit %d) starting terraformer move\n", getName().GetCString(), getID());
  26123. }
  26124. if (!isChanneler())
  26125. {
  26126. if( gUnitLogLevel >= 3)
  26127. {
  26128. logBBAI(" WARNING! Not a Channeler! Resetting AI for this unit.\n");
  26129. }
  26130. AI_setUnitAIType((UnitAITypes)m_pUnitInfo->getDefaultUnitAIType());
  26131. AI_setGroupflag(GROUPFLAG_NONE);
  26132. return;
  26133. }
  26134. if (GET_PLAYER(getOwnerINLINE()).getDisableSpellcasting() > 0)
  26135. {
  26136. if (AI_retreatToCity())
  26137. {
  26138. if( gUnitLogLevel >= 3)
  26139. {
  26140. logBBAI(" ...retreating to city due to disabled spellcasting\n");
  26141. }
  26142. return;
  26143. }
  26144. }
  26145. if (plot()->isCity() && (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3)))
  26146. {
  26147. getGroup()->pushMission(MISSION_SKIP);
  26148. return;
  26149. }
  26150. CyUnit* pyUnit1 = new CyUnit(this);
  26151. CyArgsList argsList1;
  26152. argsList1.add(gDLL->getPythonIFace()->makePythonObject(pyUnit1)); // pass in unit class
  26153. long lResult=-1;
  26154. gDLL->getPythonIFace()->callFunction(PYGameModule, "AI_MageTurn", argsList1.makeFunctionArgs(), &lResult);
  26155. delete pyUnit1; // python fxn must not hold on to this pointer
  26156. if( gUnitLogLevel >= 3)
  26157. {
  26158. logBBAI(" ...python result of %d\n", lResult);
  26159. if (isHasCasted())
  26160. {
  26161. logBBAI(" ...unit has already cast a spell this turn\n");
  26162. }
  26163. }
  26164. if (lResult == 0) // Python found nothing to do
  26165. {
  26166. if (GET_TEAM(getTeam()).getAtWarCount(false) > 0) //nothing to do and we're at war
  26167. {
  26168. if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
  26169. {
  26170. if (isDeBuffer() || isBuffer() || isDirectDamageCaster())
  26171. {
  26172. AI_setUnitAIType(UNITAI_WARWIZARD);
  26173. }
  26174. else
  26175. {
  26176. AI_setUnitAIType(UNITAI_MAGE);
  26177. }
  26178. }
  26179. else
  26180. {
  26181. AI_setUnitAIType((UnitAITypes)m_pUnitInfo->getDefaultUnitAIType());
  26182. }
  26183. }
  26184. if (AI_retreatToCity())
  26185. {
  26186. return;
  26187. }
  26188. getGroup()->pushMission(MISSION_SKIP);
  26189. return;
  26190. }
  26191. else
  26192. {
  26193. if( !isHasCasted() && !GET_PLAYER(getOwnerINLINE()).isHuman() )
  26194. {
  26195. // Let's try to cast a random spell!
  26196. int iSpell = chooseSpell();
  26197. if (iSpell != NO_SPELL)
  26198. {
  26199. cast(iSpell);
  26200. return;
  26201. }
  26202. }
  26203. if( isHasCasted() )
  26204. {
  26205. // We're done. If we wanted to move somehwere, we'd have done this in python.
  26206. getGroup()->pushMission(MISSION_SKIP); // LFGR_TODO: This does nothing if unit is busy!
  26207. return;
  26208. }
  26209. }
  26210. // Tholal note: terraformers can get stuck in loop, if they've casted, are at a terraformable plot and have movement left
  26211. if (isHasCasted())
  26212. {
  26213. getGroup()->pushMission(MISSION_SENTRY); // LFGR_TODO: This does nothing if unit is busy!
  26214. //finishMoves();
  26215. }
  26216. return;
  26217. }
  26218. //returns true if the Unit can Summon stuff
  26219. bool CvUnitAI::isSummoner()
  26220. {
  26221. if (!isChanneler())
  26222. {
  26223. return false;
  26224. }
  26225. // LFGR_TODO: Use canCastWithCurrentPromotions
  26226. for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
  26227. {
  26228. if (GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType() != NO_UNIT)
  26229. {
  26230. if( canCastWithCurrentPromotions( (SpellTypes) iSpell ) )
  26231. {
  26232. return true;
  26233. }
  26234. }
  26235. }
  26236. return false;
  26237. }
  26238. void CvUnitAI::AI_SummonCast()
  26239. {
  26240. if (isHasCasted())
  26241. {
  26242. return;
  26243. }
  26244. if (!isSummoner())
  26245. {
  26246. return;
  26247. }
  26248. int iBestValue = 0;
  26249. int iBestSpell = NO_SPELL;
  26250. int iTempValue = 0;
  26251. int iValue = 0;
  26252. CvPlot* pLoopPlot;
  26253. for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
  26254. {
  26255. iValue = 0;
  26256. if (GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType() != NO_UNIT)
  26257. {
  26258. if (canCast(iSpell, false))
  26259. {
  26260. bool bPermSummon = GC.getSpellInfo((SpellTypes)iSpell).isPermanentUnitCreate();
  26261. bool bEnemy = false;
  26262. if (!bPermSummon)
  26263. {
  26264. int iMoveRange = GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getMoves() + getExtraSpellMove();
  26265. for (int i = -iMoveRange; i <= iMoveRange; ++i)
  26266. {
  26267. for (int j = -iMoveRange; j <= iMoveRange; ++j)
  26268. {
  26269. pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
  26270. if (NULL != pLoopPlot)
  26271. {
  26272. if (pLoopPlot->isVisibleEnemyUnit(this))
  26273. {
  26274. bEnemy = true;
  26275. }
  26276. }
  26277. }
  26278. }
  26279. }
  26280. if (bEnemy || bPermSummon)
  26281. {
  26282. iTempValue = GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getCombat();
  26283. for (int iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
  26284. {
  26285. iTempValue += GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getDamageTypeCombat(iI);
  26286. }
  26287. iTempValue *= 100;
  26288. iTempValue *= GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitNum();
  26289. iTempValue += GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getCollateralDamage() * GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getCollateralDamageMaxUnits();
  26290. iTempValue *= GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getTier();
  26291. iValue += iTempValue;
  26292. }
  26293. // Tholal AI - Floating Eyes
  26294. if (GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getNumSeeInvisibleTypes() > 0)
  26295. {
  26296. iValue += 100;
  26297. }
  26298. }
  26299. }
  26300. if (iValue > iBestValue)
  26301. {
  26302. iBestValue = iValue;
  26303. iBestSpell = iSpell;
  26304. }
  26305. }
  26306. if (iBestSpell != NO_SPELL)
  26307. {
  26308. cast(iBestSpell);
  26309. }
  26310. }
  26311. //returns true if the Unit can Damage stuff
  26312. // lfgr AI 04/2021: Ignores isHasCasted and uses canCastWithCurrentPromotions instead of canCast.
  26313. bool CvUnitAI::isDirectDamageCaster()
  26314. {
  26315. if (!isChanneler())
  26316. {
  26317. return false;
  26318. }
  26319. for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
  26320. {
  26321. if (GC.getSpellInfo((SpellTypes)iSpell).getDamage() > 0)
  26322. {
  26323. if (canCastWithCurrentPromotions((SpellTypes)iSpell))
  26324. {
  26325. return true;
  26326. }
  26327. }
  26328. }
  26329. return false;
  26330. }
  26331. //Make sure iNumSummonSpells is big enough
  26332. //Spell will only be Cast if it can damage Threshold Units
  26333. void CvUnitAI::AI_DirectDamageCast(int Threshold)
  26334. {
  26335. if (isHasCasted())
  26336. {
  26337. return;
  26338. }
  26339. if (!isDirectDamageCaster())
  26340. {
  26341. return;
  26342. }
  26343. int iBestSpell = NO_SPELL;
  26344. int iBestValue = 0;
  26345. int iDmg = 0;
  26346. int iDmgLimit = 0;
  26347. int iRange = 0;
  26348. int iValue = 0;
  26349. CvPlot* pLoopPlot;
  26350. CvUnit* pLoopUnit;
  26351. CLLNode<IDInfo>* pUnitNode;
  26352. for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
  26353. {
  26354. iRange = GC.getSpellInfo((SpellTypes)iSpell).getRange();
  26355. iValue = 0;
  26356. if (GC.getSpellInfo((SpellTypes)iSpell).getDamage() != 0)
  26357. {
  26358. if (canCast(iSpell, false))
  26359. {
  26360. iDmg = GC.getSpellInfo((SpellTypes)iSpell).getDamage();
  26361. iDmgLimit = GC.getSpellInfo((SpellTypes)iSpell).getDamageLimit();
  26362. for (int i = -iRange; i <= iRange; ++i)
  26363. {
  26364. for (int j = -iRange; j <= iRange; ++j)
  26365. {
  26366. pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
  26367. if (NULL != pLoopPlot)
  26368. {
  26369. if (pLoopPlot->getX() != plot()->getX() || pLoopPlot->getY() != plot()->getY())
  26370. {
  26371. pUnitNode = pLoopPlot->headUnitNode();
  26372. while (pUnitNode != NULL)
  26373. {
  26374. pLoopUnit = ::getUnit(pUnitNode->m_data);
  26375. pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
  26376. if (!pLoopUnit->isImmuneToSpell(this, iSpell))
  26377. {
  26378. if (pLoopUnit->isEnemy(getTeam()))
  26379. {
  26380. if (pLoopUnit->getDamage() < iDmgLimit)
  26381. {
  26382. iValue += iDmg * 10;
  26383. }
  26384. }
  26385. if (pLoopUnit->getTeam() == getTeam())
  26386. {
  26387. iValue -= iDmg * 20;
  26388. }
  26389. if (pLoopUnit->getTeam() != getTeam() && pLoopUnit->isEnemy(getTeam()) == false)
  26390. {
  26391. iValue -= 1000;
  26392. }
  26393. }
  26394. }
  26395. }
  26396. }
  26397. }
  26398. }
  26399. }
  26400. }
  26401. if (iValue > iBestValue)
  26402. {
  26403. iBestValue = iValue;
  26404. iBestSpell = iSpell;
  26405. }
  26406. }
  26407. if (iBestSpell != NO_SPELL)
  26408. {
  26409. cast(iBestSpell);
  26410. }
  26411. }
  26412. //returns true if the Unit can Debuff stuff
  26413. bool CvUnitAI::isDeBuffer()
  26414. {
  26415. if (!isChanneler())
  26416. {
  26417. return false;
  26418. }
  26419. for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
  26420. {
  26421. bool bDebuffPromo = false;
  26422. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1() != NO_PROMOTION)
  26423. {
  26424. if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1()).getAIWeight() < 0)
  26425. {
  26426. bDebuffPromo = true;
  26427. }
  26428. }
  26429. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
  26430. {
  26431. if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2()).getAIWeight() < 0)
  26432. {
  26433. bDebuffPromo = true;
  26434. }
  26435. }
  26436. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
  26437. {
  26438. if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3()).getAIWeight() < 0)
  26439. {
  26440. bDebuffPromo = true;
  26441. }
  26442. }
  26443. if (bDebuffPromo)
  26444. {
  26445. // lfgr AI 04/2021: Use canCastWithCurrentPromotions
  26446. if( canCastWithCurrentPromotions( (SpellTypes) iSpell ) )
  26447. {
  26448. return true;
  26449. }
  26450. }
  26451. }
  26452. return false;
  26453. }
  26454. void CvUnitAI::AI_DeBuffCast()
  26455. {
  26456. if (this->m_bHasCasted)
  26457. return;
  26458. if (!isDeBuffer())
  26459. return;
  26460. int iBestSpell = NO_SPELL;
  26461. int iBestValue = 0;
  26462. int iValue = 0;
  26463. for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
  26464. {
  26465. iValue = 0;
  26466. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1() != NO_PROMOTION)
  26467. {
  26468. if (canCast(iSpell, false))
  26469. {
  26470. iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1()).getAIWeight();
  26471. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
  26472. {
  26473. iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2()).getAIWeight();
  26474. }
  26475. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
  26476. {
  26477. iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3()).getAIWeight();
  26478. }
  26479. }
  26480. }
  26481. if (iValue < iBestValue)
  26482. {
  26483. iBestValue = iValue;
  26484. iBestSpell = iSpell;
  26485. }
  26486. }
  26487. if (iBestSpell != NO_SPELL)
  26488. {
  26489. cast(iBestSpell);
  26490. }
  26491. }
  26492. bool CvUnitAI::isMovementCaster()
  26493. {
  26494. if (AI_getUnitAIType()==UNITAI_MAGE || AI_getUnitAIType()==UNITAI_TERRAFORMER || AI_getUnitAIType()==UNITAI_FEASTING || AI_getUnitAIType()==UNITAI_INQUISITOR
  26495. || AI_getUnitAIType()==UNITAI_MANA_UPGRADE)
  26496. {
  26497. return false;
  26498. }
  26499. if (AI_getUnitAIType() == UNITAI_HERO && isSummoner())
  26500. {
  26501. return false;
  26502. }
  26503. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_BODY1")))
  26504. return true;
  26505. return false;
  26506. }
  26507. void CvUnitAI::AI_MovementCast()
  26508. {
  26509. if (canCast(GC.getInfoTypeForString("SPELL_HASTE"),false))
  26510. cast(GC.getInfoTypeForString("SPELL_HASTE"));
  26511. }
  26512. bool CvUnitAI::isBuffer()
  26513. {
  26514. if (!isChanneler())
  26515. {
  26516. return false;
  26517. }
  26518. for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
  26519. {
  26520. bool bBuffPromo = false;
  26521. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1() != NO_PROMOTION)
  26522. {
  26523. if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1()).getAIWeight() > 0)
  26524. {
  26525. bBuffPromo = true;
  26526. }
  26527. }
  26528. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
  26529. {
  26530. if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2()).getAIWeight() > 0)
  26531. {
  26532. bBuffPromo = true;
  26533. }
  26534. }
  26535. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
  26536. {
  26537. if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3()).getAIWeight() > 0)
  26538. {
  26539. bBuffPromo = true;
  26540. }
  26541. }
  26542. if (bBuffPromo)
  26543. {
  26544. // lfgr AI 04/2021: Use canCastWithCurrentPromotions
  26545. if( canCastWithCurrentPromotions( (SpellTypes) iSpell ) )
  26546. {
  26547. return true;
  26548. }
  26549. }
  26550. }
  26551. return false;
  26552. }
  26553. // This is run often, so lets keep things simple
  26554. void CvUnitAI::AI_BuffCast()
  26555. {
  26556. if (isHasCasted())
  26557. {
  26558. return;
  26559. }
  26560. if (!isBuffer()) // LFGR_TODO: Seems redundant
  26561. {
  26562. return;
  26563. }
  26564. int iBestSpell = NO_SPELL;
  26565. int iBestValue = 0;
  26566. int iValue = 0;
  26567. for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
  26568. {
  26569. iValue = 0;
  26570. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1() != NO_PROMOTION)
  26571. {
  26572. if (canCast(iSpell, false))
  26573. {
  26574. iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1()).getAIWeight();
  26575. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
  26576. {
  26577. iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2()).getAIWeight();
  26578. }
  26579. if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
  26580. {
  26581. iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3()).getAIWeight();
  26582. }
  26583. }
  26584. }
  26585. if (iValue > iBestValue)
  26586. {
  26587. iBestValue = iValue;
  26588. iBestSpell = iSpell;
  26589. }
  26590. }
  26591. if (iBestSpell != NO_SPELL)
  26592. {
  26593. cast(iBestSpell);
  26594. }
  26595. }
  26596. bool CvUnitAI::isSuicideSummon()
  26597. {
  26598. return m_bSuicideSummon;
  26599. }
  26600. void CvUnitAI::setSuicideSummon(bool newvalue)
  26601. {
  26602. m_bSuicideSummon=newvalue;
  26603. }
  26604. bool CvUnitAI::isPermanentSummon()
  26605. {
  26606. return m_bPermanentSummon;
  26607. }
  26608. void CvUnitAI::setPermanentSummon(bool newvalue)
  26609. {
  26610. m_bPermanentSummon=newvalue;
  26611. }
  26612. // Tholal AI - rewritten to help with Religious victory strats
  26613. void CvUnitAI::AI_InquisitionMove()
  26614. {
  26615. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  26616. if( gUnitLogLevel >= 2 )
  26617. {
  26618. logBBAI(" %S (unit %d) starting InquisitionMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
  26619. }
  26620. if (kOwner.AI_isDoVictoryStrategy(AI_VICTORY_RELIGION2) && (AI_getUnitAIType() != UNITAI_HERO))
  26621. {
  26622. int iNeededInquisitors = (GET_PLAYER(getOwnerINLINE()).getNumCities() / 5);
  26623. iNeededInquisitors = std::max(1, iNeededInquisitors);
  26624. if (kOwner.AI_getNumAIUnits(UNITAI_INQUISITOR) < iNeededInquisitors)
  26625. {
  26626. joinGroup(NULL);
  26627. AI_setGroupflag(GROUPFLAG_NONE);
  26628. AI_setUnitAIType(UNITAI_INQUISITOR);
  26629. }
  26630. }
  26631. if (AI_getUnitAIType() != UNITAI_INQUISITOR)
  26632. {
  26633. return;
  26634. }
  26635. CvCity* pLoopCity;
  26636. CvCity* pBestCity = NULL;
  26637. CvPlot* pBestPlot;
  26638. int iValue = 0;
  26639. int iBestValue = 0;
  26640. int iLoop;
  26641. int iStateRel = kOwner.getStateReligion();
  26642. // Inquisitors should work alone
  26643. if (getGroup()->getNumUnits() > 1)
  26644. {
  26645. joinGroup(NULL);
  26646. }
  26647. if (iStateRel != NO_RELIGION)
  26648. {
  26649. if (canCast((SpellTypes)GC.getInfoTypeForString("SPELL_INQUISITION"), false))
  26650. {
  26651. if (plot()->plotCount(PUF_isUnitAIType, UNITAI_INQUISITOR, -1, NO_PLAYER, getTeam()) == 1)
  26652. {
  26653. cast((SpellTypes)GC.getInfoTypeForString("SPELL_INQUISITION"));
  26654. return;
  26655. }
  26656. }
  26657. bool bValidTargetForInquisition = false;
  26658. int iNumHeathenRels = 0;
  26659. for (int iJ = 0; iJ < MAX_PLAYERS; iJ++)
  26660. {
  26661. if (GET_PLAYER((PlayerTypes)iJ).isAlive())
  26662. {
  26663. if ( GET_PLAYER((PlayerTypes)iJ).getStateReligion() == iStateRel)
  26664. {
  26665. for (pLoopCity = GET_PLAYER((PlayerTypes)iJ).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iJ).nextCity(&iLoop))
  26666. {
  26667. if (pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_INQUISITOR, -1, NO_PLAYER, getTeam()) == 0)
  26668. {
  26669. int iPathTurns;
  26670. if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
  26671. {
  26672. bValidTargetForInquisition = false;
  26673. iNumHeathenRels = 0;
  26674. for (int iTarget=0; iTarget < GC.getNumReligionInfos(); iTarget++)
  26675. {
  26676. if (iStateRel != ((ReligionTypes)iTarget) && pLoopCity->isHasReligion((ReligionTypes)iTarget) && (!pLoopCity->isHolyCity((ReligionTypes)iTarget)))
  26677. {
  26678. bValidTargetForInquisition = true;
  26679. iNumHeathenRels++;
  26680. }
  26681. }
  26682. if (bValidTargetForInquisition)
  26683. {
  26684. iValue = pLoopCity->getPopulation() * (iNumHeathenRels * 2);
  26685. if (pLoopCity->isHolyCity((ReligionTypes)iStateRel))
  26686. {
  26687. iValue *= 2;
  26688. }
  26689. iValue *= 2;
  26690. iValue /= iPathTurns;
  26691. if (iValue > iBestValue)
  26692. {
  26693. iBestValue = iValue;
  26694. pBestCity = pLoopCity;
  26695. }
  26696. }
  26697. }
  26698. }
  26699. }
  26700. }
  26701. }
  26702. }
  26703. if (pBestCity != NULL)
  26704. {
  26705. pBestPlot = pBestCity->plot();
  26706. logBBAI(" ...targeting %S for Inquisition (plot %d, %d)", pBestCity->getName().GetCString(), pBestCity->getX(), pBestCity->getY());
  26707. if (atPlot(pBestPlot))
  26708. {
  26709. if (canCast((SpellTypes)GC.getInfoTypeForString("SPELL_INQUISITION"), false))
  26710. {
  26711. if (plot()->plotCount(PUF_isUnitAIType, UNITAI_INQUISITOR, -1, NO_PLAYER, getTeam()) == 1)
  26712. {
  26713. logBBAI(" ...Inquisitioning");
  26714. cast((SpellTypes)GC.getInfoTypeForString("SPELL_INQUISITION"));
  26715. return;
  26716. }
  26717. else
  26718. {
  26719. if( gUnitLogLevel > 2 ) logBBAI(" ...too many Inquisitioners at pBestPlot");
  26720. }
  26721. }
  26722. }
  26723. else
  26724. {
  26725. logBBAI(" ...moving to city");
  26726. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
  26727. return;
  26728. }
  26729. }
  26730. }
  26731. if (AI_guardCity())
  26732. {
  26733. return;
  26734. }
  26735. if (AI_anyAttack(1, 90))
  26736. {
  26737. return;
  26738. }
  26739. if (AI_retreatToCity())
  26740. {
  26741. return;
  26742. }
  26743. if (AI_safety())
  26744. {
  26745. return;
  26746. }
  26747. //getGroup()->pushMission(MISSION_SKIP);
  26748. return;
  26749. }
  26750. void CvUnitAI::AI_SvartalfarKidnapMove()
  26751. {
  26752. if( gUnitLogLevel >= 2 )
  26753. {
  26754. logBBAI(" %S (unit %d) starting SvartfalarKidnapMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
  26755. }
  26756. int iSpell = GC.getInfoTypeForString("SPELL_KIDNAP");
  26757. if (iSpell != NO_SPELL && canCast(iSpell,false))
  26758. {
  26759. logBBAI(" ..Kidnapping at plot %d, %d!", plot()->getX(), plot()->getY());
  26760. cast(iSpell);
  26761. }
  26762. CvPlot* pBestPlot=NULL;
  26763. int iValue;
  26764. int iBestValue=100;
  26765. for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  26766. {
  26767. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  26768. if(pLoopPlot)
  26769. {
  26770. if (AI_plotValid(pLoopPlot))
  26771. {
  26772. if(pLoopPlot->isCity())
  26773. {
  26774. if(pLoopPlot->getArea()==getArea() && pLoopPlot->getTeam()!=getTeam())
  26775. {
  26776. if (!pLoopPlot->isVisibleEnemyUnit(this))
  26777. {
  26778. CvCity* pLoopCity=pLoopPlot->getPlotCity();
  26779. bool bValidTargetForKidnap=true;
  26780. //too bad this is hardcoded in the Spell
  26781. SpecialistTypes iGreatPriest=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_PRIEST");
  26782. SpecialistTypes iGreatArtist=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_ARTIST");
  26783. SpecialistTypes iGreatMerchant=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_MERCHANT");
  26784. SpecialistTypes iGreatEngineer=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_ENGINEER");
  26785. SpecialistTypes iGreatScientist=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_SCIENTIST");
  26786. int iCountSpecialists=0;
  26787. if(iGreatPriest!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatPriest);
  26788. if(iGreatArtist!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatArtist);
  26789. if(iGreatMerchant!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatMerchant);
  26790. if(iGreatEngineer!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatEngineer);
  26791. if(iGreatScientist!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatScientist);
  26792. if (iCountSpecialists==0)
  26793. {
  26794. bValidTargetForKidnap=false;
  26795. }
  26796. else if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude(pLoopPlot->getOwnerINLINE())>=ATTITUDE_PLEASED)
  26797. {
  26798. if((GET_TEAM(getTeam()).getPower(true)*2)<(GET_TEAM(pLoopPlot->getTeam()).getPower(true)*3))
  26799. {
  26800. //not enough Power to risk declare war
  26801. bValidTargetForKidnap=false;
  26802. }
  26803. }
  26804. else
  26805. {
  26806. if((GET_TEAM(getTeam()).getPower(true)*3)<(GET_TEAM(pLoopPlot->getTeam()).getPower(true)*2))
  26807. {
  26808. //not enough Power to risk declare war
  26809. bValidTargetForKidnap=false;
  26810. }
  26811. }
  26812. if (bValidTargetForKidnap && generatePath(pLoopPlot,0,true,&iValue))
  26813. {
  26814. if(iValue<iBestValue)
  26815. {
  26816. pBestPlot=pLoopPlot;
  26817. iBestValue=iValue;
  26818. }
  26819. }
  26820. }
  26821. }
  26822. }
  26823. }
  26824. }
  26825. }
  26826. if (pBestPlot!=NULL)
  26827. {
  26828. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
  26829. return;
  26830. }
  26831. getGroup()->pushMission(MISSION_SKIP);
  26832. return;
  26833. }
  26834. void CvUnitAI::AI_ShadeMove()
  26835. {
  26836. const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
  26837. if( gUnitLogLevel >= 2 )
  26838. {
  26839. logBBAI(" %S (unit %d) starting Shade move (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
  26840. }
  26841. if (getGroup()->getNumUnits() > 1)
  26842. {
  26843. if( gUnitLogLevel >= 2 )
  26844. {
  26845. logBBAI(" ...degrouping");
  26846. }
  26847. AI_setGroupflag(GROUPFLAG_NONE);
  26848. joinGroup(NULL);
  26849. }
  26850. if (AI_join())
  26851. {
  26852. return;
  26853. }
  26854. if (kOwner.getCapitalCity() != NULL)
  26855. {
  26856. const CvPlot* pPlot = kOwner.getCapitalCity()->plot();
  26857. int iPathTurns;
  26858. if (generatePath(pPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
  26859. {
  26860. logBBAI(" ...moving to capital");
  26861. getGroup()->pushMission(MISSION_MOVE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
  26862. return;
  26863. }
  26864. }
  26865. if (AI_retreatToCity())
  26866. {
  26867. return;
  26868. }
  26869. }
  26870. /*************************************************************************************************/
  26871. /** Skyre Mod **/
  26872. /** BETTER AI (Lanun Pirate Coves) merged Sephi **/
  26873. /** **/
  26874. /*************************************************************************************************/
  26875. bool CvUnitAI::AI_buildPirateCove()
  26876. {
  26877. PROFILE_FUNC();
  26878. SpellTypes eCoveSpell = (SpellTypes)GC.getDefineINT("PIRATE_COVE_SPELL");
  26879. if (eCoveSpell == NO_SPELL)
  26880. {
  26881. return false;
  26882. }
  26883. std::vector<CvPlot*> apGoodPlots;
  26884. int iBestPlotValue = 0;
  26885. for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
  26886. {
  26887. CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
  26888. if (AI_plotValid(pLoopPlot))
  26889. {
  26890. if (pLoopPlot->getOwnerINLINE() != getOwnerINLINE() || pLoopPlot->getWorkingCity() == NULL)
  26891. {
  26892. continue;
  26893. }
  26894. if (pLoopPlot->area() != area() && !plot()->isAdjacentToArea(pLoopPlot->area()))
  26895. {
  26896. continue;
  26897. }
  26898. if (pLoopPlot->isVisibleEnemyUnit(this))
  26899. {
  26900. continue;
  26901. }
  26902. if (!pLoopPlot->isPirateCoveValid(getOwnerINLINE()))
  26903. {
  26904. continue;
  26905. }
  26906. if (!atPlot(pLoopPlot) && !canMoveInto(pLoopPlot))
  26907. {
  26908. continue;
  26909. }
  26910. // MNAI (by Red Key) - smarter cove placement
  26911. int idX = std::abs(pLoopPlot->getX() - pLoopPlot->getWorkingCity()->getX());
  26912. int idY = std::abs(pLoopPlot->getY() - pLoopPlot->getWorkingCity()->getY());
  26913. int iPlotValue = std::max(idX,idY) * 10 + std::min(idX,idY);
  26914. iPlotValue -= pLoopPlot->getNumCultureRangeCities(getOwner());
  26915. int iValueModifier = 1;
  26916. for (int iX = -3; iX <= 3; iX++)
  26917. {
  26918. for (int iY = -3; iY <= 3; iY++)
  26919. {
  26920. if(std::abs(iX) != 3 || std::abs(iY) != 3)
  26921. {
  26922. CvPlot* pSearchPlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iX, iY);
  26923. if (pSearchPlot != NULL && pSearchPlot->isPirateCove())
  26924. {
  26925. iValueModifier++;
  26926. }
  26927. }
  26928. }
  26929. }
  26930. iPlotValue *= iValueModifier;
  26931. // End MNAI
  26932. if (iPlotValue > iBestPlotValue)
  26933. {
  26934. apGoodPlots.clear();
  26935. apGoodPlots.push_back(pLoopPlot);
  26936. iBestPlotValue = iPlotValue;
  26937. }
  26938. else if (iPlotValue == iBestPlotValue)
  26939. {
  26940. apGoodPlots.push_back(pLoopPlot);
  26941. }
  26942. }
  26943. }
  26944. CvPlot* pBestPlot = NULL;
  26945. if (!apGoodPlots.empty())
  26946. {
  26947. int iShortestDistance = MAX_INT;
  26948. std::vector<CvPlot*>::iterator it;
  26949. for (it = apGoodPlots.begin(); it != apGoodPlots.end(); ++it)
  26950. {
  26951. int iPathTurns;
  26952. generatePath(*it, 0, true, &iPathTurns);
  26953. if (iPathTurns < iShortestDistance)
  26954. {
  26955. pBestPlot = *it;
  26956. iShortestDistance = iPathTurns;
  26957. }
  26958. }
  26959. }
  26960. if (pBestPlot)
  26961. {
  26962. if (plot() != pBestPlot)
  26963. {
  26964. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_BUILD, pBestPlot);
  26965. }
  26966. else
  26967. {
  26968. if (canCast(eCoveSpell, false))
  26969. {
  26970. cast(eCoveSpell);
  26971. }
  26972. //getGroup()->pushMission(MISSION_SKIP);
  26973. }
  26974. return true;
  26975. }
  26976. return false;
  26977. }
  26978. /*************************************************************************************************/
  26979. /** END **/
  26980. /*************************************************************************************************/
  26981. // Tholal AI - New functions
  26982. // Hardcode!
  26983. bool CvUnitAI::isInquisitor()
  26984. {
  26985. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_INQUISITOR")))
  26986. return true;
  26987. return false;
  26988. }
  26989. bool CvUnitAI::isChanneler()
  26990. {
  26991. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING1")))
  26992. return true;
  26993. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING2")))
  26994. return true;
  26995. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING3")))
  26996. return true;
  26997. return false;
  26998. }
  26999. // Priest check
  27000. bool CvUnitAI::isDivine()
  27001. {
  27002. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_DIVINE")))
  27003. return true;
  27004. return false;
  27005. }
  27006. bool CvUnitAI::isVampire()
  27007. {
  27008. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_VAMPIRE")))
  27009. return true;
  27010. return false;
  27011. }
  27012. bool CvUnitAI::isIllusionary()
  27013. {
  27014. int iI;
  27015. for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
  27016. {
  27017. if (isHasPromotion((PromotionTypes)iI))
  27018. {
  27019. if (GC.getPromotionInfo((PromotionTypes)iI).isRace() && GC.getPromotionInfo((PromotionTypes)iI).getCombatHealPercent() == 100)
  27020. {
  27021. return true;
  27022. }
  27023. }
  27024. }
  27025. return false;
  27026. }
  27027. int CvUnitAI::getChannelingLevel()
  27028. {
  27029. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING1")))
  27030. return 1;
  27031. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING2")))
  27032. return 2;
  27033. if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING3")))
  27034. return 3;
  27035. return 0;
  27036. }
  27037. // End Tholal AI
  27038. // ALN lairguards Start
  27039. void CvUnitAI::AI_lairGuardianMove()
  27040. {
  27041. // only barbarians should use this AI
  27042. if (!isBarbarian())
  27043. {
  27044. joinGroup(NULL);
  27045. AI_setUnitAIType(UNITAI_ATTACK);
  27046. return;
  27047. }
  27048. CvPlot* pPlot = plot();
  27049. if (pPlot->isLair(false, isAnimal()))
  27050. {
  27051. getGroup()->pushMission(MISSION_SKIP);
  27052. return;
  27053. }
  27054. // go to any adjacent lairs
  27055. if (AI_seekLair(1))
  27056. {
  27057. return;
  27058. }
  27059. // opportunistic attacks if not on a lair
  27060. if (AI_anyAttack(1, 55))
  27061. {
  27062. return;
  27063. }
  27064. // if not on a lair, look for one in the area
  27065. if (AI_seekLair(6))
  27066. {
  27067. return;
  27068. }
  27069. if (AI_heal())
  27070. {
  27071. return;
  27072. }
  27073. if (AI_patrol())
  27074. {
  27075. return;
  27076. }
  27077. if (AI_safety())
  27078. {
  27079. return;
  27080. }
  27081. getGroup()->pushMission(MISSION_SKIP);
  27082. return;
  27083. }
  27084. // ALN End
  27085. bool CvUnitAI::AI_seekLair(int iRange)
  27086. {
  27087. int iDX;
  27088. int iDY;
  27089. int iPathTurns;
  27090. int iValue = 0;
  27091. int iBestValue = 0;
  27092. int iSearchRange = baseMoves() * iRange;
  27093. CvPlot* pLoopPlot;
  27094. CvPlot* pPlot = plot();
  27095. CvPlot* pBestPlot = NULL;
  27096. // only returns animal dens for animals, non-animal dens for all other barbarians
  27097. for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
  27098. {
  27099. for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
  27100. {
  27101. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  27102. if (pLoopPlot != NULL)
  27103. {
  27104. if (pLoopPlot->isLair(false, isAnimal()) && AI_plotValid(pLoopPlot))
  27105. {
  27106. if (pLoopPlot->getArea() == getArea())
  27107. {
  27108. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  27109. {
  27110. if (iPathTurns > iRange)
  27111. {
  27112. continue;
  27113. }
  27114. int iDefenders = pLoopPlot->plotCount(PUF_isUnitAIType, UNITAI_LAIRGUARDIAN, -1, (PlayerTypes)BARBARIAN_PLAYER);
  27115. iValue = 10000;
  27116. iValue /= (5 + iDefenders);
  27117. iValue /= (1 + iPathTurns);
  27118. if (iValue > iBestValue)
  27119. {
  27120. iBestValue = iValue;
  27121. pBestPlot = pLoopPlot;
  27122. }
  27123. }
  27124. }
  27125. }
  27126. }
  27127. }
  27128. }
  27129. if (pBestPlot != NULL)
  27130. {
  27131. if (atPlot(pBestPlot))
  27132. {
  27133. getGroup()->pushMission(MISSION_SKIP);
  27134. }
  27135. else
  27136. {
  27137. getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL);
  27138. }
  27139. return true;
  27140. }
  27141. return false;
  27142. }
  27143. // A function to help the AI find nearby defensive ground
  27144. // iRange: path range in which to search; bIncludeHealing: include any healing bonuses from the plot when calculating defensive advantage
  27145. bool CvUnitAI::AI_seekDefensiveGround(int iRange, bool bIncludeHealing)
  27146. {
  27147. logBBAI(" %S (unit %d - %S) seeking defensive ground", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription());
  27148. CvPlot* pBestDefensivePlot = NULL;
  27149. CvPlot* pLoopPlot;
  27150. int iBestPlotValue = (noDefensiveBonus() ? 0 : plot()->defenseModifier(getTeam(), false)) + healRate(plot());
  27151. int iValue = 0;
  27152. int iDX, iDY;
  27153. int iDistance = 6; // ToDo - consider increasing this? With roads, haste, etc, some units could easily move farther than 6 squares
  27154. int iPathTurns;
  27155. for (iDX = -(iDistance); iDX <= iDistance; iDX++)
  27156. {
  27157. for (iDY = -(iDistance); iDY <= iDistance; iDY++)
  27158. {
  27159. pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
  27160. if (pLoopPlot != NULL)
  27161. {
  27162. if (canMoveInto(pLoopPlot))
  27163. {
  27164. if (pLoopPlot->getNumVisibleEnemyDefenders(this) == 0)
  27165. {
  27166. iValue = (noDefensiveBonus() ? 0 : pLoopPlot->defenseModifier(getTeam(), false));
  27167. if (!pLoopPlot->isVisibleToCivTeam())
  27168. {
  27169. iValue += 10;
  27170. }
  27171. if (pLoopPlot->isImpassable()) // being able to move into the plot is checked above
  27172. {
  27173. iValue += 100;
  27174. }
  27175. if (bIncludeHealing)
  27176. {
  27177. iValue += healRate(pLoopPlot);
  27178. }
  27179. if (iValue > iBestPlotValue)
  27180. {
  27181. if (generatePath(pLoopPlot, 0, true, &iPathTurns))
  27182. {
  27183. if (iPathTurns <= iRange)
  27184. {
  27185. iBestPlotValue = iValue;
  27186. pBestDefensivePlot = pLoopPlot;
  27187. }
  27188. }
  27189. }
  27190. }
  27191. }
  27192. }
  27193. }
  27194. }
  27195. if (pBestDefensivePlot != NULL)
  27196. {
  27197. getGroup()->pushMission(MISSION_MOVE_TO, pBestDefensivePlot->getX_INLINE(), pBestDefensivePlot->getY_INLINE());
  27198. logBBAI(" %S (unit %d - %S) moving to defensive ground (%d, %d)", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription(), pBestDefensivePlot->getX_INLINE(), pBestDefensivePlot->getY_INLINE());
  27199. return true;
  27200. }
  27201. return false;
  27202. }
  27203. // lfgr 03/2021: Helper function, to ensure consistency
  27204. bool isCityAIType( UnitAITypes eUnitAI )
  27205. {
  27206. return (eUnitAI == UNITAI_CITY_DEFENSE) ||
  27207. (eUnitAI == UNITAI_CITY_COUNTER) ||
  27208. (eUnitAI == UNITAI_CITY_SPECIAL) ||
  27209. (eUnitAI == UNITAI_RESERVE);
  27210. }
  27211. // lfgr 04/2021: See CvUnitAI.h
  27212. bool CvUnitAI::AI_readyToMoveOrCast()
  27213. {
  27214. if( canMove() )
  27215. {
  27216. return true;
  27217. }
  27218. // For now, only the terrraformer AI might want to move and then cast.
  27219. if( AI_getUnitAIType() == UNITAI_TERRAFORMER && canCastAnything() )
  27220. {
  27221. return true;
  27222. }
  27223. return false;
  27224. }