123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320 |
- // unitAI.cpp
- #include "CvGameCoreDLL.h"
- #include "CvUnitAI.h"
- #include "CvMap.h"
- #include "CvArea.h"
- #include "CvPlot.h"
- #include "CvGlobals.h"
- #include "CvGameAI.h"
- #include "CvTeamAI.h"
- #include "CvPlayerAI.h"
- #include "CvGameCoreUtils.h"
- #include "CvRandom.h"
- #include "CyUnit.h"
- #include "CyArgsList.h"
- #include "CvDLLPythonIFaceBase.h"
- #include "CvInfos.h"
- #include "FProfiler.h"
- #include "FAStarNode.h"
- // interface uses
- #include "CvDLLInterfaceIFaceBase.h"
- #include "CvDLLFAStarIFaceBase.h"
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 10/02/09 jdog5000 */
- /* */
- /* AI logging */
- /************************************************************************************************/
- #include "BetterBTSAI.h"
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- #define FOUND_RANGE (7)
- // Public Functions...
- CvUnitAI::CvUnitAI()
- {
- AI_reset();
- }
- CvUnitAI::~CvUnitAI()
- {
- AI_uninit();
- }
- void CvUnitAI::AI_init(UnitAITypes eUnitAI)
- {
- AI_reset(eUnitAI);
- //--------------------------------
- // Init other game data
- AI_setBirthmark(GC.getGameINLINE().getSorenRandNum(10000, "AI Unit Birthmark"));
- AI_setBirthmark2(GC.getGameINLINE().getSorenRandNum(10000, "AI Unit Birthmark"));
- AI_setBirthmark3(GC.getGameINLINE().getSorenRandNum(10000, "AI Unit Birthmark"));
- FAssertMsg(AI_getUnitAIType() != NO_UNITAI, "AI_getUnitAIType() is not expected to be equal with NO_UNITAI");
- area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), 1);
- GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), 1);
- }
- void CvUnitAI::AI_uninit()
- {
- }
- void CvUnitAI::AI_reset(UnitAITypes eUnitAI)
- {
- AI_uninit();
- m_iBirthmark = 0;
- /*************************************************************************************************/
- /** BETTER AI (New Functions Definition) Sephi **/
- /*************************************************************************************************/
- m_iGroupflag=GROUPFLAG_NONE;
- m_bSuicideSummon=false;
- m_bPermanentSummon=false;
- m_bAllowedPermDefense=true;
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- if (eUnitAI != NO_UNITAI)
- {
- if (!GC.getUnitInfo(getUnitType()).getUnitAIType(eUnitAI))
- {
- eUnitAI = (UnitAITypes)GC.getUnitInfo(getUnitType()).getDefaultUnitAIType();
- }
- }
- m_eUnitAIType = eUnitAI;
- m_iAutomatedAbortTurn = -1;
- }
- // AI_update returns true when we should abort the loop and wait until next slice
- bool CvUnitAI::AI_update()
- {
- PROFILE_FUNC();
- CvUnit* pTransportUnit;
- //FAssertMsg(canMove(), "canMove is expected to be true"); // lfgr 03/2021: Also allow calling this when unit can only cast
- FAssertMsg(isGroupHead(), "isGroupHead is expected to be true"); // XXX is this a good idea???
- // allow python to handle it for certain barbarians
- if (isBarbarian())
- {
- CyUnit* pyUnit = new CyUnit(this);
- CyArgsList argsList;
- argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit)); // pass in unit class
- long lResult=0;
- gDLL->getPythonIFace()->callFunction(PYGameModule, "AI_unitUpdate", argsList.makeFunctionArgs(), &lResult);
- delete pyUnit; // python fxn must not hold on to this pointer
- if (lResult == 1)
- {
- return false;
- }
- }
- //FfH: End Modify
- // Various FFH AI functions - lots of HARDCODE
- // TODO: make this section better
- if (!GET_PLAYER(getOwnerINLINE()).isHuman())
- {
- // Tholal AI - Shades
- if (getUnitClassType() == GC.getInfoTypeForString("UNITCLASS_SHADE"))
- {
- AI_ShadeMove();
- }
-
- // Bring out the comfy chair!
- if (GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_RELIGION2))
- {
- if (isInquisitor())
- {
- AI_InquisitionMove();
- }
- }
- // Vampire stuff. Eating local pop, assignment of AI_FEASTING
- if (isVampire() && getGroup()->getNumUnits() == 1)
- {
- AI_feastingmove();
- }
- // End Tholal AI
- /** BETTER AI Sephi (Time for the Mages to Caste Haste, etc.) **/
- /*
- CLLNode<IDInfo>* pEntityNode = getGroup()->headUnitNode();
- CvUnit* pLoopUnit;
- while (pEntityNode != NULL)
- {
- pLoopUnit = ::getUnit(pEntityNode->m_data);
- pEntityNode = getGroup()->nextUnitNode(pEntityNode);
- if (pLoopUnit->isMovementCaster())
- {
- pLoopUnit->AI_MovementCast();
- }
- }
- */
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- if (getDomainType() == DOMAIN_LAND)
- {
- if (plot()->isWater() && !canMoveAllTerrain())
- {
- getGroup()->pushMission(MISSION_SKIP);
- return false;
- }
- else
- {
- pTransportUnit = getTransportUnit();
- if (pTransportUnit != NULL)
- {
- if (pTransportUnit->getGroup()->hasMoved() || (pTransportUnit->getGroup()->headMissionQueueNode() != NULL))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return false;
- }
- }
- }
- }
- if (AI_afterAttack())
- {
- return false;
- }
- //FfH: Added by Kael 10/26/2008
- if (!isBarbarian())
- {
- if (getLevel() < (isAnimal() ? 6 : 3))
- {
- bool bDoesBuild = false;
- for (int iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
- {
- BuildingTypes eBuilding = (BuildingTypes)GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iI);
- if (NO_BUILDING != eBuilding)
- {
- if ((m_pUnitInfo->getForceBuildings(eBuilding)) || (m_pUnitInfo->getBuildings(eBuilding)))// LFGR_TODO: This can be cached
- {
- /*
- if (canConstruct(plot(),eBuilding))
- {
- construct(eBuilding);
- return false;
- }
- */
- bDoesBuild = true;
- }
- }
- }
- if (bDoesBuild)
- {
- if (AI_construct())
- {
- return false;
- }
- }
- }
- }
- /*************************************************************************************************/
- /** BUGFIX (also AI Units can become Enraged) Sephi **/
- /** **/
- /** **/
- /*************************************************************************************************/
- /** FFH code
- if (isHuman())
- {
- if (getGroup()->getHeadUnit()->isAIControl())
- {
- if (AI_anyAttack(3, 20))
- {
- return true;
- }
- AI_barbAttackMove();
- }
- }
- **/
- if(isAIControl())
- {
- /*
- if (getGroup()->getNumUnits()>1)
- {
- joinGroup(NULL);
- return true;
- }
- */
- // Fix from Snarko - Merged by Tholal on 6/15/10
- if (getGroup()->getNumUnits()>1)
- {
- CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
- CvUnit* pLoopUnit;
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- if (!pLoopUnit->isAIControl())
- {
- joinGroup(NULL);
- return true;
- }
- }
- }
- // End Tholal Merge
- //remove AI control from Defensive only Units
- if(isOnlyDefensive()) // lfgr fix 03/2021: else if -> if, due to Snarko's fix above
- {
- changeAIControl(-1);
- getGroup()->pushMission(MISSION_SKIP);
- return false;
- }
- else if(isAIControl())
- {
- if (canMove() && canAttack()) // lfgr 11/2022: Fix for defensive-only units
- {
- if (AI_anyAttack(getMoves(), 0))
- {
- return false;
- }
- if (AI_anyAttack(3, 0))
- {
- return false;
- }
- if (AI_anyAttack(10, 0))
- {
- return false;
- }
- if (AI_anyAttack(30, 0))
- {
- return false;
- }
- }
- getGroup()->pushMission(MISSION_SKIP);
- return false;
- }
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- //FfH: End Add
- if (getGroup()->isAutomated())
- {
- switch (getGroup()->getAutomateType())
- {
- case AUTOMATE_BUILD:
- if (AI_getUnitAIType() == UNITAI_WORKER)
- {
- AI_workerMove();
- }
- else if (AI_getUnitAIType() == UNITAI_WORKER_SEA)
- {
- AI_workerSeaMove();
- }
- else
- {
- FAssert(false);
- }
- break;
- case AUTOMATE_NETWORK:
- AI_networkAutomated();
- // XXX else wake up???
- break;
- case AUTOMATE_CITY:
- AI_cityAutomated();
- // XXX else wake up???
- break;
- case AUTOMATE_EXPLORE:
- switch (getDomainType())
- {
- case DOMAIN_SEA:
- AI_exploreSeaMove();
- break;
- case DOMAIN_AIR:
- // if we are cargo (on a carrier), hold if the carrier is not done moving yet
- pTransportUnit = getTransportUnit();
- if (pTransportUnit != NULL)
- {
- if (pTransportUnit->isAutomated() && pTransportUnit->canMove() && pTransportUnit->getGroup()->getActivityType() != ACTIVITY_HOLD)
- {
- getGroup()->pushMission(MISSION_SKIP);
- break;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/12/09 jdog5000 */
- /* */
- /* Player Interface */
- /************************************************************************************************/
- // Have air units explore like AI units do
- AI_exploreAir();
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- break;
- case DOMAIN_LAND:
- AI_exploreMove();
- break;
- default:
- FAssert(false);
- break;
- }
- // if we have air cargo (we are a carrier), and we done moving, explore with the aircraft as well
- if (hasCargo() && domainCargo() == DOMAIN_AIR && (!canMove() || getGroup()->getActivityType() == ACTIVITY_HOLD))
- {
- std::vector<CvUnit*> aCargoUnits;
- getCargoUnits(aCargoUnits);
- for (uint i = 0; i < aCargoUnits.size() && isAutomated(); ++i)
- {
- CvUnit* pCargoUnit = aCargoUnits[i];
- if (pCargoUnit->getDomainType() == DOMAIN_AIR)
- {
- if (pCargoUnit->canMove())
- {
- pCargoUnit->getGroup()->setAutomateType(AUTOMATE_EXPLORE);
- pCargoUnit->getGroup()->setActivityType(ACTIVITY_AWAKE);
- }
- }
- }
- }
- break;
- case AUTOMATE_RELIGION:
- if (AI_getUnitAIType() == UNITAI_MISSIONARY)
- {
- AI_missionaryMove();
- }
- break;
- // Start Sephi Code - Automatic Terraforming
- case AUTOMATE_TERRAFORMING:
- if( AI_getUnitAIType() != UNITAI_TERRAFORMER )
- {
- AI_setUnitAIType(UNITAI_TERRAFORMER); // lfgr comment: This kicks us out of our group and resets our AutomateType!
- getGroup()->setAutomateType( AUTOMATE_TERRAFORMING ); // lfgr fix 03/2021
- }
- AI_terraformerMove();
- break;
- // End Sephi Code
- default: // lfgr comment: isAIControl() makes isAutomated() true without actually having to have an automate type.
- FAssertMsg( isAIControl(), CvString::format( "Unknown automate type: %d", getGroup()->getAutomateType() ).c_str() );
- break;
- }
- // if no longer automated, then we want to bail
- //return !getGroup()->isAutomated();
- }
- else
- {
- /*************************************************************************************************/
- /** BETTER AI (UnitAI::AI_update) Sephi **/
- /*************************************************************************************************/
- // Tholal ToDo - this section is kind of hacky. Figure out a way to remove it entirely and move the functionality to appropriate spots
- if (!isBarbarian())
- {
- if (getExperience() > 99)
- {
- if (AI_getUnitAIType() != UNITAI_HERO)
- {
- AI_setUnitAIType(UNITAI_HERO);
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- }
- }
- // Tholal AI - temp hack for adepts that get wrong AI type
- if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
- {
- switch (AI_getUnitAIType())
- {
- case UNITAI_WARWIZARD:
- case UNITAI_MANA_UPGRADE:
- case UNITAI_TERRAFORMER:
- case UNITAI_MAGE:
- case UNITAI_HERO:
- break;
- case UNITAI_FEASTING:
- if (isVampire())
- {
- break;
- }
- case UNITAI_INQUISITOR:
- if (isInquisitor())
- {
- break;
- }
- default:
- if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_MANA_UPGRADE) == 0)
- {
- AI_setUnitAIType(UNITAI_MANA_UPGRADE);
- AI_setGroupflag(GROUPFLAG_NONE);
- break;
- }
- if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_TERRAFORMER) == 0 && isTerraformer())
- {
- AI_setUnitAIType(UNITAI_TERRAFORMER);
- AI_setGroupflag(GROUPFLAG_NONE);
- break;
- }
- if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_MAGE) < GET_PLAYER(getOwnerINLINE()).getNumCities())
- {
- AI_setUnitAIType(UNITAI_MAGE);
- AI_setGroupflag(GROUPFLAG_PERMDEFENSE);
- break;
- }
- AI_setUnitAIType(UNITAI_WARWIZARD);
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- break;
- }
- }
- // Tholal AI - catch for units who have casted already this turn and now can't move
- // lfgr 04/2021: Allow certain AI functions to be called when we can still cast, but not move anymore
- if (!AI_readyToMoveOrCast())
- {
- return false;
- }
- switch (AI_getGroupflag())
- {
- case GROUPFLAG_HNGROUP:
- AI_HiddenNationalityMove();
- return false;
- break;
- case GROUPFLAG_SUICIDE_SUMMON:
- AI_summonAttackMove();
- return false;
- break;
- case GROUPFLAG_SVARTALFAR_KIDNAP:
- AI_SvartalfarKidnapMove();
- return false;
- break;
- case GROUPFLAG_CONQUEST:
- AI_ConquestMove();
- return false;
- break;
- case GROUPFLAG_PERMDEFENSE:
- AI_cityDefenseMove();
- return false;
- break;
- case GROUPFLAG_PATROL:
- AI_PatrolMove();
- return false;
- break;
- case GROUPFLAG_HERO:
- AI_heromove();
- return false;
- break;
- default:
- break;
- }
- if (isSuicideSummon())
- {
- AI_summonAttackMove();
- setSuicideSummon(false);
- return false;
- }
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- // Tholal AI - make sure we dont try to move if we can't (ie, due to spell/ability usage earlier in this function)
- // lfgr 04/2021: Allow certain AI functions to be called when we can still cast, but not move anymore
- if (AI_readyToMoveOrCast())
- {
- switch (AI_getUnitAIType())
- {
- case UNITAI_UNKNOWN:
- getGroup()->pushMission(MISSION_SKIP);
- break;
- case UNITAI_ANIMAL:
- AI_animalMove();
- break;
- case UNITAI_SETTLE:
- AI_settleMove();
- break;
- case UNITAI_WORKER:
- AI_workerMove();
- break;
- case UNITAI_ATTACK:
- //Added by Kael 09/19/2007
- if (getDuration() > 0)
- {
- AI_summonAttackMove();
- break;
- }
- //FfH: End Add
- if (isBarbarian())
- {
- AI_barbAttackMove();
- }
- else
- {
- AI_attackMove();
- }
- break;
- /*************************************************************************************************/
- /** BETTER AI (New UNITAI) Sephi **/
- /** **/
- /** **/
- /*************************************************************************************************/
- case UNITAI_HERO:
- if (isBarbarian())
- {
- AI_barbAttackMove();
- }
- else
- {
- AI_heromove();
- }
- break;
- case UNITAI_INQUISITOR:
- AI_InquisitionMove();
- break;
- case UNITAI_FEASTING:
- AI_feastingmove();
- break;
- case UNITAI_MANA_UPGRADE:
- AI_upgrademanaMove();
- break;
- case UNITAI_MAGE:
- //AI_mageMove();
- AI_cityDefenseMove();
- break;
- case UNITAI_WARWIZARD:
- AI_ConquestMove();
- break;
- case UNITAI_TERRAFORMER:
- AI_terraformerMove();
- break;
- case UNITAI_ATTACK_CITY:
- if (isBarbarian())
- {
- AI_barbAttackMove();
- }
- else
- {
- AI_attackCityMove();
- }
- break;
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- case UNITAI_COLLATERAL:
- AI_collateralMove();
- break;
- case UNITAI_PILLAGE:
- AI_pillageMove();
- break;
- case UNITAI_RESERVE:
- AI_reserveMove();
- break;
- case UNITAI_MEDIC:
- case UNITAI_COUNTER:
- AI_counterMove();
- break;
- case UNITAI_PARADROP:
- AI_paratrooperMove();
- break;
- case UNITAI_CITY_DEFENSE:
- AI_cityDefenseMove();
- break;
- case UNITAI_CITY_COUNTER:
- case UNITAI_CITY_SPECIAL:
- AI_cityDefenseExtraMove();
- break;
- case UNITAI_EXPLORE:
- AI_exploreMove();
- break;
- case UNITAI_MISSIONARY:
- AI_missionaryMove();
- break;
- case UNITAI_PROPHET:
- AI_prophetMove();
- break;
- case UNITAI_ARTIST:
- AI_artistMove();
- break;
- case UNITAI_SCIENTIST:
- AI_scientistMove();
- break;
- case UNITAI_GENERAL:
- AI_generalMove();
- break;
- case UNITAI_MERCHANT:
- AI_merchantMove();
- break;
- case UNITAI_ENGINEER:
- AI_engineerMove();
- break;
- case UNITAI_SPY:
- AI_spyMove();
- break;
- case UNITAI_ICBM:
- AI_ICBMMove();
- break;
- case UNITAI_WORKER_SEA:
- AI_workerSeaMove();
- break;
- case UNITAI_ATTACK_SEA:
- if (isBarbarian())
- {
- AI_barbAttackSeaMove();
- }
- else
- {
- AI_attackSeaMove();
- }
- break;
- case UNITAI_RESERVE_SEA:
- AI_reserveSeaMove();
- break;
- case UNITAI_ESCORT_SEA:
- AI_escortSeaMove();
- break;
- case UNITAI_EXPLORE_SEA:
- AI_exploreSeaMove();
- break;
- case UNITAI_ASSAULT_SEA:
- AI_assaultSeaMove();
- break;
- case UNITAI_SETTLER_SEA:
- AI_settlerSeaMove();
- break;
- case UNITAI_MISSIONARY_SEA:
- AI_missionarySeaMove();
- break;
- case UNITAI_SPY_SEA:
- AI_spySeaMove();
- break;
- case UNITAI_CARRIER_SEA:
- AI_carrierSeaMove();
- break;
- case UNITAI_MISSILE_CARRIER_SEA:
- AI_missileCarrierSeaMove();
- break;
- case UNITAI_PIRATE_SEA:
- AI_pirateSeaMove();
- break;
- case UNITAI_ATTACK_AIR:
- AI_attackAirMove();
- break;
- case UNITAI_DEFENSE_AIR:
- AI_defenseAirMove();
- break;
- case UNITAI_CARRIER_AIR:
- AI_carrierAirMove();
- break;
- case UNITAI_MISSILE_AIR:
- AI_missileAirMove();
- break;
- case UNITAI_ATTACK_CITY_LEMMING:
- AI_attackCityLemmingMove();
- break;
- case UNITAI_LAIRGUARDIAN:
- AI_lairGuardianMove();
- break;
- case UNITAI_SHADE:
- AI_ShadeMove();
- break;
-
- default:
- FAssert(false);
- break;
- }
- }
- }
- return false;
- }
- // Returns true if took an action or should wait to move later...
- // K-Mod. I've basically rewriten this function.
- // bFirst should be "true" if this is the first unit in the group to use this follow function.
- // the point is that there are some calculations and checks in here which only depend on the group, not the unit
- // so for efficiency, we should only check them once.
- bool CvUnitAI::AI_follow(bool bFirst)
- {
- FAssert(getDomainType() != DOMAIN_AIR);
- if (AI_followBombard())
- return true;
- if (bFirst && getGroup()->getHeadUnitAI() == UNITAI_ATTACK_CITY)
- {
- // note: AI_stackAttackCity will check which of our units can attack when comparing stacks;
- // and it will issue the attack order using MOVE_DIRECT ATTACK, which will execute without waiting for the entire group to have movement points.
- if (AI_stackAttackCity(1, 160, true)) // automatic threshold
- return true;
- }
- // I've changed attack-follow code so that it will only attack with a single unit, not the whole group.
- if (bFirst && AI_cityAttack(1, 65, true))
- return true;
- if (bFirst)
- {
- bool bMoveGroup = false; // to large groups to leave some units behind.
- if (getGroup()->getNumUnits() >= 16)
- {
- int iCanMove = 0;
- CLLNode<IDInfo>* pEntityNode = getGroup()->headUnitNode();
- while (pEntityNode)
- {
- CvUnit* pLoopUnit = ::getUnit(pEntityNode->m_data);
- pEntityNode = getGroup()->nextUnitNode(pEntityNode);
- iCanMove += (pLoopUnit->canMove() ? 1 : 0);
- }
- bMoveGroup = 5 * iCanMove >= 4 * getGroup()->getNumUnits() || iCanMove >= 20; // if 4/5 of our group can still move.
- }
- if (AI_anyAttack(1, isEnemy(plot()->getTeam()) ? 65 : 70, bMoveGroup ? 0 : 2, true, true))
- return true;
- }
- //
- if (isEnemy(plot()->getTeam()))
- {
- if (canPillage(plot()))
- {
- getGroup()->pushMission(MISSION_PILLAGE);
- return true;
- }
- }
- if (isFound())
- {
- if (area()->getBestFoundValue(getOwnerINLINE()) > 0)
- {
- if (AI_foundRange(FOUND_RANGE, true))
- {
- return true;
- }
- }
- }
- return false;
- }
- // K-Mod. This function has been completely rewritten to improve efficiency and intelligence.
- void CvUnitAI::AI_upgrade()
- {
- PROFILE_FUNC();
- FAssert(!isHuman());
- FAssert(AI_getUnitAIType() != NO_UNITAI);
- if (!isReadyForUpgrade())
- return;
- const CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- const CvCivilizationInfo& kCivInfo = GC.getCivilizationInfo(kPlayer.getCivilizationType());
- UnitAITypes eUnitAI = AI_getUnitAIType();
- CvArea* pArea = area();
- int iBestValue = kPlayer.AI_unitValue(getUnitType(), eUnitAI, pArea, true) * 100;
- UnitTypes eBestUnit = NO_UNIT;
- // LFGR_TODO: A new function CvUnit::canEverUpgrade(UnitTypes) could help here. Caching a list of possible upgrades for each UnitType could also make sense.
- // Note: the original code did two passes, presumably for speed reasons.
- // In the first pass, they checked only units which were flagged with the right unitAI.
- // Then, only if no such units were found, they checked all other units.
- //
- // 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.
- //
- // I've reversed the order of iteration because the stronger units are typically later in the list
- for (UnitClassTypes i = (UnitClassTypes)(GC.getNumUnitClassInfos()-1); i >= 0; i=(UnitClassTypes)(i-1))
- {
- UnitTypes eLoopUnit = (UnitTypes)kCivInfo.getCivilizationUnits(i);
- if (eLoopUnit != NO_UNIT)
- {
- int iValue = kPlayer.AI_unitValue(eLoopUnit, eUnitAI, pArea, true);
- // use a random factor. less than 100, so that the upgrade must be better than the current unit.
- iValue *= 80 + GC.getGameINLINE().getSorenRandNum(21, "AI Upgrade");
- // (believe it or not, AI_unitValue is faster than canUpgrade.)
- if (iValue > iBestValue && canUpgrade(eLoopUnit))
- {
- iBestValue = iValue;
- eBestUnit = eLoopUnit;
- }
- }
- }
- if (eBestUnit != NO_UNIT)
- {
- 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);
- //upgrade(eBestUnit);
- // K-Mod. Ungroup the unit, so that we don't cause the whole group to miss their turn.
- CvUnit* pUpgradeUnit = upgrade(eBestUnit);
- doDelayedDeath();
- if (pUpgradeUnit != this)
- {
- CvSelectionGroup* pGroup = pUpgradeUnit->getGroup();
- if (pGroup->getHeadUnit() != pUpgradeUnit)
- {
- pUpgradeUnit->joinGroup(NULL);
- // indicate that the unit intends to rejoin the old group (although it might not actually do so...)
- pUpgradeUnit->getGroup()->AI_setMissionAI(MISSIONAI_GROUP, 0, pGroup->getHeadUnit());
- }
- }
- }
- }
- void CvUnitAI::AI_promote()
- {
- PROFILE_FUNC();
- // 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.
- if (!isPromotionReady())
- return; // can't get any normal promotions. (see CvUnit::canPromote)
- // K-Mod end
- if( gPromoteLogLevel >= 1 )
- {
- logBBAI(" %S (unit %d - %S) looking for best promotion...", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription() );
- }
- int iBestValue = 0;
- PromotionTypes eBestPromotion = NO_PROMOTION;
- for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
- {
- if (canPromote((PromotionTypes)iI, -1))
- {
- int iValue = AI_promotionValue((PromotionTypes)iI);
- if( gPromoteLogLevel >= 1 && iValue > 0 )
- {
- logBBAI(" %S has value %d", GC.getPromotionInfo( (PromotionTypes)iI ).getDescription(), iValue );
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestPromotion = ((PromotionTypes)iI);
- }
- }
- }
- if (eBestPromotion != NO_PROMOTION)
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" %S (unit %d - %S) choosing promotion %S (value: %d)", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription(), GC.getPromotionInfo(eBestPromotion).getDescription(), iBestValue);
- }
- promote(eBestPromotion, -1);
- AI_promote();
- }
- }
- int CvUnitAI::AI_groupFirstVal()
- {
- if (isBarbarian() && AI_getUnitAIType() != UNITAI_HERO)
- {
- return (AI_getBarbLeadership());
- }
- /*************************************************************************************************/
- /** BETTER AI (improved logic which unit becomes head of a group) Sephi **/
- /** **/
- /** **/
- /*************************************************************************************************/
- if (getDuration()>0)
- {
- return 1;
- }
- /*
- if (AI_getGroupflag()==GROUPFLAG_CONQUEST)
- {
- return 25;
- }
- */
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- switch (AI_getUnitAIType())
- {
- case UNITAI_UNKNOWN:
- case UNITAI_ANIMAL:
- //FAssert(false);
- return 1;
- break;
- case UNITAI_SETTLE:
- return 21;
- break;
- case UNITAI_WORKER:
- return 20;
- break;
- case UNITAI_ATTACK:
- if (collateralDamage() > 0)
- {
- return 17;
- }
- else if (withdrawalProbability() > 0)
- {
- return 15;
- }
- else if (!m_pUnitInfo->isPillage())
- {
- return 10;
- }
- else
- {
- return 13;
- }
- break;
- case UNITAI_ATTACK_CITY:
- if (bombardRate() > 0)
- {
- return 19;
- }
- else if (collateralDamage() > 0)
- {
- return 18;
- }
- else if (withdrawalProbability() > 0)
- {
- return 16;
- }
- else if (!m_pUnitInfo->isPillage())
- {
- return 10;
- }
- else
- {
- return 14;
- }
- break;
- case UNITAI_COLLATERAL:
- return 7;
- break;
- case UNITAI_PILLAGE:
- return 12;
- break;
- case UNITAI_RESERVE:
- return 6;
- break;
- case UNITAI_COUNTER:
- return 5;
- break;
- case UNITAI_CITY_DEFENSE:
- return 3;
- break;
- case UNITAI_CITY_COUNTER:
- return 2;
- break;
- case UNITAI_CITY_SPECIAL:
- /*************************************************************************************************/
- /** BETTER AI (New UNITAI) Sephi **/
- /** **/
- /** **/
- /*************************************************************************************************/
- case UNITAI_MAGE:
- case UNITAI_TERRAFORMER:
- case UNITAI_MANA_UPGRADE:
- case UNITAI_WARWIZARD:
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- return 3;
- break;
- /*************************************************************************************************/
- /** BETTER AI (New UNITAI) Sephi **/
- /** **/
- /** **/
- /*************************************************************************************************/
- case UNITAI_FEASTING:
- case UNITAI_MEDIC:
- case UNITAI_INQUISITOR:
- return 3;
- break;
- case UNITAI_HERO:
- return 100; //Heroes don't like to get pushed around
- break;
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- case UNITAI_PARADROP:
- return 4;
- break;
- case UNITAI_EXPLORE:
- return 8;
- break;
- case UNITAI_MISSIONARY:
- return 10;
- break;
- case UNITAI_PROPHET:
- case UNITAI_ARTIST:
- case UNITAI_SCIENTIST:
- case UNITAI_GENERAL:
- case UNITAI_MERCHANT:
- case UNITAI_ENGINEER:
- return 11;
- break;
- case UNITAI_SPY:
- return 9;
- break;
- case UNITAI_ICBM:
- break;
- case UNITAI_WORKER_SEA:
- return 8;
- break;
- case UNITAI_ATTACK_SEA:
- return 3;
- break;
- case UNITAI_RESERVE_SEA:
- return 2;
- break;
- case UNITAI_ESCORT_SEA:
- return 1;
- break;
- case UNITAI_EXPLORE_SEA:
- return 5;
- break;
- case UNITAI_ASSAULT_SEA:
- return 11;
- break;
- case UNITAI_SETTLER_SEA:
- return 9;
- break;
- case UNITAI_MISSIONARY_SEA:
- return 9;
- break;
- case UNITAI_SPY_SEA:
- return 10;
- break;
- case UNITAI_CARRIER_SEA:
- return 7;
- break;
- case UNITAI_MISSILE_CARRIER_SEA:
- return 6;
- break;
- case UNITAI_PIRATE_SEA:
- return 4;
- break;
- case UNITAI_ATTACK_AIR:
- case UNITAI_DEFENSE_AIR:
- case UNITAI_CARRIER_AIR:
- case UNITAI_MISSILE_AIR:
- break;
- case UNITAI_ATTACK_CITY_LEMMING:
- return 1;
- break;
- case UNITAI_LAIRGUARDIAN:
- case UNITAI_SHADE:
- break;
- default:
- FAssert(false);
- break;
- }
- return 0;
- }
- int CvUnitAI::AI_groupSecondVal()
- {
- return ((getDomainType() == DOMAIN_AIR) ? airBaseCombatStr() : baseCombatStr());
- }
- // Returns attack odds out of 100 (the higher, the better...)
- // Withdrawal odds included in returned value
- int CvUnitAI::AI_attackOdds(const CvPlot* pPlot, bool bPotentialEnemy) const
- {
- PROFILE_FUNC();
- CvUnit* pDefender;
- int iOurStrength;
- int iTheirStrength;
- int iOurFirepower;
- int iTheirFirepower;
- int iBaseOdds;
- int iStrengthFactor;
- int iDamageToUs;
- int iDamageToThem;
- int iNeededRoundsUs;
- int iNeededRoundsThem;
- int iHitLimitThem;
- pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, !bPotentialEnemy, bPotentialEnemy);
- if (pDefender == NULL)
- {
- return 100;
- }
- iOurStrength = ((getDomainType() == DOMAIN_AIR) ? airCurrCombatStr(NULL) : currCombatStr(NULL, pDefender));
- iOurFirepower = ((getDomainType() == DOMAIN_AIR) ? iOurStrength : currFirepower(NULL, pDefender));
- if (iOurStrength == 0)
- {
- return 1;
- }
- iTheirStrength = pDefender->currCombatStr(pPlot, this);
- iTheirFirepower = pDefender->currFirepower(pPlot, this);
- FAssert((iOurStrength + iTheirStrength) > 0);
- FAssert((iOurFirepower + iTheirFirepower) > 0);
- iBaseOdds = (100 * iOurStrength) / (iOurStrength + iTheirStrength);
- if (iBaseOdds == 0)
- {
- return 1;
- }
- iStrengthFactor = ((iOurFirepower + iTheirFirepower + 1) / 2);
- iDamageToUs = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iTheirFirepower + iStrengthFactor)) / (iOurFirepower + iStrengthFactor)));
- iDamageToThem = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iOurFirepower + iStrengthFactor)) / (iTheirFirepower + iStrengthFactor)));
- iHitLimitThem = pDefender->maxHitPoints() - combatLimit();
- iNeededRoundsUs = (std::max(0, pDefender->currHitPoints() - iHitLimitThem) + iDamageToThem - 1 ) / iDamageToThem;
- iNeededRoundsThem = (std::max(0, currHitPoints()) + iDamageToUs - 1 ) / iDamageToUs;
- if (getDomainType() != DOMAIN_AIR)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 10/30/09 Mongoose & jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- // From Mongoose SDK
- if (!pDefender->immuneToFirstStrikes()) {
- iNeededRoundsUs -= ((iBaseOdds * firstStrikes()) + ((iBaseOdds * chanceFirstStrikes()) / 2)) / 100;
- }
- if (!immuneToFirstStrikes()) {
- iNeededRoundsThem -= (((100 - iBaseOdds) * pDefender->firstStrikes()) + (((100 - iBaseOdds) * pDefender->chanceFirstStrikes()) / 2)) / 100;
- }
- iNeededRoundsUs = std::max(1, iNeededRoundsUs);
- iNeededRoundsThem = std::max(1, iNeededRoundsThem);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- int iRoundsDiff = iNeededRoundsUs - iNeededRoundsThem;
- if (iRoundsDiff > 0)
- {
- iTheirStrength *= (1 + iRoundsDiff);
- }
- else
- {
- iOurStrength *= (1 - iRoundsDiff);
- }
- int iOdds = (((iOurStrength * 100) / (iOurStrength + iTheirStrength)));
- iOdds += ((100 - iOdds) * withdrawalProbability()) / 100;
- iOdds += GET_PLAYER(getOwnerINLINE()).AI_getAttackOddsChange();
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 10/30/09 Mongoose & jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- // From Mongoose SDK
- return range(iOdds, 1, 99);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- // Returns true if the unit found a build for this city...
- bool CvUnitAI::AI_bestCityBuild(CvCity* pCity, CvPlot** ppBestPlot, BuildTypes* peBestBuild, CvPlot* pIgnorePlot, CvUnit* pUnit)
- {
- PROFILE_FUNC();
- int iBestValue = 0;
- BuildTypes eBestBuild = NO_BUILD;
- CvPlot* pBestPlot = NULL;
- for (int iPass = 0; iPass < 2; iPass++)
- {
- for (int iI = 0; iI < pCity->getNumCityPlots(); iI++)
- {
- CvPlot* pLoopPlot = plotCity(pCity->getX_INLINE(), pCity->getY_INLINE(), iI);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot != pIgnorePlot)
- {
- if ((pLoopPlot->getImprovementType() == NO_IMPROVEMENT) || !(GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION) && !(pLoopPlot->getImprovementType() == (GC.getDefineINT("RUINS_IMPROVEMENT")))))
- {
- int iValue = pCity->AI_getBestBuildValue(iI);
- if (iValue > iBestValue)
- {
- BuildTypes eBuild = pCity->AI_getBestBuild(iI);
- FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");
- if (eBuild != NO_BUILD)
- {
- if (0 == iPass)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- eBestBuild = eBuild;
- }
- else if (canBuild(pLoopPlot, eBuild))
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- // XXX take advantage of range (warning... this could lead to some units doing nothing...)
- int iMaxWorkers = 1;
- if (getPathLastNode()->m_iData1 == 0)
- {
- iPathTurns++;
- }
- else if (iPathTurns <= 1)
- {
- iMaxWorkers = AI_calculatePlotWorkersNeeded(pLoopPlot, eBuild);
- }
- if (pUnit != NULL)
- {
- if (pUnit->plot()->isCity() && iPathTurns == 1 && getPathLastNode()->m_iData1 > 0)
- {
- iMaxWorkers += 10;
- }
- }
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup()) < iMaxWorkers)
- {
- //XXX this could be improved greatly by
- //looking at the real build time and other factors
- //when deciding whether to stack.
- iValue /= iPathTurns;
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- eBestBuild = eBuild;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (0 == iPass)
- {
- if (eBestBuild != NO_BUILD)
- {
- FAssert(pBestPlot != NULL);
- int iPathTurns;
- if ((generatePath(pBestPlot, 0, true, &iPathTurns)) && canBuild(pBestPlot, eBestBuild)
- && !(pBestPlot->isVisibleEnemyUnit(this)))
- {
- int iMaxWorkers = 1;
- if (pUnit != NULL)
- {
- if (pUnit->plot()->isCity())
- {
- iMaxWorkers += 10;
- }
- }
- if (getPathLastNode()->m_iData1 == 0)
- {
- iPathTurns++;
- }
- else if (iPathTurns <= 1)
- {
- iMaxWorkers = AI_calculatePlotWorkersNeeded(pBestPlot, eBestBuild);
- }
- int iWorkerCount = GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pBestPlot, MISSIONAI_BUILD, getGroup());
- if (iWorkerCount < iMaxWorkers)
- {
- //Good to go.
- break;
- }
- }
- eBestBuild = NO_BUILD;
- iBestValue = 0;
- }
- }
- }
- if (NO_BUILD != eBestBuild)
- {
- FAssert(NULL != pBestPlot);
- if (ppBestPlot != NULL)
- {
- *ppBestPlot = pBestPlot;
- }
- if (peBestBuild != NULL)
- {
- *peBestBuild = eBestBuild;
- }
- }
- return (NO_BUILD != eBestBuild);
- }
- bool CvUnitAI::AI_isCityAIType() const
- {
- return isCityAIType( AI_getUnitAIType() );
- }
- int CvUnitAI::AI_getBirthmark() const
- {
- return m_iBirthmark;
- }
- int CvUnitAI::AI_getBirthmark2() const
- {
- return m_iBirthmark;
- }
- int CvUnitAI::AI_getBirthmark3() const
- {
- return m_iBirthmark;
- }
- int CvUnitAI::AI_getBarbLeadership() const
- {
- int iFollowers = 0;
- return (AI_getBarbLeadership(iFollowers));
- }
- // ALN - This is used as a measure of how able a barbarian unit is able to pull
- // others barbarians under his command
- int CvUnitAI::AI_getBarbLeadership(int& iFollowers) const
- {
- bool bHero = AI_getUnitAIType() == UNITAI_HERO;
- bool bAttack = AI_getUnitAIType() == UNITAI_ATTACK;
- bool bAttackCity = AI_getUnitAIType() == UNITAI_ATTACK_CITY;
-
- // Only certain unitAIs can command other barbs
- if (!bHero && !bAttack && !bAttackCity)
- {
- return 0;
- }
-
- int iLeadership = AI_getBirthmark3() % 8;
-
- // more experienced units are better leaders
- iLeadership += (std::min(3, getLevel() / 2));
-
- // heros always are better leaders, not always great ones though
- iLeadership += (bHero ? 2 + (AI_getBirthmark3() % 3) : 0);
-
- // Absolute highest level possible will be 11
- iLeadership = std::min(11, iLeadership);
- // sorry goblins, you won't be leading any stacks of doom
- iLeadership = std::min((baseCombatStr() * 2) + 1, iLeadership);
- // undead don't lead large groups
- if (!bHero && !isAlive())
- {
- iLeadership -= 1;
- iLeadership = std::min(5 + (AI_getBirthmark3() % 2), iLeadership);
- }
- // max follower units based on leadership
- if (iLeadership >= 9)
- {
- iFollowers = iLeadership - 6;
- }
- else if (iLeadership >= 5)
- {
- iFollowers = 2;
- }
- else if (iLeadership >= 3)
- {
- iFollowers = 1;
- }
-
- // limit group sizes in the beginning of the game
- int iCivCities = GC.getGameINLINE().getNumCivCities();
- int iCivs = GC.getGameINLINE().countCivPlayersAlive();
- // Bugfix: Prevent a crash when playing with require complete kills.
- if (iCivs <= 0) {
- iCivs = 1;
- }
- iFollowers = std::min((iCivCities / (iCivs + (iCivs / 2))) + 1, iFollowers);
-
- return iLeadership;
- }
- // ALN - This function is always to be called in the position of a barb looking for a higher 'leadership' barbarian
- // that he's looking to join, never from the leader side, but from the follower side(looking for a better leader).
- bool CvUnitAI::AI_groupBarbLeader(int iMaxRange) const
- {
- bool bHero = AI_getUnitAIType() == UNITAI_HERO;
- bool bAttack = AI_getUnitAIType() == UNITAI_ATTACK;
- bool bAttackCity = AI_getUnitAIType() == UNITAI_ATTACK_CITY;
- if (isCargo())
- {
- return false;
- }
- if (bHero)
- {
- return false;
- }
-
- CvPlot* pPlot = plot();
- CvSelectionGroup* pGroup = getGroup();
- int iGroupSize = pGroup->getNumUnits();
- int iOurLeadership = AI_getBarbLeadership();
- int iOurRace = getRace();
-
- int iLeadership;
- int iRace;
- int iMaxFollowers;
- int iFollowers;
- int iJoiners;
-
- int iBestValue = 0;
- CvUnit* pBestUnit = NULL;
- for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
- {
- for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
- {
- CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL && pLoopPlot->getArea() == pPlot->getArea())
- {
- CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
- CvSelectionGroup* pLoopGroup = pLoopUnit->getGroup();
- iRace = pLoopUnit->getRace();
- // if pLoopUnit is not a hero, require race to be the same
- if (iRace == iOurRace || pLoopUnit->AI_getUnitAIType() == UNITAI_HERO)
- {
- if (AI_allowGroup(pLoopUnit, UNITAI_UNKNOWN))
- {
- iLeadership = pLoopUnit->AI_getBarbLeadership(iMaxFollowers);
- iFollowers = pLoopGroup->getNumUnits() - 1;
- if (iLeadership > iOurLeadership)
- {
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- iJoiners = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, MISSIONAI_GROUP, pLoopGroup);
- if (iFollowers + iJoiners + iGroupSize <= iMaxFollowers)
- {
- int XDist=pLoopPlot->getX_INLINE() - plot()->getX_INLINE();
- int YDist=pLoopPlot->getY_INLINE() - plot()->getY_INLINE();
- if (((XDist*XDist)+(YDist*YDist))<(iMaxRange + 2)*(iMaxRange + 2)*4)
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= (iMaxRange <= 2 ? iMaxRange + 2 : iMaxRange + 1))
- {
- int iValue = iLeadership * 1000;
- // leaders can pick up different race units, but reduce it's value still
- // so those different race units will prefer one of their own if also in range
- iValue /= (iRace == iOurRace ? 1 : 2);
- iValue /= (iPathTurns + 2);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopUnit;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestUnit != NULL)
- {
- if (atPlot(pBestUnit->plot()))
- {
- pGroup->mergeIntoGroup(pBestUnit->getGroup());
- return true;
- }
- else
- {
- if (getGroup()->getNumUnits() > 1)
- {
- pGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
- return true;
- }
- else
- {
- pGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
- return true;
- }
- }
- }
- return false;
- }
- void CvUnitAI::AI_setBirthmark(int iNewValue)
- {
- m_iBirthmark = iNewValue;
- if (AI_getUnitAIType() == UNITAI_EXPLORE_SEA)
- {
- if (GC.getGame().circumnavigationAvailable())
- {
- m_iBirthmark -= m_iBirthmark % 4;
- int iExplorerCount = GET_PLAYER(getOwnerINLINE()).AI_getNumAIUnits(UNITAI_EXPLORE_SEA);
- iExplorerCount += getOwnerINLINE() % 4;
- if (GC.getMap().isWrapX())
- {
- if ((iExplorerCount % 2) == 1)
- {
- m_iBirthmark += 1;
- }
- }
- if (GC.getMap().isWrapY())
- {
- if (!GC.getMap().isWrapX())
- {
- iExplorerCount *= 2;
- }
- if (((iExplorerCount >> 1) % 2) == 1)
- {
- m_iBirthmark += 2;
- }
- }
- }
- }
- }
- void CvUnitAI::AI_setBirthmark2(int iNewValue)
- {
- m_iBirthmark = iNewValue;
- }
- void CvUnitAI::AI_setBirthmark3(int iNewValue)
- {
- m_iBirthmark = iNewValue;
- }
- UnitAITypes CvUnitAI::AI_getUnitAIType() const
- {
- return m_eUnitAIType;
- }
- // XXX make sure this gets called...
- void CvUnitAI::AI_setUnitAIType(UnitAITypes eNewValue)
- {
- FAssertMsg(eNewValue != NO_UNITAI, "NewValue is not assigned a valid value");
- if (AI_getUnitAIType() != eNewValue)
- {
- area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), -1);
- GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), -1);
- m_eUnitAIType = eNewValue;
- area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), 1);
- GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), 1);
- joinGroup(NULL);
- }
- }
- int CvUnitAI::AI_sacrificeValue(const CvPlot* pPlot) const
- {
- int iValue;
- int iCollateralDamageValue = 0;
- if (pPlot != NULL)
- {
- int iPossibleTargets = std::min((pPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits());
- if (iPossibleTargets > 0)
- {
- iCollateralDamageValue = collateralDamage();
- iCollateralDamageValue += std::max(0, iCollateralDamageValue - 100);
- // Improved Pyre Zombie AI (Skyre) - account for their explosion factor - merged by Tholal 4/12/10
- if (getUnitInfo().isExplodeInCombat())
- {
- iCollateralDamageValue += 150;
- }
- // End Improved Pyre Zombie AI
- iCollateralDamageValue *= iPossibleTargets;
- iCollateralDamageValue /= 5;
- }
- }
- if (getDomainType() == DOMAIN_AIR)
- {
- iValue = 128 * (100 + currInterceptionProbability());
- if (m_pUnitInfo->getNukeRange() != -1)
- {
- iValue += 25000;
- }
- iValue /= std::max(1, (1 + m_pUnitInfo->getProductionCost()));
- iValue *= (maxHitPoints() - getDamage());
- iValue /= 100;
- }
- else
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 05/14/10 jdog5000 */
- /* */
- /* General AI */
- /************************************************************************************************/
- /*
- // original bts code
- iValue = 128 * (currEffectiveStr(pPlot, ((pPlot == NULL) ? NULL : this)));
- iValue *= (100 + iCollateralDamageValue);
- iValue /= (100 + cityDefenseModifier());
- iValue *= (100 + withdrawalProbability());
- iValue /= std::max(1, (1 + m_pUnitInfo->getProductionCost()));
- iValue /= (10 + getExperience());
- */
- iValue = 128 * (currEffectiveStr(pPlot, ((pPlot == NULL) ? NULL : this)));
- iValue *= (100 + iCollateralDamageValue);
- iValue /= (100 + cityDefenseModifier());
- iValue *= (100 + withdrawalProbability());
- // Value experience a bit more, especially medics
- iValue /= (10 + getExperience());
- iValue /= (10 + getSameTileHeal() + getAdjacentTileHeal());
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Value units which can't kill units later, also combat limits mean higher survival odds
- if (combatLimit() < 100)
- {
- iValue *= 150;
- iValue /= 100;
- iValue *= 100;
- iValue /= std::max(1, combatLimit());
- }
- iValue /= std::max(1, (1 + m_pUnitInfo->getProductionCost()));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- // summoned units make good sacrifices since they can be resummoned
- if (getSummoner() != -1)
- {
- iValue *= 10;
- }
- return iValue;
- }
- // Protected Functions...
- void CvUnitAI::AI_animalMove()
- {
- PROFILE_FUNC();
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting animalMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- //FfH: Added by Kael 10/26/2008 So that animals can build their pens...
- if (!isBarbarian())
- {
- if (AI_construct())
- {
- return;
- }
- // ToDo: here's where we should decide whether or not to keep animals as HN - requires more HN move code
- if (getDomainType() == DOMAIN_SEA)
- {
- if (isHiddenNationality())
- {
- AI_setUnitAIType(UNITAI_PIRATE_SEA);
- }
- else
- {
- AI_setUnitAIType(UNITAI_ATTACK_SEA);
- }
- }
- else
- {
- AI_setUnitAIType(UNITAI_COUNTER);
- }
- return;
- }
- //FfH: End Add
- if (GC.getGameINLINE().getSorenRandNum(100, "Animal Attack") < GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAnimalAttackProb())
- {
- if (AI_anyAttack(1, 0, 0, false))
- {
- return;
- }
- }
- if (AI_heal())
- {
- return;
- }
- if (AI_patrol())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_settleMove()
- {
- PROFILE_FUNC();
-
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting settleMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- /*************************************************************************************************/
- /** BETTER AI (UNITAI_SETTLE move) Sephi **/
- /*************************************************************************************************/
- //reset values after first city is build
- if (kOwner.getNumCities() == 1 && getGroup()->getNumUnits()==1)
- {
- GET_PLAYER(getOwnerINLINE()).AI_updateFoundValues(false);
- }
- // TODO - figure out why the AI does a poor job of settling without this section
- if (kOwner.getNumCities() == 0)
- {
- if (GC.getGameINLINE().getGameTurn()==0)
- {
- kOwner.AI_updateFoundValues(false);
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- iSearchRange = 6;
- int iRange = 6;
- iBestValue = plot()->getFoundValue(getOwnerINLINE());
- pBestPlot = plot();
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (pLoopPlot->isRevealed(getTeam(), false) || pLoopPlot->isAdjacentRevealed(getTeam()))
- {
- if ((AI_plotValid(pLoopPlot)) && canFound(pLoopPlot))
- {
- if (!pLoopPlot->isVisibleEnemyUnit(this))
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns < 2)
- {
- iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if(atPlot(pBestPlot))
- {
- CvCity* pNearestCity;
- pNearestCity = GC.getMapINLINE().findCity(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), NO_PLAYER, getTeam());
- if (pNearestCity != NULL)
- {
- if (plotDistance(plot()->getX_INLINE(), plot()->getY_INLINE(), pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE()) <= 3)
- {
- kOwner.AI_updateFoundValues(false);
- int iNewCityPlotValue = pBestPlot->getFoundValue(getOwnerINLINE());
- if (iNewCityPlotValue < iBestValue)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- getGroup()->pushMission(MISSION_FOUND);
- return;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return;
- }
- }
- }
- if (canFound(plot()))
- {
- getGroup()->pushMission(MISSION_FOUND);
- return;
- }
- }
- // Tholal AI - modified from BBAI
- int iDanger = kOwner.AI_getPlotDanger(plot(), 2);
- int iNeededSettleDefenders = (GC.getGameINLINE().isOption(GAMEOPTION_RAGING_BARBARIANS) ? 4 : 3);
- if (GET_TEAM(getTeam()).isBarbarianAlly() && GET_TEAM(getTeam()).getAtWarCount(true) == 0)
- {
- iNeededSettleDefenders = 2;
- }
- if (GC.getGameINLINE().isOption(GAMEOPTION_NO_BARBARIANS) || GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_PEACE))
- {
- iNeededSettleDefenders -= 1;
- }
- if (iDanger > 0)
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ... in Danger (%d) Zone at plot %d, %d", iDanger, plot()->getX(), plot()->getY());
- if ((plot()->getOwnerINLINE() == getOwnerINLINE()) || (iDanger > getGroup()->getNumUnits()) || !getGroup()->canDefend())
- {
- //if (getGroup()->getNumUnits() < iNeededSettleDefenders)
- if (plot()->getNumDefenders(getOwnerINLINE()) < iNeededSettleDefenders)
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ... not enough defenders; seeking safety (H/N: %d/%d)", plot()->getNumDefenders(getOwnerINLINE()), iNeededSettleDefenders);
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- //getGroup()->pushMission(MISSION_SKIP);
- }
- }
- }
- if (plot()->isCity())
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (getGroup()->getNumUnits() < iNeededSettleDefenders)
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...not enough defenders");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- int iAreaBestFoundValue = 0;
- int iOtherBestFoundValue = 0;
- if( gUnitLogLevel > 3 ) logBBAI(" ...number of city sites: %d", kOwner.AI_getNumCitySites());
- if( gUnitLogLevel > 3 ) logBBAI(" ...min found value: %d", kOwner.AI_getMinFoundValue());
-
- for (int iI = 0; iI < kOwner.AI_getNumCitySites(); iI++)
- {
- CvPlot* pCitySitePlot = kOwner.AI_getCitySite(iI);
- if( gUnitLogLevel > 3 ) logBBAI(" ...checking site at %d, %d", pCitySitePlot->getX(), pCitySitePlot->getY());
- /************************************************************************************************/
- /* UNOFFICIAL_PATCH 01/10/09 jdog5000 */
- /* */
- /* Bugfix, settler AI */
- /************************************************************************************************/
- /* original bts code
- if (pCitySitePlot->getArea() == getArea())
- */
- // Only count city sites we can get to
- if ((pCitySitePlot->getArea() == getArea() || canMoveAllTerrain()) && generatePath(pCitySitePlot, MOVE_AVOID_ENEMY_WEIGHT_3, true))
- /************************************************************************************************/
- /* UNOFFICIAL_PATCH END */
- /************************************************************************************************/
- {
- if (plot() == pCitySitePlot)
- {
- if (canFound(plot()))
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Settler founding in place since it's at a city site %d, %d", getX_INLINE(), getY_INLINE());
- }
- getGroup()->pushMission(MISSION_FOUND);
- return;
- }
- }
- if( gUnitLogLevel > 3 ) logBBAI(" ...found value: %d", pCitySitePlot->getFoundValue(getOwnerINLINE()));
- iAreaBestFoundValue = std::max(iAreaBestFoundValue, pCitySitePlot->getFoundValue(getOwnerINLINE()));
- }
- else
- {
- iOtherBestFoundValue = std::max(iOtherBestFoundValue, pCitySitePlot->getFoundValue(getOwnerINLINE()));
- }
- }
- if( gUnitLogLevel > 3 ) logBBAI(" ...iAreaBestFoundValue: %d", iAreaBestFoundValue);
- if( gUnitLogLevel > 3 ) logBBAI(" ...iOtherBestFoundValue: %d", iOtherBestFoundValue);
- if (iAreaBestFoundValue > 0 && kOwner.getNumCities() == 0)
- {
- if (AI_found())
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/16/09 jdog5000 */
- /* */
- /* Gold AI */
- /************************************************************************************************/
- // No new settling of colonies when AI is in financial trouble
- /*
- if( plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()) )
- {
- if( kOwner.AI_isFinancialTrouble() )
- {
- iOtherBestFoundValue = 0;
- }
- }
- */
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if ((iOtherBestFoundValue * 100) > (iAreaBestFoundValue * 110))
- {
- // Tholal TODO - Make sure we dont board a ship for a distant location unless the ship can take us there
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, 0, MOVE_SAFE_TERRITORY))
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" ... boarding a transport because we have better site in another area");
- }
- return;
- }
- }
- }
- /*
- if ((iAreaBestFoundValue > 0) && plot()->isBestAdjacentFound(getOwnerINLINE()))
- {
- if (canFound(plot()))
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Settler founding in place due to best adjacent found");
- }
- getGroup()->pushMission(MISSION_FOUND);
- return;
- }
- }
- */
- if (!GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_PEACE) && !GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) && !getGroup()->canDefend())
- {
- if (AI_retreatToCity())
- {
- if( gUnitLogLevel >= 2 ){logBBAI(" ... retreating to city due to lack of defense");}
- return;
- }
- }
- if (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0)
- if (kOwner.AI_getAnyPlotDanger(plot())
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- && (GC.getGameINLINE().getMaxCityElimination() > 0))
- {
- if (getGroup()->getNumUnits() < iNeededSettleDefenders)
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... staying in place due to lack of defense");}
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- if (iAreaBestFoundValue > 0)
- {
- if (AI_found())
- {
- return;
- }
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, 0, MOVE_NO_ENEMY_TERRITORY))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... loading onto a Settler transport");}
- return;
- }
- // BBAI TODO: Go to a good city (like one with a transport) ...
- }
- // make sure combat units dont get stuck guarding settlers in cities during wartime
- if (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()))
- {
- if (getGroup()->getNumUnits() > 2)
- {
- if ((GET_TEAM(getTeam()).getAtWarCount(false) > 0) && (iDanger > 0))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... breaking up Settler group");}
- joinGroup(NULL, true);
- return;
- }
- }
- }
- if (!plot()->isCity())
- {
- if (AI_retreatToCity())
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... retreating to city");}
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Settler AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... loading onto ship due to Stranded status");}
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_workerMove()
- {
- PROFILE_FUNC();
- CvCity* pCity;
- bool bCanRoute;
- bool bNextCity;
- bCanRoute = canBuildRoute();
- bNextCity = false;
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting workerMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- if (AI_construct())
- {
- return;
- }
- // Tholal AI - Catch for upgraded worker units
- if (m_pUnitInfo->getWorkRate() == 0)
- {
- AI_setUnitAIType((UnitAITypes)m_pUnitInfo->getDefaultUnitAIType());
- AI_setGroupflag(GROUPFLAG_NONE);
- }
- // slaves can hurry production
- if (GC.getUnitInfo(getUnitType()).getBaseHurry() > 0)
- {
- if (AI_hurry())
- {
- return;
- }
- }
- // XXX could be trouble...
- // Super Forts begin *AI_worker* (removing this to allow workers to build outside borders)
- if(!GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS) && plot()->getOwnerINLINE() != getOwnerINLINE())
- //if (plot()->getOwnerINLINE() != getOwnerINLINE())
- {
- if (AI_retreatToCity())
- {
- return;
- }
- }
- // Super Forts end
- if (!isHuman())
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, 2, -1, -1, 0, MOVE_SAFE_TERRITORY))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... loading onto Settler ship");}
- return;
- }
- }
- }
- /*************************************************************************************************/
- /** Skyre Mod **/
- /** BETTER AI (Workers retreat at Danger ) merged Sephi **/
- /** **/
- /*************************************************************************************************/
- /**Orig
- if (!(getGroup()->canDefend()))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_isPlotThreatened(plot(), 2))
- {
- if (AI_retreatToCity()) // XXX maybe not do this??? could be working productively somewhere else...
- {
- return;
- }
- }
- }
- if (bCanRoute)
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
- {
- BonusTypes eNonObsoleteBonus = plot()->getNonObsoleteBonusType(getTeam());
- if (NO_BONUS != eNonObsoleteBonus)
- {
- if (!(plot()->isConnectedToCapital()))
- {
- ImprovementTypes eImprovement = plot()->getImprovementType();
- if (NO_IMPROVEMENT != eImprovement && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
- {
- if (AI_connectPlot(plot()))
- {
- return;
- }
- }
- }
- }
- }
- }
- CvPlot* pBestBonusPlot = NULL;
- BuildTypes eBestBonusBuild = NO_BUILD;
- int iBestBonusValue = 0;
- if (AI_improveBonus(25, &pBestBonusPlot, &eBestBonusBuild, &iBestBonusValue))
- {
- return;
- }
- **/
- if (kOwner.AI_isPlotThreatened(plot(), 3))
- {
- bool bDanger = true;
- if (bDanger)
- {
- if (AI_retreatToCity())
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... retreating from danger");}
- return;
- }
- }
- }
- CvPlot* pBestBonusPlot = NULL;
- BuildTypes eBestBonusBuild = NO_BUILD;
- int iBestBonusValue = 0;
- // First try to connect resources. Only consider resources inside borders, even if super forts is enabled.
- if (AI_improveBonus(25, &pBestBonusPlot, &eBestBonusBuild, &iBestBonusValue, true))
- {
- return;
- }
- if (bCanRoute)
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
- {
- BonusTypes eNonObsoleteBonus = plot()->getNonObsoleteBonusType(getTeam());
- if (NO_BONUS != eNonObsoleteBonus)
- {
- if (!(plot()->isConnectedToCapital()))
- {
- ImprovementTypes eImprovement = plot()->getImprovementType();
- //if (NO_IMPROVEMENT != eImprovement && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
- if (kOwner.doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus))
- {
- if (AI_connectPlot(plot()))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting the plot on which we're standing");}
- return;
- }
- }
- }
- }
- }
- }
- /*
- if (AI_improveBonus(25, &pBestBonusPlot, &eBestBonusBuild, &iBestBonusValue))
- {
- return;
- }
- */
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- if (bCanRoute && !isBarbarian())
- {
- if (AI_connectCity())
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting some city");}
- return;
- }
- }
- pCity = NULL;
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- pCity = plot()->getPlotCity();
- if (pCity == NULL)
- {
- pCity = plot()->getWorkingCity();
- }
- }
- // if (pCity != NULL)
- // {
- // bool bMoreBuilds = false;
- // for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
- // {
- // CvPlot* pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
- // if ((iI != CITY_HOME_PLOT) && (pLoopPlot != NULL))
- // {
- // if (pLoopPlot->getWorkingCity() == pCity)
- // {
- // if (pLoopPlot->isBeingWorked())
- // {
- // if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT)
- // {
- // if (pCity->AI_getBestBuildValue(iI) > 0)
- // {
- // ImprovementTypes eImprovement;
- // eImprovement = (ImprovementTypes)GC.getBuildInfo((BuildTypes)pCity->AI_getBestBuild(iI)).getImprovement();
- // if (eImprovement != NO_IMPROVEMENT)
- // {
- // bMoreBuilds = true;
- // break;
- // }
- // }
- // }
- // }
- // }
- // }
- // }
- //
- // if (bMoreBuilds)
- // {
- // if (AI_improveCity(pCity))
- // {
- // return;
- // }
- // }
- // }
- if (pCity != NULL)
- {
- /* original bts code (is it just me, or did they get this backwards?)
- if ((pCity->AI_getWorkersNeeded() > 0) && (plot()->isCity() || (pCity->AI_getWorkersNeeded() < ((1 + pCity->AI_getWorkersHave() * 2) / 3)))) */
- // K-Mod
- if (pCity->AI_getWorkersNeeded() > 0 && (plot()->isCity() || pCity->AI_getWorkersHave() < (1 + pCity->AI_getWorkersNeeded() * 2) / 3))
- // K-Mod end
- {
- if (AI_improveCity(pCity))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... improving city %S", pCity->getName().c_str());}
- return;
- }
- }
- }
- if (AI_improveLocalPlot(2, pCity))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... improving local plot");}
- return;
- }
-
- bool bBuildFort = false;
-
- if (GC.getGame().getSorenRandNum(5, "AI Worker build Fort with Priority") == 1)
- {
- // Super Forts begin *canal* *choke*
- //CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- bool bCanal = kOwner.countNumCoastalCities() > 0; //((100 * area()->getNumCities()) / std::max(1, GC.getGame().getNumCities()) < 85);
- bool bAirbase = false;
- bAirbase = (kOwner.AI_totalUnitAIs(UNITAI_PARADROP) || kOwner.AI_totalUnitAIs(UNITAI_ATTACK_AIR) || kOwner.AI_totalUnitAIs(UNITAI_MISSILE_AIR));
-
- // if (bCanal || bAirbase)
- // {
- if (AI_fortTerritory(bCanal, bAirbase))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... build fort");}
- return;
- }
- // }
- bBuildFort = bCanal && bAirbase;
- }
- // Super Forts end
- if (bCanRoute && isBarbarian())
- {
- if (AI_connectCity())
- {
- // LFGR_TODO: Can this ever happen? Same checks above.
- if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting some city");}
- return;
- }
- }
- if ((pCity == NULL) || (pCity->AI_getWorkersNeeded() == 0) || ((pCity->AI_getWorkersHave() > (pCity->AI_getWorkersNeeded() + 1))))
- {
- if ((pBestBonusPlot != NULL) && (iBestBonusValue >= 15))
- {
- if (AI_improvePlot(pBestBonusPlot, eBestBonusBuild))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting bonus with low priority that we found earlier");}
- return;
- }
- }
- // if (pCity == NULL)
- // {
- // pCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE()); // XXX do team???
- // }
- if (AI_nextCityToImprove(pCity))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... improve next city");}
- return;
- }
- bNextCity = true;
- }
- if (pBestBonusPlot != NULL)
- {
- if (AI_improvePlot(pBestBonusPlot, eBestBonusBuild))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting bonus with very low priority that we found earlier");}
- return;
- }
- }
- // Second try to connect resources, outside borders with super forts
- if( GC.getGameINLINE().isOption( GAMEOPTION_ADVANCED_TACTICS ) )
- {
- // Only do this if we have defenders to spare for the fort.
- bool bDefendersAvailable = true; // LFGR_TODO
- /*bool bDefendersAvailable = false;
- CvPlayerAI& kOwner = GET_PLAYER( getOwnerINLINE() );
- int iLoop;
- for( CvCity* pLoopCity = kOwner.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kOwner.nextCity(&iLoop) )
- {
- if( pLoopCity->area()->getID() == area()->getID() )
- {
- int iDefenders = pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE());
- iDefenders += pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_COUNTER, -1, getOwnerINLINE());
- if( pLoopCity->AI_neededDefenders() < iDefenders ) {
- bDefendersAvailable = true;
- break;
- }
- }
- }*/
-
- if( bDefendersAvailable ) {
- if( AI_improveBonus() ) {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting bonus outside borders");}
- return;
- }
- }
- else {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... don't try to connect bonus outside borders: no defenders available!");}
- }
- }
- if (pCity != NULL)
- {
- if (AI_improveCity(pCity))
- {
- return;
- }
- }
- if (!bNextCity)
- {
- if (AI_nextCityToImprove(pCity))
- {
- return;
- }
- }
- if (bCanRoute)
- {
- if (AI_routeTerritory(true))
- {
- return;
- }
- if (AI_connectBonus(false))
- {
- return;
- }
- if (AI_routeCity())
- {
- return;
- }
- }
- if (AI_irrigateTerritory())
- {
- return;
- }
- // Super Forts begin *canal* *choke*
- if (!bBuildFort)
- {
- if (AI_fortTerritory(true, true /*bCanal, bAirbase*/))
- {
- return;
- }
- }
- /* if (!bBuildFort)
- {
- bool bCanal = ((100 * area()->getNumCities()) / std::max(1, GC.getGame().getNumCities()) < 85);
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- bool bAirbase = false;
- bAirbase = (kPlayer.AI_totalUnitAIs(UNITAI_PARADROP) || kPlayer.AI_totalUnitAIs(UNITAI_ATTACK_AIR) || kPlayer.AI_totalUnitAIs(UNITAI_MISSILE_AIR));
-
- if (bCanal || bAirbase)
- {
- if (AI_fortTerritory(bCanal, bAirbase))
- {
- return;
- }
- }
- }*/
- // Super Forts end
- if (bCanRoute)
- {
- if (AI_routeTerritory())
- {
- return;
- }
- }
- if (!isHuman() || (isAutomated() && GET_TEAM(getTeam()).getAtWarCount(true) == 0))
- {
- if (!isHuman() || (getGameTurnCreated() < GC.getGame().getGameTurn()))
- {
- if (AI_nextCityToImproveAirlift())
- {
- return;
- }
- }
- if (!isHuman())
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/14/09 jdog5000 */
- /* */
- /* Worker AI */
- /************************************************************************************************/
- /*
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY))
- {
- return;
- }
- */
- // Fill up boats which already have workers
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_WORKER, -1, -1, -1, -1, MOVE_SAFE_TERRITORY))
- {
- return;
- }
- // Avoid filling a galley which has just a settler in it, reduce chances for other ships
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, 2, -1, -1, MOVE_SAFE_TERRITORY))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- }
- if (AI_improveLocalPlot(3, NULL))
- {
- return;
- }
- /*************************************************************************************************/
- /** BETTER AI (stop AI from deleting workers) Sephi **/
- /** **/
- /** **/
- /*************************************************************************************************/
- /**
- if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_WORKER))
- {
- if (GC.getGameINLINE().getElapsedGameTurns() > 10)
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_WORKER) > GET_PLAYER(getOwnerINLINE()).getNumCities())
- {
- if (GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
- {
- scrap();
- return;
- }
- }
- }
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- if (AI_retreatToCity(false, true))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... connecting bonus outside of borders with a super fort");}
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Worker AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_barbAttackMove()
- {
- PROFILE_FUNC();
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting barbAttackMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- // catch for wrong AI - units spawned through lair events maybe?
- if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL"))
- {
- AI_setUnitAIType(UNITAI_PIRATE_SEA);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (isAnimal())
- {
- AI_setUnitAIType(UNITAI_ANIMAL);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- // ALN Notes: This is an experiment in mixing up barb behaivor, some will attack earlier, some later in terms of civ developement
- // the more 'cautious' they are, the later they will step up their attacks against civilized lands
- // 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
- // but still give some breathing room early on
- bool bRagingBarbs = GC.getGameINLINE().isOption(GAMEOPTION_RAGING_BARBARIANS);
- bool bBarbWorld = GC.getGameINLINE().isOption(GAMEOPTION_BARBARIAN_WORLD);
- bool bHero = AI_getUnitAIType() == UNITAI_HERO;
- bool bAttack = AI_getUnitAIType() == UNITAI_ATTACK;
- bool bAttackCity = AI_getUnitAIType() == UNITAI_ATTACK_CITY;
- int iPillage = AI_getBirthmark2() % 10;
- if (!isAlive())
- {
- iPillage = 0;
- }
-
- // pay attention to where we are
- bool bFriendlyTerritory = false;
- bool bEnemyTerritory = false;
- if (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE())
- {
- if (!isEnemy(plot()->getTeam()))
- {
- bFriendlyTerritory = true;
- }
- else
- {
- bEnemyTerritory = true;
- }
- }
- int iMaxFollowers;
- int iLeadership = AI_getBarbLeadership(iMaxFollowers);
- int iHeroAttMod = (bHero ? 10 + (AI_getBirthmark() % 15) : 0);
-
- // 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
- int iCaution = 2;
- iCaution += AI_getBirthmark() % 7;
- if (bHero)
- {
- // Barbarian Heros hang back till they level up typically
- iCaution += 6 - getLevel();
- }
- // larger stacks more likely to attack civs
- iCaution -= (getGroup()->getNumUnits() - 1);
- // more aggressive (attack cities earlier) when raging barbarians is on
- if (bRagingBarbs)
- {
- iCaution -= 2;
- }
- else if (bBarbWorld)
- {
- iCaution -= 1;
- }
- if (!isAlive())
- {
- iCaution = 0;
- }
- iCaution = std::max(0, iCaution);
-
- // how likely they are to attack against poor odds
- int iRecklessness = iHeroAttMod + (iPillage) - (int)pow((float)(GC.getGameINLINE().getSorenRandNum(100, "AI Barb")), 0.5f);
- if (!isAlive())
- {
- iRecklessness -= 10;
- }
-
- // Aggression steps based on units caution level and number of civilized cities per player
- bool bAggressive = (GC.getGameINLINE().getNumCivCities() > (GC.getGameINLINE().countCivPlayersAlive() * iCaution / 2));
- bool bSemiAggressive = (GC.getGameINLINE().getNumCivCities() > (GC.getGameINLINE().countCivPlayersAlive() * iCaution / 3));
- bool bPassiveAggressive = (GC.getGameINLINE().getNumCivCities() > (GC.getGameINLINE().countCivPlayersAlive() * iCaution / 4) || bEnemyTerritory);
-
- // heros and aggressive units will wait till someone else starts defending the plot then move on
- // otherwise switch UnitAIs
- /*
- if (!bHero && plot()->isLair(false, isAnimal()))
- {
- if (plot()->plotCount(PUF_isUnitAIType, UNITAI_LAIRGUARDIAN, -1, (PlayerTypes)BARBARIAN_PLAYER) == 0)
- {
- // ToDo, split off a unit to guard it if we are in a group
- if ((!bHero || iCaution >= 4) && getGroup()->getNumUnits() == 1)
- {
- AI_setUnitAIType(UNITAI_LAIRGUARDIAN);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- else // wait till we have a guard unit
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- */
-
- // Heros shouldn't be guarding cities or goodies
- if (!bHero && ((!bAttackCity || !bAttack) && iCaution > 4))
- {
- if (getDomainType() == DOMAIN_LAND)
- {
- if (AI_guardCity(false, true, 1))
- {
- return;
- }
- }
- if (plot()->isGoody())
- {
- if (plot()->plotCount(PUF_isUnitAIType, UNITAI_ATTACK, -1, getOwnerINLINE()) == 1)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- // new grouping code
- // higher leadership barbs will wait at longer path lengths
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- int iJoiners = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), (iLeadership > 7 ? 3 : 2));
-
- // wait for joiners
- int iFollowers = getGroup()->getNumUnits() - 1;
- if (iLeadership > 5)
- {
- if (iJoiners > 0 && !bEnemyTerritory)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- // look for higher leadership barbs to join with
- if (iLeadership <= 8 && (bSemiAggressive || bAggressive))
- {
- if (bEnemyTerritory)
- {
- if (AI_groupBarbLeader(1))
- {
- return;
- }
- }
- else
- {
- if (AI_groupBarbLeader(2))
- {
- return;
- }
- }
- }
- // Pillaging
- if (isAlive())
- {
- if (GC.getGameINLINE().getSorenRandNum(20, "AI Barb") + iPillage >= 15)
- {
- if (AI_pillageRange(1))
- {
- return;
- }
- }
- }
-
- // General Attack on adjacent units
- if (AI_anyAttack(1, std::max(10, 20 + iRecklessness)))
- {
- return;
- }
- // don't wander aimlessly in Clan territory, please
- if (bFriendlyTerritory)
- {
- if (AI_goToTargetCity(0, 12))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- }
-
- // Aggressive movements (actively seek out distant cities)
- if (bAggressive)
- {
- // high pillage barbs get another go at this check
- if (iPillage > 5 && isAlive())
- {
- if (GC.getGameINLINE().getSorenRandNum(20, "AI Barb") + iPillage >= 15)
- {
- if (AI_pillageRange(1))
- {
- return;
- }
- }
- }
- if (AI_cityAttack(1, std::max(8, 15 + iRecklessness)))
- {
- return;
- }
- if (isAlive())
- {
- if (AI_pillageRange(3))
- {
- return;
- }
- }
- if (AI_cityAttack(2, std::max(5, 10 + iRecklessness), true))
- {
- return;
- }
- if (AI_goToTargetCity(0, 12))
- {
- return;
- }
- }
- // Semi-Aggressive Movements (attack cities if nearby)
- if (bSemiAggressive)
- {
- // high pillage barbs get another go at this check
- if (iPillage > 5 && isAlive())
- {
- if (GC.getGameINLINE().getSorenRandNum(20, "AI Barb") + iPillage >= 15)
- {
- if (AI_pillageRange(1))
- {
- return;
- }
- }
- }
- if (AI_cityAttack(1, std::max(8, 15 + iRecklessness)))
- {
- return;
- }
- if (isAlive())
- {
- if (AI_pillageRange(3))
- {
- return;
- }
- }
- if (AI_cityAttack(1, std::max(5, 10 + iRecklessness)))
- {
- return;
- }
- if (AI_goToTargetCity(0, 4))
- {
- return;
- }
- }
- // Cautious Movements (only cause trouble if they stumble into it)
- if (bPassiveAggressive)
- {
- if (isAlive())
- {
- if (AI_pillageRange(2))
- {
- return;
- }
- }
- if (AI_cityAttack(1, std::max(5, 10 + iRecklessness)))
- {
- return;
- }
- }
-
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 1))
- {
- return;
- }
- if (AI_heal())
- {
- return;
- }
-
- if (!bHero && (getDomainType() == DOMAIN_LAND))
- {
- if (AI_guardCity(false, true, 2))
- {
- return;
- }
- }
- /* if (AI_groupBarbLeader(3))
- {
- return;
- } */
-
- if (AI_patrol())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_attackMove()
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_attackMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- PROFILE_FUNC();
- if (GET_PLAYER(getOwnerINLINE()).getNumCities() == 0)
- {
- if (AI_shadow(UNITAI_SETTLE, -1, -1, false, false, 5))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... defend settler" );}
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 05/14/10 jdog5000 */
- /* */
- /* Unit AI, Settler AI, Efficiency */
- /************************************************************************************************/
- bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
- bool bLandWar = GET_PLAYER(getOwnerINLINE()).AI_isLandWar(area()); // K-Mod
- if( getGroup()->getNumUnits() > 2 )
- {
- UnitAITypes eGroupAI = getGroup()->getHeadUnitAI();
- if( eGroupAI == AI_getUnitAIType() )
- {
- if( plot()->getOwnerINLINE() == getOwnerINLINE() && !bDanger )
- {
- // Shouldn't have groups of > 2 attack units
- if( getGroup()->countNumUnitAIType(UNITAI_ATTACK) > 2 )
- {
- getGroup()->AI_separate(); // will change group
- FAssert( eGroupAI == getGroup()->getHeadUnitAI() );
- }
- // Should never have attack city group lead by attack unit
- if( getGroup()->countNumUnitAIType(UNITAI_ATTACK_CITY) > 0 )
- {
- getGroup()->AI_separateAI(UNITAI_ATTACK_CITY); // will change group
- // Since ATTACK can try to joing ATTACK_CITY again, need these units to
- // take a break to let ATTACK_CITY group move and avoid hang
- getGroup()->pushMission(MISSION_SKIP);
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... take a break while ATTACK_CITY stack move along" );}
- return;
- }
- }
- }
- }
- // Attack choking units
- if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() && bDanger )
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if( iOurDefense < 3*iEnemyOffense )
- {
- if (AI_guardCity(true))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> guard city" );}
- return;
- }
- }
- if( iOurDefense > 2*iEnemyOffense )
- {
- if (AI_anyAttack(2, 55))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack!" );}
- return;
- }
- }
- if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, false))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> merge" );}
- return;
- }
- if( iOurDefense > 2*iEnemyOffense )
- {
- if (AI_anyAttack(2, 30))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack!" );}
- return;
- }
- }
- }
- {
- PROFILE("CvUnitAI::AI_attackMove() 1");
- // Guard a city we're in if it needs it
- if (AI_guardCity(true))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... guard city" );}
- return;
- }
- if( !(plot()->isOwned()) )
- {
- // Group with settler after naval drop
- if( AI_groupMergeRange(UNITAI_SETTLE, 2, true, false, false) )
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... group with settler (after naval drop?)" );}
- return;
- }
- }
- if( !(plot()->isOwned()) || (plot()->getOwnerINLINE() == getOwnerINLINE()) )
- {
- if( area()->getCitiesPerPlayer(getOwnerINLINE()) > GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(area(), UNITAI_CITY_DEFENSE) )
- {
- // Defend colonies in new world
- if (AI_guardCity(true, true, 3))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... defend colonies in new world" );}
- return;
- }
- }
- }
- if (AI_heal(30, 1))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... heal" );}
- return;
- }
-
- if (!bDanger)
- {
- if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 3, true))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> group with settler" );}
- return;
- }
- if (AI_group(UNITAI_SETTLE, 2, -1, -1, false, false, false, 3, true))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> group with settler" );}
- return;
- }
- if( AI_guardFortMinDefender( true ) ) {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> defend fort" );}
- return;
- }
- }
- if (AI_guardCityAirlift())
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... AI_guardCityAirlift" );}
- return;
- }
- if (AI_guardCity(false, true, 1))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... guard city" );}
- return;
- }
- //join any city attacks in progress
- if (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE())
- {
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... join city attack in progress" );}
- return;
- }
- }
- AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
- if (plot()->isCity())
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
- {
- if (AI_offensiveAirlift())
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... offensive airlift" );}
- return;
- }
- }
- }
- }
- if (bDanger)
- {
- if (AI_cityAttack(1, 55))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack city!" );}
- return;
- }
- if (AI_anyAttack(1, 65))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack!" );}
- return;
- }
- if (collateralDamage() > 0)
- {
- if (AI_anyAttack(1, 45, 3))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... danger -> attack!" );}
- return;
- }
- }
- }
- if (!noDefensiveBonus())
- {
- if (AI_guardCity(false, false))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... guard city" );}
- return;
- }
- }
- if (!bDanger)
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- bool bAssault = ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_MASSING) || (eAreaAIType == AREAAI_ASSAULT_ASSIST));
- if ( bAssault )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> load" );}
- return;
- }
- }
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, -1, 1, MOVE_SAFE_TERRITORY, 3))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> load" );}
- return;
- }
- //bool bLandWar = ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
- if (!bLandWar)
- {
- // Fill transports before starting new one, but not just full of our unit ai
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> load" );}
- return;
- }
- // Pick new transport which has space for other unit ai types to join
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, 2, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> load" );}
- return;
- }
- }
- if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) > 0) // LFGR_TODO: I don't really understand this
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... no danger -> wait (?)" );}
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- // Allow larger groups if outside territory
- if( getGroup()->getNumUnits() < 3 )
- {
- if( plot()->isOwned() && GET_TEAM(getTeam()).isAtWar(plot()->getTeam()) )
- {
- if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, true))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... outside territory, merge" );}
- return;
- }
- }
- }
- if (AI_goody(3))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... get goody" );}
- return;
- }
- if (AI_anyAttack(1, 70))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... attack!" );}
- return;
- }
- }
- {
- PROFILE("CvUnitAI::AI_attackMove() 2");
- if (bDanger)
- {
- if (AI_pillageRange(1, 20))
- {
- return;
- }
- if (AI_cityAttack(1, 35))
- {
- return;
- }
- if (AI_anyAttack(1, 45))
- {
- return;
- }
- if (AI_pillageRange(3, 20))
- {
- return;
- }
- if( getGroup()->getNumUnits() < 4 )
- {
- if (AI_choke(1))
- {
- return;
- }
- }
-
- if (AI_cityAttack(4, 30))
- {
- return;
- }
- if (AI_anyAttack(2, 40))
- {
- return;
- }
- }
- if (!isEnemy(plot()->getTeam()))
- {
- if (AI_heal())
- {
- return;
- }
- }
- /************************************************************************************************/
- /* REVOLUTION_MOD 02/11/09 jdog5000 */
- /* */
- /* Revolution AI */
- /************************************************************************************************/
- // Change grouping rules shortly after civ creation
- if( GET_PLAYER(getOwnerINLINE()).getFreeUnitCountdown() > 0 )
- {
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, false, true, true))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* REVOLUTION_MOD END */
- /************************************************************************************************/
- if ((GET_PLAYER(getOwnerINLINE()).AI_getNumAIUnits(UNITAI_CITY_DEFENSE) > 0) || (GET_TEAM(getTeam()).getAtWarCount(true) > 0))
- {
- // BBAI TODO: If we're fast, maybe shadow an attack city stack and pillage off of it
- bool bIgnoreFaster = false;
- if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
- {
- if (area()->getAreaAIType(getTeam()) != AREAAI_ASSAULT)
- {
- bIgnoreFaster = true;
- }
- }
- if (AI_group(UNITAI_ATTACK_CITY, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 5))
- {
- return;
- }
- if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, true, true, false, /*iMaxPath*/ 4))
- {
- return;
- }
-
- // BBAI TODO: Need group to be fast, need to ignore slower groups
- //if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_FASTMOVERS))
- //{
- // if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 4, /*iMaxOwnUnitAI*/ 1, -1, true, false, false, /*iMaxPath*/ 3))
- // {
- // return;
- // }
- //}
- if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, true, false, false, /*iMaxPath*/ 1))
- {
- return;
- }
- }
- if (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
- {
- if (getGroup()->getNumUnits() > 1)
- {
- //if (AI_targetCity())
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12))
- {
- return;
- }
- }
- }
- else if( area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE )
- {
- if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0)
- {
- if (getGroup()->getNumUnits() >= GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getBarbarianInitialDefenders())
- {
- if (AI_goToTargetBarbCity(10))
- {
- return;
- }
- }
- }
- }
- if (AI_guardCity(false, true, 3))
- {
- return;
- }
- if ((GET_PLAYER(getOwnerINLINE()).getNumCities() > 1) && (getGroup()->getNumUnits() == 1))
- {
- if (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE)
- {
- if (area()->getNumUnrevealedTiles(getTeam()) > 0)
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_areaMissionAIs(area(), MISSIONAI_EXPLORE, getGroup()) < (GET_PLAYER(getOwnerINLINE()).AI_neededExplorers(area()) + 1))
- {
- if (AI_exploreRange(3))
- {
- return;
- }
- if (AI_explore())
- {
- return;
- }
- }
- }
- }
- }
- if (AI_protect(35, 5))
- {
- return;
- }
- if (AI_offensiveAirlift())
- {
- return;
- }
- if (!bDanger && (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE))
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) && !(getGroup()->isHasPathToAreaEnemyCity(false)) )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- }
- }
- if (AI_defend())
- {
- return;
- }
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- if( !bDanger && !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
- {
- // If no other desireable actions, wait for pickup
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if( getGroup()->getNumUnits() < 4 )
- {
- if (AI_patrol())
- {
- return;
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- void CvUnitAI::AI_paratrooperMove()
- {
- PROFILE_FUNC();
- bool bHostile = (plot()->isOwned() && isPotentialEnemy(plot()->getTeam()));
- if (!bHostile)
- {
- if (AI_guardCity(true))
- {
- return;
- }
-
- if (plot()->getTeam() == getTeam())
- {
- if (plot()->isCity())
- {
- if (AI_heal(30, 1))
- {
- return;
- }
- }
-
- AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
- //bool bLandWar = ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
- bool bLandWar = GET_PLAYER(getOwnerINLINE()).AI_isLandWar(area()); // K-Mod
- if (!bLandWar)
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, 0, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- }
- if (AI_guardCity(false, true, 1))
- {
- return;
- }
- }
- if (AI_cityAttack(1, 45))
- {
- return;
- }
- if (AI_anyAttack(1, 55))
- {
- return;
- }
- if (!bHostile)
- {
- if (AI_paradrop(getDropRange()))
- {
- return;
- }
- if (AI_offensiveAirlift())
- {
- return;
- }
- if (AI_moveToStagingCity())
- {
- return;
- }
- if (AI_guardFort(true))
- {
- return;
- }
- if (AI_guardCityAirlift())
- {
- return;
- }
- }
- if (collateralDamage() > 0)
- {
- if (AI_anyAttack(1, 45, 3))
- {
- return;
- }
- }
- if (AI_pillageRange(1, 15))
- {
- return;
- }
- if (bHostile)
- {
- if (AI_choke(1))
- {
- return;
- }
- }
- if (AI_heal())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- //if (AI_protect(35))
- if (AI_protect(35, 5))
- {
- return;
- }
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/02/10 jdog5000 */
- /* */
- /* War tactics AI, Barbarian AI */
- /************************************************************************************************/
- void CvUnitAI::AI_attackCityMove()
- {
- PROFILE_FUNC();
- logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_attackCityMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
- AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
- //bool bLandWar = !isBarbarian() && ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
- bool bLandWar = !isBarbarian() && kOwner.AI_isLandWar(area()); // K-Mod
- bool bAssault = !isBarbarian() && ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) || (eAreaAIType == AREAAI_ASSAULT_MASSING));
- bool bTurtle = kOwner.AI_isDoStrategy(AI_STRATEGY_TURTLE);
- bool bAlert1 = kOwner.AI_isDoStrategy(AI_STRATEGY_ALERT1);
- bool bIgnoreFaster = false;
- if (kOwner.AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
- {
- if (!bAssault && area()->getCitiesPerPlayer(getOwnerINLINE()) > 0)
- {
- bIgnoreFaster = true;
- }
- }
- // Super Forts begin *AI_offense* - allow stack to split after capturing a fort in addition to cities
- bool bInCity = plot()->isCity(true);
- //bool bInCity = plot()->isCity(); // Original Code
- // Super Forts end
- if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
- {
- // force heal if we in our own city and damaged
- // can we remove this or call AI_heal here?
- if ((getGroup()->getNumUnits() == 1) && (getDamage() > 0))
- {
- getGroup()->pushMission(MISSION_HEAL);
- return;
- }
- if( bIgnoreFaster )
- {
- // BBAI TODO: split out slow units ... will need to test to make sure this doesn't cause loops
- }
- // Super Forts begin *AI_offense* - allow stack to split after capturing a fort in addition to cities
- if (plot()->getOwnershipDuration() <= 1)
- //if ((GC.getGame().getGameTurn() - plot()->getPlotCity()->getGameTurnAcquired()) <= 1) // Original Code
- // Super Forts end
- {
- CvSelectionGroup* pOldGroup = getGroup();
- pOldGroup->AI_separateNonAI(UNITAI_ATTACK_CITY);
- if (pOldGroup != getGroup())
- {
- return;
- }
- }
- if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
- {
- if (AI_offensiveAirlift())
- {
- return;
- }
- }
- }
- bool bAtWar = isEnemy(plot()->getTeam());
- bool bHuntBarbs = false;
- if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0 && !isBarbarian())
- {
- if ((eAreaAIType != AREAAI_OFFENSIVE) && (eAreaAIType != AREAAI_DEFENSIVE) && !bAlert1 && !bTurtle)
- {
- bHuntBarbs = true;
- }
- }
- bool bReadyToAttack = false;
- if( !bTurtle )
- {
- bReadyToAttack = ((getGroup()->getNumUnits() >= ((bHuntBarbs) ? 3 : AI_stackOfDoomExtra())));
- }
- if( isBarbarian() )
- {
- bLandWar = (area()->getNumCities() - area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0);
- bReadyToAttack = (getGroup()->getNumUnits() >= 3);
- }
-
- if( bReadyToAttack )
- {
- // Check that stack has units which can capture cities
- bReadyToAttack = false;
- int iCityCaptureCount = 0;
- CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
- while (pUnitNode != NULL && !bReadyToAttack)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- if( !pLoopUnit->isOnlyDefensive() )
- {
- if( !(pLoopUnit->isNoCapture()) && (pLoopUnit->combatLimit() >= 100) )
- {
- iCityCaptureCount++;
- if( iCityCaptureCount > 5 || 3*iCityCaptureCount > getGroup()->getNumUnits() )
- {
- bReadyToAttack = true;
- }
- }
- }
- }
- }
- if (AI_guardCity(false, false))
- {
- if( bReadyToAttack && (eAreaAIType != AREAAI_DEFENSIVE))
- {
- CvSelectionGroup* pOldGroup = getGroup();
- pOldGroup->AI_separateNonAI(UNITAI_ATTACK_CITY);
- }
- return;
- }
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 0, true, true, bIgnoreFaster))
- {
- return;
- }
-
- CvCity* pTargetCity = NULL;
- if( isBarbarian() )
- {
- pTargetCity = AI_pickTargetCity(0, 12);
- }
- else
- {
- // BBAI TODO: Find some way of reliably targetting nearby cities with less defense ...
- pTargetCity = AI_pickTargetCity(0, MAX_INT, bHuntBarbs);
- }
- if( pTargetCity != NULL )
- {
- int iStepDistToTarget = stepDistance(pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), getX_INLINE(), getY_INLINE());
- int iAttackRatio = std::max(100, GC.getBBAI_ATTACK_CITY_STACK_RATIO());
- if( isBarbarian() )
- {
- iAttackRatio = 80;
- }
- int iComparePostBombard = 0;
- // AI gets a 1-tile sneak peak to compensate for lack of memory
- if( iStepDistToTarget <= 2 || pTargetCity->isVisible(getTeam(),false) )
- {
- iComparePostBombard = getGroup()->AI_compareStacks(pTargetCity->plot(), true, true, true);
- int iDefenseModifier = pTargetCity->getDefenseModifier(true);
- int iBombardTurns = getGroup()->getBombardTurns(pTargetCity);
- iDefenseModifier *= std::max(0, 20 - iBombardTurns);
- iDefenseModifier /= 20;
- iComparePostBombard *= 100 + std::max(0, iDefenseModifier);
- iComparePostBombard /= 100;
- }
- if( iStepDistToTarget <= 2 )
- {
- if( iComparePostBombard < iAttackRatio )
- {
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
- {
- return;
- }
- int iOurOffense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),1,false,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pTargetCity->plot(),2,false,false);
- // If in danger, seek defensive ground
- if( 4*iOurOffense < 3*iEnemyOffense )
- {
- if( AI_choke(1, true) )
- {
- return;
- }
- }
- }
- if (iStepDistToTarget == 1)
- {
- // If next to target city and we would attack after bombarding down defenses,
- // or if defenses have crept up past half
- if( (iComparePostBombard >= iAttackRatio) || (pTargetCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE() * 1) / 2)) )
- {
- if( (iComparePostBombard < std::max(150, GC.getDefineINT("BBAI_SKIP_BOMBARD_MIN_STACK_RATIO"))) )
- {
- // Move to good tile to attack from unless we're way more powerful
- if( AI_goToTargetCity(0,1,pTargetCity) )
- {
- return;
- }
- }
- // Bombard may skip if stack is powerful enough
- if (AI_bombardCity())
- {
- return;
- }
- //stack attack
- if (getGroup()->getNumUnits() > 1)
- {
- // BBAI TODO: What is right ratio?
- if (AI_stackAttackCity(1, iAttackRatio, true))
- {
- return;
- }
- }
- // If not strong enough alone, merge if another stack is nearby
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
- {
- return;
- }
-
- if( getGroup()->getNumUnits() == 1 )
- {
- if( AI_cityAttack(1, 50) )
- {
- return;
- }
- }
- }
- }
- if( iComparePostBombard < iAttackRatio )
- {
- // If not strong enough, pillage around target city without exposing ourselves
- if( AI_pillageRange(0) )
- {
- return;
- }
-
- if( AI_anyAttack(1, 60, 0, false) )
- {
- return;
- }
- if (AI_heal(30, 1))
- {
- return;
- }
- // Pillage around enemy city
- if( AI_pillageAroundCity(pTargetCity, 11, 3) )
- {
- return;
- }
- if( AI_pillageAroundCity(pTargetCity, 0, 5) )
- {
- return;
- }
- if( AI_choke(1) )
- {
- return;
- }
- }
- else
- {
- if( AI_goToTargetCity(0,4,pTargetCity) )
- {
- return;
- }
- }
- }
- }
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
- {
- return;
- }
- if (AI_heal(30, 1))
- {
- return;
- }
- // BBAI TODO: Stack v stack combat ... definitely want to do in own territory, but what about enemy territory?
- if (collateralDamage() > 0 && plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_anyAttack(1, 45, 3, false))
- {
- return;
- }
- if( !bReadyToAttack )
- {
- if (AI_anyAttack(1, 25, 5, false))
- {
- return;
- }
- }
- }
- if (AI_anyAttack(1, 60, 0, false))
- {
- return;
- }
- if (bAtWar && (getGroup()->getNumUnits() <= 2))
- {
- if (AI_pillageRange(3, 11))
- {
- return;
- }
- if (AI_pillageRange(1))
- {
- return;
- }
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (!bLandWar)
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- if( bReadyToAttack )
- {
- // Wait for units about to join our group
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- int iJoiners = kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
-
- if( (iJoiners*5) > getGroup()->getNumUnits() )
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- else
- {
- if( !isBarbarian() && (eAreaAIType == AREAAI_DEFENSIVE) )
- {
- // Use smaller attack city stacks on defense
- if (AI_guardCity(false, true, 3))
- {
- return;
- }
- }
- if( bTurtle )
- {
- if (AI_guardCity(false, true, 7))
- {
- return;
- }
- }
- int iTargetCount = kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
- if ((iTargetCount * 5) > getGroup()->getNumUnits())
- {
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- int iJoiners = kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
-
- if( (iJoiners*5) > getGroup()->getNumUnits() )
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_moveToStagingCity())
- {
- return;
- }
- }
- }
- }
- if (AI_heal(50, 3))
- {
- return;
- }
- if (!bAtWar)
- {
- if (AI_heal())
- {
- return;
- }
- if ((getGroup()->getNumUnits() == 1) && (getTeam() != plot()->getTeam()))
- {
- if (AI_retreatToCity())
- {
- return;
- }
- }
- }
- if (!bReadyToAttack && !noDefensiveBonus())
- {
- if (AI_guardCity(false, false))
- {
- return;
- }
- }
- bool bAnyWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
- if (bReadyToAttack)
- {
- if( isBarbarian() )
- {
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12))
- {
- return;
- }
- if (AI_pillageRange(3, 11))
- {
- return;
- }
- if (AI_pillageRange(1))
- {
- return;
- }
- }
- else if (bHuntBarbs && AI_goToTargetBarbCity((bAnyWarPlan ? 7 : 12)))
- {
- return;
- }
- else if (bLandWar && pTargetCity != NULL)
- {
- // Before heading out, check whether to wait to allow unit upgrades
- if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
- {
- if( !kOwner.AI_isFinancialTrouble() )
- {
- // Check if stack has units which can upgrade
- int iNeedUpgradeCount = 0;
- CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- if( pLoopUnit->getUpgradeCity(false) != NULL )
- {
- iNeedUpgradeCount++;
- if( 8*iNeedUpgradeCount > getGroup()->getNumUnits() )
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- }
- }
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 5, pTargetCity))
- {
- return;
- }
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 2, 2))
- {
- return;
- }
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 8, pTargetCity))
- {
- return;
- }
- // Load stack if walking will take a long time
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 3))
- {
- return;
- }
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12, pTargetCity))
- {
- return;
- }
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 7))
- {
- return;
- }
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, MAX_INT, pTargetCity))
- {
- return;
- }
- if (bAnyWarPlan)
- {
- CvCity* pTargetCity = area()->getTargetCity(getOwnerINLINE());
- if (pTargetCity != NULL)
- {
- if (AI_solveBlockageProblem(pTargetCity->plot(), (GET_TEAM(getTeam()).getAtWarCount(true) == 0)))
- {
- return;
- }
- }
- }
- }
- }
- else
- {
- int iTargetCount = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
- if( ((iTargetCount * 4) > getGroup()->getNumUnits()) || ((getGroup()->getNumUnits() + iTargetCount) >= (bHuntBarbs ? 3 : AI_stackOfDoomExtra())) )
- {
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- int iJoiners = kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
-
- if( (iJoiners*6) > getGroup()->getNumUnits() )
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- if ((bombardRate() > 0) && noDefensiveBonus())
- {
- // BBAI Notes: Add this stack lead by bombard unit to stack probably not lead by a bombard unit
- // BBAI TODO: Some sense of minimum stack size? Can have big stack moving 10 turns to merge with tiny stacks
- if (AI_group(UNITAI_ATTACK_CITY, -1, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ true))
- {
- return;
- }
- }
- else
- {
- if (AI_group(UNITAI_ATTACK_CITY, AI_stackOfDoomExtra() * 2, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ false))
- {
- return;
- }
- }
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE() && bLandWar)
- {
- if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) )
- {
- // if no land path to enemy cities, try getting there another way
- if (AI_offensiveAirlift())
- {
- return;
- }
- if( pTargetCity == NULL )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- }
- }
- if (AI_moveToStagingCity())
- {
- return;
- }
- if (AI_offensiveAirlift())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- if( !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
- {
- // If no other desireable actions, wait for pickup
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_patrol())
- {
- return;
- }
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- void CvUnitAI::AI_attackCityLemmingMove()
- {
- if (AI_cityAttack(1, 80))
- {
- return;
- }
- if (AI_bombardCity())
- {
- return;
- }
- if (AI_cityAttack(1, 40))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/29/10 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if (AI_goToTargetCity(MOVE_THROUGH_ENEMY))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- return;
- }
- if (AI_anyAttack(1, 70))
- {
- return;
- }
- if (AI_anyAttack(1, 0))
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- }
- void CvUnitAI::AI_collateralMove()
- {
- PROFILE_FUNC();
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting collateralMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- if (AI_leaveAttack(1, 20, 100))
- {
- return;
- }
- if (AI_guardCity(false, true, 1))
- {
- return;
- }
- if (AI_heal(30, 1))
- {
- return;
- }
- if (AI_cityAttack(1, 35))
- {
- return;
- }
- if (AI_anyAttack(1, 45, 3))
- {
- return;
- }
- if (AI_anyAttack(1, 55, 2))
- {
- return;
- }
- if (AI_anyAttack(1, 35, 3))
- {
- return;
- }
- if (AI_anyAttack(1, 30, 4))
- {
- return;
- }
- if (AI_anyAttack(1, 20, 5))
- {
- return;
- }
- if (AI_heal())
- {
- return;
- }
- if (!noDefensiveBonus())
- {
- if (AI_guardCity(false, false))
- {
- return;
- }
- }
- if (AI_anyAttack(2, 55, 3))
- {
- return;
- }
- if (AI_cityAttack(2, 50))
- {
- return;
- }
- if (AI_anyAttack(2, 60))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- //if (AI_protect(50))
- if (AI_protect(50, 8))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- return;
- }
- if (AI_guardCity(false, true, 3))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_pillageMove()
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/05/10 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- PROFILE_FUNC();
- if (AI_guardCity(false, true, 1))
- {
- return;
- }
- if (AI_heal(30, 1))
- {
- return;
- }
- // BBAI TODO: Shadow ATTACK_CITY stacks and pillage
- //join any city attacks in progress
- if (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE())
- {
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
- {
- return;
- }
- }
-
- if (AI_cityAttack(1, 75))
- {
- return;
- }
- if (AI_anyAttack(1, 65))
- {
- return;
- }
- if (!noDefensiveBonus())
- {
- if (AI_guardCity(false, false))
- {
- return;
- }
- }
- if (AI_pillageRange(3, 11))
- {
- return;
- }
- if (AI_choke(1))
- {
- return;
- }
- if (AI_pillageRange(1))
- {
- return;
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- if (AI_heal(50, 3))
- {
- return;
- }
- if (!isEnemy(plot()->getTeam()))
- {
- if (AI_heal())
- {
- return;
- }
- }
- if (AI_group(UNITAI_PILLAGE, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, /*bIgnoreFaster*/ true, false, false, /*iMaxPath*/ 3))
- {
- return;
- }
- if ((area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) || isEnemy(plot()->getTeam()))
- {
- if (AI_pillage(20))
- {
- return;
- }
- }
- if (AI_heal())
- {
- return;
- }
- if (AI_guardCity(false, true, 3))
- {
- return;
- }
- if (AI_offensiveAirlift())
- {
- return;
- }
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- if( !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_patrol())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- void CvUnitAI::AI_reserveMove()
- {
- PROFILE_FUNC();
-
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3) > 0);
- bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (bDanger && AI_leaveAttack(2, 55, 130))
- {
- return;
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, 1, -1, MOVE_SAFE_TERRITORY))
- {
- return;
- }
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_WORKER, -1, -1, 1, -1, MOVE_SAFE_TERRITORY))
- {
- return;
- }
- }
-
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Settler AI */
- /************************************************************************************************/
- if( !(plot()->isOwned()) )
- {
- if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 1, true))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (!bDanger)
- {
- if (AI_group(UNITAI_SETTLE, 2, -1, -1, false, false, false, 3, true))
- {
- return;
- }
- }
- if (GET_TEAM(getTeam()).getAtWarCount(true) > 0)
- {
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- return;
- }
- if (AI_guardCity(true))
- {
- return;
- }
- if (!noDefensiveBonus())
- {
- if (AI_guardFort(false))
- {
- return;
- }
- }
- if (AI_guardCityAirlift())
- {
- return;
- }
- if (AI_guardCity(false, true, 1))
- {
- return;
- }
- if (AI_guardCitySite())
- {
- return;
- }
- if (!noDefensiveBonus())
- {
- if (AI_guardFort(true))
- {
- return;
- }
- if (AI_guardBonus(15))
- {
- return;
- }
- }
- if (AI_heal(30, 1))
- {
- return;
- }
- if (bDanger)
- {
- if (AI_cityAttack(1, 55))
- {
- return;
- }
- if (AI_anyAttack(1, 60))
- {
- return;
- }
- }
- if (!noDefensiveBonus())
- {
- if (AI_guardCity(false, false))
- {
- return;
- }
- }
- if (bDanger)
- {
- if (AI_cityAttack(3, 45))
- {
- return;
- }
- if (AI_anyAttack(3, 50))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- //if (AI_protect(45))
- if (AI_protect(45, 8))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- return;
- }
- if (AI_guardCity(false, true, 3))
- {
- return;
- }
- if (AI_defend())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_counterMove()
- {
- PROFILE_FUNC();
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting counterMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/03/10 jdog5000 */
- /* */
- /* Unit AI, Settler AI */
- /************************************************************************************************/
- // Should never have group lead by counter unit
- if( getGroup()->getNumUnits() > 1 )
- {
- UnitAITypes eGroupAI = getGroup()->getHeadUnitAI();
- if( eGroupAI == AI_getUnitAIType() )
- {
- if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
- {
- //FAssert(false); // just interested in when this happens, not a problem
- getGroup()->AI_separate(); // will change group
- return;
- }
- }
- }
- if( !(plot()->isOwned()) )
- {
- if( AI_groupMergeRange(UNITAI_SETTLE, 2, true, false, false) )
- {
- return;
- }
- }
- if (AI_guardCity(false, true, 1))
- {
- return;
- }
- if (getSameTileHeal() > 0)
- {
- if (!canAttack())
- {
- // Don't restrict to groups carrying cargo ... does this apply to any units in standard bts anyway?
- if (AI_shadow(UNITAI_ATTACK_CITY, -1, 21, false, false, 4))
- {
- return;
- }
- }
- }
- bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
- AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if( !bDanger )
- {
- if (plot()->isCity())
- {
- if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
- {
- if (AI_offensiveAirlift())
- {
- return;
- }
- }
- }
-
- if( (eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) || (eAreaAIType == AREAAI_ASSAULT_MASSING) )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- }
- if (!noDefensiveBonus())
- {
- if (AI_guardCity(false, false))
- {
- return;
- }
- }
- }
- //join any city attacks in progress
- if (plot()->getOwnerINLINE() != getOwnerINLINE())
- {
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
- {
- return;
- }
- }
- if (bDanger)
- {
- if (AI_cityAttack(1, 35))
- {
- return;
- }
- if (AI_anyAttack(1, 40))
- {
- return;
- }
- }
-
- bool bIgnoreFasterStacks = false;
- if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
- {
- if (area()->getAreaAIType(getTeam()) != AREAAI_ASSAULT)
- {
- bIgnoreFasterStacks = true;
- }
- }
- if (AI_group(UNITAI_ATTACK_CITY, /*iMaxGroup*/ -1, 2, -1, bIgnoreFasterStacks, /*bIgnoreOwnUnitType*/ true, /*bStackOfDoom*/ true, /*iMaxPath*/ 6))
- {
- return;
- }
-
- bool bFastMovers = (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_FASTMOVERS));
- if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 2, -1, -1, bFastMovers, /*bIgnoreOwnUnitType*/ true, /*bStackOfDoom*/ true, /*iMaxPath*/ 5))
- {
- return;
- }
- // BBAI TODO: merge with nearby pillage
-
- if (AI_guardCity(false, true, 3))
- {
- return;
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if( !bDanger )
- {
- if( (eAreaAIType != AREAAI_DEFENSIVE) )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- }
- }
- if (AI_heal())
- {
- return;
- }
- if (AI_offensiveAirlift())
- {
- return;
- }
- if (AI_anyAttack(1, 80))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- void CvUnitAI::AI_cityDefenseMove()
- {
- PROFILE_FUNC();
-
- /* - a little too spammy - just use for debugging issues
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" %S (unit %d) starting cityDefenseMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- */
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3) > 0);
- bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Settler AI */
- /************************************************************************************************/
- if( !(plot()->isOwned()) )
- {
- if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 2, true))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (bDanger)
- {
- if (AI_leaveAttack(1, 70, 175))
- {
- return;
- }
- if (AI_chokeDefend())
- {
- return;
- }
- }
- if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
- {
- if (AI_mageMove())
- {
- return;
- }
- else if (isBarbarian() && plot()->isCity())
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- if (AI_guardCityBestDefender())
- {
- return;
- }
- if (!bDanger)
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, 1, -1, MOVE_SAFE_TERRITORY, 1))
- {
- return;
- }
- }
- }
- if (AI_guardCityMinDefender(true))
- {
- return;
- }
- if (plot()->isCity())
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (plot()->getPlotCity()->AI_neededDefenders() > (plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE())) +
- plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_COUNTER, -1, getOwnerINLINE()))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- // Super Forts begin *AI_defense*
- if (AI_guardFortMinDefender(true))
- {
- logBBAI(" Unit %d (%S) guard fort at [%d, %d] (MinDefender pass 1) \n", getID(), getName().GetCString(), getX_INLINE(), getY_INLINE());
- return;
- }
- // Super Forts end
- if (AI_guardCity(true))
- {
- return;
- }
- if (!bDanger)
- {
- if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 1, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
- {
- return;
- }
- if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 3, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
- {
- return;
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, 1, -1, MOVE_SAFE_TERRITORY))
- {
- return;
- }
-
- if (plot()->isCity())
- {
- CvCity* pCity = plot()->getPlotCity();
- if (pCity->AI_neededDefenders() > plot()->getNumDefenders(getOwnerINLINE()))
- {
- if (AI_travelToUpgradeCity())
- {
- logBBAI(" %S (unit %d - %S) traveling to upgrade city (DEFENSE)", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription());
- return;
- }
- }
- }
- }
- /*
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- */
- }
- AreaAITypes eAreaAI = area()->getAreaAIType(getTeam());
- if ((eAreaAI == AREAAI_ASSAULT) || (eAreaAI == AREAAI_ASSAULT_MASSING) || (eAreaAI == AREAAI_ASSAULT_ASSIST))
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, 0, MOVE_SAFE_TERRITORY))
- {
- return;
- }
- }
- if ((AI_getBirthmark() % 4) == 0)
- {
- if (AI_guardFort())
- {
- return;
- }
- }
- if (AI_guardCityAirlift())
- {
- return;
- }
- if (AI_guardCity(false, true, 1))
- {
- return;
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, 3, -1, -1, -1, MOVE_SAFE_TERRITORY))
- {
- // will enter here if in danger
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/02/10 jdog5000 */
- /* */
- /* City AI */
- /************************************************************************************************/
- //join any city attacks in progress
- if (plot()->getOwnerINLINE() != getOwnerINLINE())
- {
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_guardCity(false, true))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/04/10 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if (!isBarbarian() && ((area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) || (area()->getAreaAIType(getTeam()) == AREAAI_MASSING)))
- {
- bool bIgnoreFaster = false;
- if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
- {
- if (area()->getAreaAIType(getTeam()) != AREAAI_ASSAULT)
- {
- bIgnoreFaster = true;
- }
- }
- if (AI_group(UNITAI_ATTACK_CITY, -1, 2, 4, bIgnoreFaster))
- {
- return;
- }
- }
-
- if (area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT)
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, 2, -1, -1, 1, MOVE_SAFE_TERRITORY))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_cityDefenseExtraMove()
- {
- PROFILE_FUNC();
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting cityDefenseExtraMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- CvCity* pCity;
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Settler AI */
- /************************************************************************************************/
- if( !(plot()->isOwned()) )
- {
- if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 1, true))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_leaveAttack(2, 55, 150))
- {
- return;
- }
- if (AI_chokeDefend())
- {
- return;
- }
- if (AI_guardCityBestDefender())
- {
- return;
- }
- if (AI_guardCity(true))
- {
- return;
- }
- if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 1, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
- {
- return;
- }
- if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 2, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
- {
- return;
- }
- // Super Forts begin *AI_defense*
- if (AI_guardFortMinDefender(true))
- {
- logBBAI(" Unit %d (%S) guard fort at [%d, %d] (MinDefender pass 2) \n", getID(), getName().GetCString(), getX_INLINE(), getY_INLINE());
- return;
- }
- if ((AI_getBirthmark() % 4) == 0)
- {
- if (AI_guardFort(true))
- {
- return;
- }
- }
- // Super Forts end
- pCity = plot()->getPlotCity();
- if ((pCity != NULL) && (pCity->getOwnerINLINE() == getOwnerINLINE())) // XXX check for other team?
- {
- if (plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isUnitAIType, AI_getUnitAIType()) == 1)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- if (AI_guardCityAirlift())
- {
- return;
- }
- if (AI_guardCity(false, true, 1))
- {
- return;
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, 3, -1, -1, -1, MOVE_SAFE_TERRITORY, 3))
- {
- return;
- }
- }
- if (AI_guardCity(false, true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_exploreMove()
- {
- PROFILE_FUNC();
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" %S (unit %d) starting exploreMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- // Floating Eyes & Hawks
- if (getDomainType() == DOMAIN_AIR)
- {
- if (airRange() > 0)
- {
- if (AI_exploreAir())
- {
- return;
- }
- else
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- if (!isHuman() && canAttack())
- {
- if (AI_cityAttack(1, 60))
- {
- return;
- }
- if (AI_anyAttack(1, 70))
- {
- return;
- }
- }
- /*
- if (getDamage() > 0)
- {
- if ((plot()->getFeatureType() == NO_FEATURE) || (GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() <= 0))
- {
- getGroup()->pushMission(MISSION_HEAL);
- return;
- }
- }
- */
- if (AI_heal())
- {
- return;
- }
- if (!isHuman())
- {
- if (AI_pillageRange(1))
- {
- return;
- }
- if (AI_cityAttack(3, 80))
- {
- return;
- }
- }
- if (AI_goody(4))
- {
- return;
- }
- if (AI_pickupEquipment(6))
- {
- return;
- }
- if (!isHuman())
- {
- if (AI_exploreLair(6))
- {
- return;
- }
- }
- if (AI_exploreRange(3))
- {
- return;
- }
- if (!isHuman())
- {
- if (AI_pillageRange(3))
- {
- return;
- }
- }
- if (AI_explore())
- {
- return;
- }
- if (!isHuman())
- {
- if (AI_pillage())
- {
- return;
- }
- }
- if (!isHuman())
- {
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 12/03/08 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_patrol())
- {
- return;
- }
- if (AI_pickupEquipment(12))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_missionaryMove()
- {
- PROFILE_FUNC();
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- CvCity* pLoopCity;
- CvPlot* pBestGreatWorkPlot = NULL;
- int iLoop;
- // Tholal AI - modifications to improve Missionary AI
- // Initial check to make sure AI doesn't use it's first disciple for a Great Work
- if (!kPlayer.isAgnostic() && kPlayer.getStateReligion() == NO_RELIGION)
- {
- if (AI_spreadReligion())
- {
- return;
- }
- }
-
- // Catch Disciples who have been upgraded to different units and change their AI
- // Tholal ToDo - Secondary check is for Savants who can never do Great Works. Is there a better way to handle this?
- if (m_pUnitInfo->getGreatWorkCulture() == 0)
- {
- if (m_pUnitInfo->getDefaultUnitAIType() != UNITAI_MISSIONARY)
- {
- AI_setUnitAIType(UNITAI_MEDIC);
- return;
- }
- }
- // Find cities in disorder or who have no culture and perform Great Works
- // Tholal ToDo - Incorporate this into the AI_greatWork() function rather than duplicating code
- /*
- if (AI_greatWork())
- {
- return;
- }
- */
- else
- {
- CvCity* pCity = plot()->getPlotCity();
- CvPlot* pBestPlot = NULL;
- if (pCity != NULL)
- {
- if (pCity->getOwner() == getOwner())
- {
- if (pCity->isDisorder() || pCity->getCultureLevel() == 0)
- {
- getGroup()->pushMission(MISSION_GREAT_WORK);
- return;
- }
- }
- }
-
- int iBestValue = 0;
- for (pLoopCity = kPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kPlayer.nextCity(&iLoop))
- {
- if (pLoopCity->isDisorder() || pLoopCity->getCulture(pLoopCity->getOwnerINLINE()) == 0)
- {
- if (canGreatWork(pLoopCity->plot()))
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GREAT_WORK, getGroup()) == 0)
- {
- if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true))
- {
- int iValue = pLoopCity->getPopulation() * 10;
- if (pLoopCity->isCapital())
- {
- iValue *= 10;
- }
- if (pLoopCity->isSettlement())
- {
- iValue /= 8;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestGreatWorkPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestGreatWorkPlot != NULL))
- {
- if (atPlot(pBestGreatWorkPlot))
- {
- getGroup()->pushMission(MISSION_GREAT_WORK);
- return;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_GREAT_WORK, pBestGreatWorkPlot);
- return;
- }
- }
- }
- //End Tholal AI
- if (AI_spreadReligion())
- {
- return;
- }
- if (AI_spreadCorporation())
- {
- return;
- }
- if (!isHuman() || (isAutomated() && GET_TEAM(getTeam()).getAtWarCount(true) == 0))
- {
- if (!isHuman() || (getGameTurnCreated() < GC.getGame().getGameTurn()))
- {
- if (AI_spreadReligionAirlift())
- {
- return;
- }
- if (AI_spreadCorporationAirlift())
- {
- return;
- }
- }
- if (!isHuman())
- {
- if (AI_load(UNITAI_MISSIONARY_SEA, MISSIONAI_LOAD_SPECIAL, NO_UNITAI, -1, -1, -1, 0, MOVE_SAFE_TERRITORY))
- {
- return;
- }
- if (AI_load(UNITAI_MISSIONARY_SEA, MISSIONAI_LOAD_SPECIAL, NO_UNITAI, -1, -1, -1, 0, MOVE_NO_ENEMY_TERRITORY))
- {
- return;
- }
- }
- }
- if (AI_guardCity())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_prophetMove()
- {
- PROFILE_FUNC();
- logBBAI(" %S (%d) starting ProphetMove", getName().GetCString(), getID());
- // Sephi AI (Altar)
- if (GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_ALTAR1))
- {
- if (AI_construct(10000,10000))
- {
- return;
- }
- }
- // End Sephi AI
- if (AI_construct())
- {
- return;
- }
- if (AI_discover(true, true))
- {
- return;
- }
- if (AI_construct(3))
- {
- return;
- }
- int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
- int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
- if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
- {
- if (AI_goldenAge())
- {
- return;
- }
- if (iDiscoverValue > iGoldenAgeValue)
- {
- if (AI_discover())
- {
- return;
- }
- if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
- {
- if (AI_join())
- {
- return;
- }
- }
- }
- }
- else
- {
- if (AI_discover())
- {
- return;
- }
- if (AI_join())
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
- if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
- {
- if (AI_discover())
- {
- return;
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_artistMove()
- {
- PROFILE_FUNC();
-
- if (AI_artistCultureVictoryMove())
- {
- return;
- }
- if (AI_construct())
- {
- return;
- }
- if (AI_discover(true, true))
- {
- return;
- }
- int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
- int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
- if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
- {
- if (AI_goldenAge())
- {
- return;
- }
- if (iDiscoverValue > iGoldenAgeValue)
- {
- if (AI_discover())
- {
- return;
- }
- if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
- {
- if (AI_join())
- {
- return;
- }
- }
- }
- }
- else
- {
- if (AI_discover())
- {
- return;
- }
- if (AI_join())
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
- if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
- {
- if (AI_discover())
- {
- return;
- }
- }
- if (AI_greatWork())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_scientistMove()
- {
- PROFILE_FUNC();
- if (AI_discover(true, true))
- {
- return;
- }
- if (AI_construct(MAX_INT, 1))
- {
- return;
- }
- if (GC.getGameINLINE().getCurrentEra() < 3)
- {
- if (AI_join(2))
- {
- return;
- }
- }
- if (GC.getGameINLINE().getCurrentEra() <= (GC.getNumRealEras() / 2))
- {
- if (AI_construct())
- {
- return;
- }
- }
- int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
- int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
- if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
- {
- if (AI_goldenAge())
- {
- return;
- }
- if (iDiscoverValue > iGoldenAgeValue)
- {
- if (AI_discover())
- {
- return;
- }
- if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
- {
- if (AI_join())
- {
- return;
- }
- }
- }
- }
- else
- {
- if (AI_discover())
- {
- return;
- }
- if (AI_join())
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
- if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
- {
- if (AI_discover())
- {
- return;
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_generalMove()
- {
- PROFILE_FUNC();
- std::vector<UnitAITypes> aeUnitAITypes;
- int iDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2);
- bool bOffenseWar = (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE);
- if (iDanger > 0)
- {
- aeUnitAITypes.clear();
- aeUnitAITypes.push_back(UNITAI_ATTACK);
- aeUnitAITypes.push_back(UNITAI_COUNTER);
- if (AI_lead(aeUnitAITypes))
- {
- return;
- }
- }
- if (AI_construct())
- {
- return;
- }
- if (AI_join(1))
- {
- return;
- }
-
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 05/14/10 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if ((bOffenseWar && (AI_getBirthmark() % 2 == 0)) || GC.getUnitInfo(getUnitType()).getLeaderPromotion() != NO_PROMOTION)
- {
- aeUnitAITypes.clear();
- aeUnitAITypes.push_back(UNITAI_ATTACK_CITY);
- if (AI_lead(aeUnitAITypes))
- {
- return;
- }
- aeUnitAITypes.clear();
- aeUnitAITypes.push_back(UNITAI_ATTACK);
- if (AI_lead(aeUnitAITypes))
- {
- return;
- }
- }
-
- if (AI_join(2))
- {
- return;
- }
- if (AI_construct(2))
- {
- return;
- }
- if (AI_join(4))
- {
- return;
- }
- if (GC.getGameINLINE().getSorenRandNum(3, "AI General Construct") == 0)
- {
- if (AI_construct())
- {
- return;
- }
- }
- if (AI_join())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_merchantMove()
- {
- PROFILE_FUNC();
- logBBAI(" %S (%d) starting MerchantMove", getName().GetCString(), getID());
-
- if (AI_construct())
- {
- return;
- }
- if (AI_discover(true, true))
- {
- return;
- }
- int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
- int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
- if (AI_trade(iGoldenAgeValue * 2))
- {
- return;
- }
- if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
- {
- if (AI_goldenAge())
- {
- return;
- }
- if (AI_trade(iGoldenAgeValue))
- {
- return;
- }
- if (iDiscoverValue > iGoldenAgeValue)
- {
- if (AI_discover())
- {
- return;
- }
- if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
- {
- if (AI_join())
- {
- return;
- }
- }
- }
- }
- else
- {
- if (AI_discover())
- {
- return;
- }
- if (AI_join())
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
- if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
- {
- if (AI_discover())
- {
- return;
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_engineerMove()
- {
- PROFILE_FUNC();
- if (AI_construct())
- {
- return;
- }
- if (AI_switchHurry())
- {
- return;
- }
- if (AI_hurry())
- {
- return;
- }
- if (AI_discover(true, true))
- {
- return;
- }
- int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
- int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));
- if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
- {
- if (AI_goldenAge())
- {
- return;
- }
- if (iDiscoverValue > iGoldenAgeValue)
- {
- if (AI_discover())
- {
- return;
- }
- if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
- {
- if (AI_join())
- {
- return;
- }
- }
- }
- }
- else
- {
- if (AI_discover())
- {
- return;
- }
- if (AI_join())
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
- if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
- {
- if (AI_discover())
- {
- return;
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/25/10 jdog5000 */
- /* */
- /* Espionage AI */
- /************************************************************************************************/
- void CvUnitAI::AI_spyMove()
- {
- PROFILE_FUNC();
- CvTeamAI& kTeam = GET_TEAM(getTeam());
- int iEspionageChance = 0;
- if (plot()->isOwned() && (plot()->getTeam() != getTeam()))
- {
- switch (GET_PLAYER(getOwnerINLINE()).AI_getAttitude(plot()->getOwnerINLINE()))
- {
- case ATTITUDE_FURIOUS:
- iEspionageChance = 100;
- break;
- case ATTITUDE_ANNOYED:
- iEspionageChance = 50;
- break;
- case ATTITUDE_CAUTIOUS:
- iEspionageChance = (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 30 : 10);
- break;
- case ATTITUDE_PLEASED:
- iEspionageChance = (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 20 : 0);
- break;
- case ATTITUDE_FRIENDLY:
- iEspionageChance = 0;
- break;
- default: // lfgr comment: isAIControl() makes isAutomated() true without actually having to have an automate type.
- FAssertMsg( isAIControl(), CvString::format( "Unknown automate type: %d", getGroup()->getAutomateType() ).c_str() );
- break;
- }
- WarPlanTypes eWarPlan = kTeam.AI_getWarPlan(plot()->getTeam());
- if (eWarPlan != NO_WARPLAN)
- {
- if (eWarPlan == WARPLAN_LIMITED)
- {
- iEspionageChance += 50;
- }
- else
- {
- iEspionageChance += 20;
- }
- }
- if (plot()->isCity() && plot()->getTeam() != getTeam())
- {
- bool bTargetCity = false;
- // would we have more power if enemy defenses were down?
- int iOurPower = GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(),1,false,true);
- int iEnemyPower = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),0,false,false);
- if( 5*iOurPower > 6*iEnemyPower && eWarPlan != NO_WARPLAN )
- {
- bTargetCity = true;
- if( AI_revoltCitySpy() )
- {
- return;
- }
- if (GC.getGame().getSorenRandNum(5, "AI Spy Skip Turn") > 0)
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
- return;
- }
- if ( AI_cityOffenseSpy(5, plot()->getPlotCity()) )
- {
- return;
- }
- }
-
- if( GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(plot(), MISSIONAI_ASSAULT, getGroup()) > 0 )
- {
- bTargetCity = true;
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
- return;
- }
-
- if( !bTargetCity )
- {
- // normal city handling
- if (getFortifyTurns() >= GC.getDefineINT("MAX_FORTIFY_TURNS"))
- {
- if (AI_espionageSpy())
- {
- return;
- }
- }
- else if (GC.getGame().getSorenRandNum(100, "AI Spy Skip Turn") > 5)
- {
- // don't get stuck forever
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
- return;
- }
- }
- }
- else if (GC.getGameINLINE().getSorenRandNum(100, "AI Spy Espionage") < iEspionageChance)
- {
- // This applies only when not in an enemy city, so for destroying improvements
- if (AI_espionageSpy())
- {
- return;
- }
- }
- }
- if (plot()->getTeam() == getTeam())
- {
- if (kTeam.getAnyWarPlanCount(true) == 0 || GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_SPACE4) || GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE3))
- {
- if( GC.getGame().getSorenRandNum(10, "AI Spy defense") > 0)
- {
- if (AI_guardSpy(0))
- {
- return;
- }
- }
- }
- if (GC.getGame().getSorenRandNum(100, "AI Spy pillage improvement") < 25)
- {
- if (AI_bonusOffenseSpy(5))
- {
- return;
- }
- }
- else
- {
- if (AI_cityOffenseSpy(10))
- {
- return;
- }
- }
- }
-
- if (iEspionageChance > 0 && (plot()->isCity() || (plot()->getNonObsoleteBonusType(getTeam()) != NO_BONUS)))
- {
- if (GC.getGame().getSorenRandNum(7, "AI Spy Skip Turn") > 0)
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
- return;
- }
- }
- if( area()->getNumCities() > area()->getCitiesPerPlayer(getOwnerINLINE()) )
- {
- if (GC.getGame().getSorenRandNum(4, "AI Spy Choose Movement") > 0)
- {
- if (AI_reconSpy(3))
- {
- return;
- }
- }
- else
- {
- if (AI_cityOffenseSpy(10))
- {
- return;
- }
- }
- }
-
- if (AI_load(UNITAI_SPY_SEA, MISSIONAI_LOAD_SPECIAL, NO_UNITAI, -1, -1, -1, 0, MOVE_NO_ENEMY_TERRITORY))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- void CvUnitAI::AI_ICBMMove()
- {
- PROFILE_FUNC();
- // CvCity* pCity = plot()->getPlotCity();
- // if (pCity != NULL)
- // {
- // if (pCity->AI_isDanger())
- // {
- // if (!(pCity->AI_isDefended()))
- // {
- // if (AI_airCarrier())
- // {
- // return;
- // }
- // }
- // }
- // }
- if (airRange() > 0)
- {
- if (AI_nukeRange(airRange()))
- {
- return;
- }
- }
- else if (AI_nuke())
- {
- return;
- }
- if (isCargo())
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (airRange() > 0)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/25/10 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if (4*iEnemyOffense > iOurDefense || iOurDefense == 0)
- {
- // Too risky, pull back
- if (AI_airOffensiveCity())
- {
- return;
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_missileLoad(UNITAI_MISSILE_CARRIER_SEA, 2, true))
- {
- return;
- }
- if (AI_missileLoad(UNITAI_MISSILE_CARRIER_SEA, 1, false))
- {
- return;
- }
- if (AI_getBirthmark() % 3 == 0)
- {
- if (AI_missileLoad(UNITAI_ATTACK_SEA, 0, false))
- {
- return;
- }
- }
- if (AI_airOffensiveCity())
- {
- return;
- }
- }
- getGroup()->pushMission(MISSION_SKIP);
- }
- void CvUnitAI::AI_workerSeaMove()
- {
- PROFILE_FUNC();
- //CvCity* pCity;
- int iI;
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting workerSeaMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- if (!(getGroup()->canDefend()))
- {
- //if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot()))
- if (GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), -1))
- {
- if (AI_retreatToCity())
- {
- return;
- }
- }
- }
- /*************************************************************************************************/
- /** Skyre Mod **/
- /** BETTER AI (Lanun Pirate Coves) merged Sephi **/
- /** **/
- /*************************************************************************************************/
- if (GET_PLAYER(getOwnerINLINE()).isPirate())
- {
- if (AI_buildPirateCove())
- {
- return;
- }
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- if (AI_improveBonus(20))
- {
- return;
- }
- if (AI_improveBonus(10))
- {
- return;
- }
- if (AI_improveBonus())
- {
- return;
- }
- if (isHuman())
- {
- FAssert(isAutomated());
- if (plot()->getBonusType() != NO_BONUS)
- {
- if ((plot()->getOwnerINLINE() == getOwnerINLINE()) || (!plot()->isOwned()))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- CvPlot* pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), (DirectionTypes)iI);
- if (pLoopPlot != NULL)
- {
- if (pLoopPlot->getBonusType() != NO_BONUS)
- {
- if (pLoopPlot->isValidDomainForLocation(*this))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- }
- }
- /*
- if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_WORKER_SEA))
- {
- pCity = plot()->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- if (pCity->AI_neededSeaWorkers() == 0)
- {
- if (GC.getGameINLINE().getElapsedGameTurns() > 10)
- {
- if (GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
- {
- scrap();
- return;
- }
- }
- }
- else
- {
- //Probably icelocked since it can't perform actions.
- scrap();
- return;
- }
- }
- }
- }
- */
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_barbAttackSeaMove()
- {
- PROFILE_FUNC();
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 9/25/08 jdog5000 */
- /* */
- /* Barbarian AI */
- /********************************************************************************/
- /* original BTS code
- if (GC.getGameINLINE().getSorenRandNum(2, "AI Barb") == 0)
- {
- if (AI_pillageRange(1))
- {
- return;
- }
- }
- if (AI_anyAttack(2, 25))
- {
- return;
- }
- if (AI_pillageRange(4))
- {
- return;
- }
- if (AI_heal())
- {
- return;
- }
- */
- // Less suicide, always chase good targets
- if( AI_anyAttack(2,51) )
- {
- return;
- }
- if (AI_pillageRange(1))
- {
- return;
- }
- if( AI_anyAttack(1,34) )
- {
- return;
- }
- // We're easy to take out if wounded
- if (AI_heal())
- {
- return;
- }
- if (AI_pillageRange(3))
- {
- return;
- }
- // Barb ships will often hang out for a little while blockading before moving on
- if( (GC.getGame().getGameTurn() + getID())%12 > 5 )
- {
- if( AI_pirateBlockade())
- {
- return;
- }
- }
- if( GC.getGameINLINE().getSorenRandNum(3, "AI Check trapped") == 0 )
- {
- // If trapped in small hole in ice or around tiny island, disband to allow other units to be generated
- bool bScrap = true;
- int iMaxRange = baseMoves() + 2;
- for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
- {
- for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
- {
- if( bScrap )
- {
- CvPlot* pLoopPlot = plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), iDX, iDY);
-
- if (pLoopPlot != NULL && AI_plotValid(pLoopPlot))
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if( iPathTurns > 1 )
- {
- bScrap = false;
- }
- }
- }
- }
- }
- }
- if( bScrap )
- {
- scrap();
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (AI_patrol())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/23/10 jdog5000 */
- /* */
- /* Pirate AI */
- /************************************************************************************************/
- void CvUnitAI::AI_pirateSeaMove()
- {
- PROFILE_FUNC();
- CvArea* pWaterArea;
- // heal in defended, unthreatened forts and cities
- if (plot()->isCity(true) && (GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(),0,true,false) > 0) && !(GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2, false)) )
- {
- if (AI_heal())
- {
- return;
- }
- }
- if (plot()->isOwned() && (plot()->getTeam() == getTeam()))
- {
- if (AI_anyAttack(2, 55))
- {
- return;
- }
-
- //if (AI_protect(30))
- if (AI_protect(40, 3))
- {
- return;
- }
-
- if (((AI_getBirthmark() / 8) % 2) == 0)
- {
- // Previously code actually blocked grouping
- if (AI_group(UNITAI_PIRATE_SEA, -1, 1, -1, true, false, false, 8))
- {
- return;
- }
- }
- }
- else
- {
- if (AI_anyAttack(2, 51))
- {
- return;
- }
- }
- if (GC.getGame().getSorenRandNum(10, "AI Pirate Explore") == 0)
- {
- pWaterArea = plot()->waterArea();
- if (pWaterArea != NULL)
- {
- if (pWaterArea->getNumUnrevealedTiles(getTeam()) > 0)
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_areaMissionAIs(pWaterArea, MISSIONAI_EXPLORE, getGroup()) < (GET_PLAYER(getOwnerINLINE()).AI_neededExplorers(pWaterArea)))
- {
- if (AI_exploreRange(2))
- {
- return;
- }
- }
- }
- }
- }
- if (GC.getGame().getSorenRandNum(11, "AI Pirate Pillage") == 0)
- {
- if (AI_pillageRange(1))
- {
- return;
- }
- }
- //Includes heal and retreat to sea routines.
- if (AI_pirateBlockade())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- void CvUnitAI::AI_attackSeaMove()
- {
- PROFILE_FUNC();
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 06/14/09 Solver & jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0) //prioritize getting outta there
- {
- if (AI_anyAttack(2, 50))
- {
- return;
- }
- if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34, false, true, getMoves()))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- //if (AI_protect(35))
- if (AI_protect(35, 3))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (AI_heal(30, 1))
- {
- return;
- }
- if (AI_anyAttack(1, 55))
- {
- return;
- }
- if (AI_anyAttack(2, 60))
- {
- return;
- }
- if (AI_seaBombardRange(6))
- {
- return;
- }
- if (AI_heal(50, 3))
- {
- return;
- }
- if (AI_heal())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/10/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- // BBAI TODO: Turn this into a function, have docked escort ships do it to
- //Fuyu: search for more attackers, and when enough are found, always try to break through
- CvCity* pCity = plot()->getPlotCity();
- if( pCity != NULL )
- {
- if( pCity->isBlockaded() )
- {
- int iBlockadeRange = GC.getDefineINT("SHIP_BLOCKADE_RANGE");
- // City under blockade
- // Attacker has low odds since anyAttack checks above passed, try to break if sufficient numbers
- int iAttackers = plot()->plotCount(PUF_isUnitAIType, UNITAI_ATTACK_SEA, -1, NO_PLAYER, getTeam(), PUF_isGroupHead, -1, -1);
- int iBlockaders = GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), (iBlockadeRange + 1));
- //bool bBreakBlockade = (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders);
- if (true)
- {
- int iMaxRange = iBlockadeRange - 1;
- if( gUnitLogLevel > 2 ) logBBAI(" Not enough attack fleet found in %S, searching for more in a %d-tile radius", pCity->getName().GetCString(), iMaxRange);
- for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
- {
- for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
- {
- CvPlot* pLoopPlot = plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), iDX, iDY);
-
- if (pLoopPlot != NULL && pLoopPlot->isWater())
- {
- if (pLoopPlot->getBlockadedCount(getTeam()) > 0)
- {
- iAttackers += pLoopPlot->plotCount(PUF_isUnitAIType, UNITAI_ATTACK_SEA, -1, NO_PLAYER, getTeam(), PUF_isGroupHead, -1, -1);
- }
- }
- }
- }
- }
- //bBreakBlockade = (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders);
- //if (bBreakBlockade)
- if (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders)
- {
- if( gUnitLogLevel > 2 ) logBBAI(" Found %d attackers and %d blockaders, proceeding to break blockade", iAttackers, iBlockaders);
- if(true) /* (iAttackers > GC.getGameINLINE().getSorenRandNum(2*iBlockaders + 1, "AI - Break blockade")) */
- {
- // BBAI TODO: Make odds scale by # of blockaders vs number of attackers
- if (baseMoves() >= iBlockadeRange)
- {
- if (AI_anyAttack(1, 15))
- {
- return;
- }
- }
- else
- {
- //Fuyu: Even slow ships should attack
- //Assuming that every ship can reach a blockade with 2 moves
- if (AI_anyAttack(2, 15))
- {
- return;
- }
- }
-
- //If no mission was pushed yet and we have a lot of ships, try again with even lower odds
- if(iAttackers > 2*iBlockaders)
- {
- if (AI_anyAttack(1, 10))
- {
- return;
- }
- }
- }
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
-
- if (AI_group(UNITAI_CARRIER_SEA, /*iMaxGroup*/ 4, 1, -1, true, false, false, /*iMaxPath*/ 5))
- {
- return;
- }
- if (AI_group(UNITAI_ATTACK_SEA, /*iMaxGroup*/ 1, -1, -1, true, false, false, /*iMaxPath*/ 3))
- {
- return;
- }
- if (!plot()->isOwned() || !isEnemy(plot()->getTeam()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/11/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- /* original bts code
- if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34))
- {
- return;
- }
-
- if (AI_shadow(UNITAI_CARRIER_SEA, 4, 51))
- {
- return;
- }
- if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, -1, false, false, false))
- {
- return;
- }
- }
-
- if (AI_group(UNITAI_CARRIER_SEA, -1, 1, -1, false, false, false))
- {
- return;
- } */
- // K-Mod / BBAI. I've changed the order of group / shadow.
- // What I'd really like is to join the assault group if the group needs escorts, but shadow if it doesn't.
- // Get at least one shadow per assault group.
- if (AI_shadow(UNITAI_ASSAULT_SEA, 1, -1, true, false, 4))
- {
- return;
- }
- // Allow several attack_sea with large flotillas
- if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, 4, false, false, false, 4, false, true, false))
- {
- return;
- }
- // allow just a couple with small asault teams
- if (AI_group(UNITAI_ASSAULT_SEA, -1, 2, -1, false, false, false, 5, false, true, false))
- {
- return;
- }
- // Otherwise, try to shadow.
- if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34, true, false, 4))
- {
- return;
- }
- if (AI_shadow(UNITAI_CARRIER_SEA, 4, 51, true, false, 5))
- {
- return;
- }
- }
-
- if (AI_group(UNITAI_CARRIER_SEA, -1, 1, -1, false, false, false, 10))
- {
- return;
- }
- // K-Mod / BBAI end
-
- if (plot()->isOwned() && (isEnemy(plot()->getTeam())))
- {
- if (AI_blockade())
- {
- return;
- }
- }
- if (AI_pillageRange(4))
- {
- return;
- }
-
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- //if (AI_protect(35))
- if (AI_protect(35, 3))
- {
- return;
- }
- if (AI_protect(35, 8))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- return;
- }
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- // K-Mod
- if (AI_guardBonus(10))
- return;
- if (AI_patrol())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_reserveSeaMove()
- {
- PROFILE_FUNC();
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 06/14/09 Solver & jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0) //prioritize getting outta there
- {
- if (AI_anyAttack(2, 60))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- //if (AI_protect(40))
- if (AI_protect(40, 3))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- return;
- }
- if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, getMoves()))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (AI_guardBonus(30))
- {
- return;
- }
- if (AI_heal(30, 1))
- {
- return;
- }
- if (AI_anyAttack(1, 55))
- {
- return;
- }
- if (AI_seaBombardRange(6))
- {
- return;
- }
-
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- //if (AI_protect(40))
- if (AI_protect(40, 5))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- return;
- }
-
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/03/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- /* original bts code
- if (AI_shadow(UNITAI_SETTLER_SEA, 1, -1, true))
- {
- return;
- }
- if (AI_group(UNITAI_RESERVE_SEA, 1))
- {
- return;
- }
-
- if (bombardRate() > 0)
- {
- if (AI_shadow(UNITAI_ASSAULT_SEA, 2, 30, true))
- {
- return;
- }
- }
- */
- // Shadow any nearby settler sea transport out at sea
- if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 5))
- {
- return;
- }
-
- if (AI_group(UNITAI_RESERVE_SEA, 1, -1, -1, false, false, false, 8))
- {
- return;
- }
- if (bombardRate() > 0)
- {
- if (AI_shadow(UNITAI_ASSAULT_SEA, 2, 30, true, false, 8))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_heal(50, 3))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- if (AI_protect(40))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_anyAttack(3, 65))
- {
- return;
- }
- if (AI_heal())
- {
- return;
- }
- if (!isNeverInvisible())
- {
- if (AI_anyAttack(5, 55))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/03/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- // Shadow settler transport with cargo
- if (AI_shadow(UNITAI_SETTLER_SEA, 1, -1, true, false, 10))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- if (AI_patrol())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_escortSeaMove()
- {
- PROFILE_FUNC();
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE()); // K-Mod
- // // if we have cargo, possibly convert to UNITAI_ASSAULT_SEA (this will most often happen with galleons)
- // // note, this should not happen when we are not the group head, so escort galleons are fine joining a group, just not as head
- // if (hasCargo() && (getUnitAICargo(UNITAI_ATTACK_CITY) > 0 || getUnitAICargo(UNITAI_ATTACK) > 0))
- // {
- // // non-zero AI_unitValue means that UNITAI_ASSAULT_SEA is valid for this unit (that is the check used everywhere)
- // if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_ASSAULT_SEA, NULL) > 0)
- // {
- // // save old group, so we can merge it back in
- // CvSelectionGroup* pOldGroup = getGroup();
- //
- // // this will remove this unit from the current group
- // AI_setUnitAIType(UNITAI_ASSAULT_SEA);
- //
- // // merge back the rest of the group into the new group
- // CvSelectionGroup* pNewGroup = getGroup();
- // if (pOldGroup != pNewGroup)
- // {
- // pOldGroup->mergeIntoGroup(pNewGroup);
- // }
- //
- // // perform assault sea action
- // AI_assaultSeaMove();
- // return;
- // }
- // }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 06/14/09 Solver & jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (plot()->isCity(true)) //prioritize getting outta there
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = kOwner.AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0)
- {
- if (AI_anyAttack(1, 60))
- {
- return;
- }
- if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 1, -1, /*bIgnoreFaster*/ true, false, false, /*iMaxPath*/ getMoves()))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (AI_heal(30, 1))
- {
- return;
- }
- if (AI_anyAttack(1, 55))
- {
- return;
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 9/14/08 jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- // Galleons can get stuck with this AI type since they don't upgrade to any escort unit
- // Galleon escorts are much less useful once Frigates or later are available
- if (!isHuman() && !isBarbarian())
- {
- if( getCargo() > 0 && (GC.getUnitInfo(getUnitType()).getSpecialCargo() == NO_SPECIALUNIT) )
- {
- //Obsolete?
- int iValue = kOwner.AI_unitValue(getUnitType(), AI_getUnitAIType(), area());
- int iBestValue = kOwner.AI_bestAreaUnitAIValue(AI_getUnitAIType(), area());
-
- if (iValue < iBestValue)
- {
- if (kOwner.AI_unitValue(getUnitType(), UNITAI_ASSAULT_SEA, area()) > 0)
- {
- AI_setUnitAIType(UNITAI_ASSAULT_SEA);
- return;
- }
- if (kOwner.AI_unitValue(getUnitType(), UNITAI_SETTLER_SEA, area()) > 0)
- {
- AI_setUnitAIType(UNITAI_SETTLER_SEA);
- return;
- }
- scrap();
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
-
- if (AI_group(UNITAI_CARRIER_SEA, -1, /*iMaxOwnUnitAI*/ 0, -1, /*bIgnoreFaster*/ true))
- {
- return;
- }
- if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ -1, -1, /*bIgnoreFaster*/ false, false, false, /*iMaxPath*/ 3))
- {
- return;
- }
- if (AI_heal(50, 3))
- {
- return;
- }
- if (AI_pillageRange(2))
- {
- return;
- }
- if (AI_group(UNITAI_MISSILE_CARRIER_SEA, 1, 1, true))
- {
- return;
- }
- if (AI_group(UNITAI_ASSAULT_SEA, 1, /*iMaxOwnUnitAI*/ -1, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ true))
- {
- return;
- }
- if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 2, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ true))
- {
- return;
- }
- if (AI_group(UNITAI_CARRIER_SEA, -1, /*iMaxOwnUnitAI*/ 2, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ true))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/01/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- /* original bts code
- if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, -1, true))
- {
- return;
- }
- */
- // Group only with large flotillas first
- if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 4, /*iMinUnitAI*/ 3, /*bIgnoreFaster*/ true))
- {
- return;
- }
- if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 4))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_heal())
- {
- return;
- }
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/18/10 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- // If nothing else useful to do, escort nearby large flotillas even if they're faster
- // Gives Caravel escorts something to do during the Galleon/pre-Frigate era
- if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 4, /*iMinUnitAI*/ 3, /*bIgnoreFaster*/ false, false, false, 4, false, true))
- {
- return;
- }
- if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 2, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ false, false, false, 1, false, true))
- {
- return;
- }
- // Pull back to primary area if it's not too far so primary area cities know you exist
- // and don't build more, unnecessary escorts
- if (AI_retreatToCity(true,false,6))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_exploreSeaMove()
- {
- PROFILE_FUNC();
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (plot()->isCity(true)) //prioritize getting outta there
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = kOwner.AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 )
- {
- if (!isHuman())
- {
- if (AI_anyAttack(1, 60))
- {
- return;
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (!isHuman())
- {
- if (AI_exploreLairSea(6))
- {
- return;
- }
- }
- CvArea* pWaterArea = plot()->waterArea();
- if (!isHuman())
- {
- if (AI_anyAttack(1, 60))
- {
- return;
- }
- }
- if (!isHuman() && !isBarbarian()) //XXX move some of this into a function? maybe useful elsewhere
- {
- //Obsolete?
- int iValue = kOwner.AI_unitValue(getUnitType(), AI_getUnitAIType(), area());
- int iBestValue = kOwner.AI_bestAreaUnitAIValue(AI_getUnitAIType(), area());
-
- if (iValue < iBestValue)
- {
- //Transform
- if (kOwner.AI_unitValue(getUnitType(), UNITAI_WORKER_SEA, area()) > 0)
- {
- AI_setUnitAIType(UNITAI_WORKER_SEA);
- return;
- }
-
- if (kOwner.AI_unitValue(getUnitType(), UNITAI_PIRATE_SEA, area()) > 0)
- {
- AI_setUnitAIType(UNITAI_PIRATE_SEA);
- return;
- }
-
- if (kOwner.AI_unitValue(getUnitType(), UNITAI_MISSIONARY_SEA, area()) > 0)
- {
- AI_setUnitAIType(UNITAI_MISSIONARY_SEA);
- return;
- }
-
- if (kOwner.AI_unitValue(getUnitType(), UNITAI_RESERVE_SEA, area()) > 0)
- {
- AI_setUnitAIType(UNITAI_RESERVE_SEA);
- return;
- }
- scrap();
- }
- }
- if (AI_heal())
- {
- return;
- }
- if (!isHuman())
- {
- if (AI_pillageRange(1))
- {
- return;
- }
- }
- if (AI_exploreRange(4))
- {
- return;
- }
- if (!isHuman())
- {
- if (AI_pillageRange(4))
- {
- return;
- }
- }
- if (AI_explore())
- {
- return;
- }
- if (!isHuman())
- {
- if (AI_pillage())
- {
- return;
- }
- }
- if (!isHuman())
- {
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- }
- if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
- {
- pWaterArea = plot()->waterArea();
- if (pWaterArea != NULL)
- {
- if (kOwner.AI_totalWaterAreaUnitAIs(pWaterArea, UNITAI_EXPLORE_SEA) > kOwner.AI_neededExplorers(pWaterArea))
- {
- if (kOwner.calculateUnitCost() > 0)
- {
- scrap();
- return;
- }
- }
- }
- }
- if (AI_patrol())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/18/10 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- void CvUnitAI::AI_assaultSeaMove()
- {
- PROFILE_FUNC();
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE()); // K-Mod
- FAssert(AI_getUnitAIType() == UNITAI_ASSAULT_SEA);
- bool bEmpty = !getGroup()->hasCargo();
- bool bFull = (getGroup()->AI_isFull() && (getGroup()->getCargo() > 0));
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting assaultSeaMove (cargo: %d)", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits(), getGroup()->getCargo());
- }
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = kOwner.AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if (iEnemyOffense > iOurDefense/4) // was 1 vs 1/8
- {
- if (iEnemyOffense > iOurDefense/2) // was 1 vs 1/4
- {
- if( !bEmpty )
- {
- getGroup()->unloadAll();
- }
- if (AI_anyAttack(1, 65))
- {
- return;
- }
- // Retreat to primary area first
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- if( !bFull && !bEmpty )
- {
- getGroup()->unloadAll();
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- if (bEmpty)
- {
- if (AI_anyAttack(1, 65))
- {
- return;
- }
- }
- bool bReinforce = false;
- bool bAttack = false;
- bool bNoWarPlans = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) == 0);
- bool bAttackBarbarian = false;
- //bool bLandWar = false;
- bool bIsBarbarian = isBarbarian();
-
- // Count forts as cities
- bool bIsCity = plot()->isCity(true);
- // Cargo if already at war
- int iTargetReinforcementSize = (bIsBarbarian ? 2 : AI_stackOfDoomExtra());
- // Cargo to launch a new invasion
- int iTargetInvasionSize = 2 * iTargetReinforcementSize;
- int iCargo = getGroup()->getCargo();
- int iEscorts = getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA) + getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA);
- AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
- //bLandWar = !bIsBarbarian && ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
- bool bLandWar = !bIsBarbarian && kOwner.AI_isLandWar(area()); // K-Mod
- // Plot danger case handled above
- if( hasCargo() && (getUnitAICargo(UNITAI_SETTLE) > 0 || getUnitAICargo(UNITAI_WORKER) > 0) )
- {
- // Dump inappropriate load at first oppurtunity after pick up
- if( bIsCity && (plot()->getOwnerINLINE() == getOwnerINLINE()) )
- {
- getGroup()->unloadAll();
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- else
- {
- if( !isFull() )
- {
- if(AI_pickupStranded(NO_UNITAI, 1))
- {
- return;
- }
- }
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- }
- }
- if (bIsCity)
- {
- CvCity* pCity = plot()->getPlotCity();
- if( pCity != NULL && (plot()->getOwnerINLINE() == getOwnerINLINE()) )
- {
- // split out galleys from stack of ocean capable ships
- if( kOwner.AI_unitImpassableCount(getUnitType()) == 0 && getGroup()->getNumUnits() > 1 )
- {
- logBBAI(" ...separating from Galleys");
- getGroup()->AI_separateImpassable();
- }
- // galleys with upgrade available should get that ASAP
- if( kOwner.AI_unitImpassableCount(getUnitType()) > 0 )
- {
- CvCity* pUpgradeCity = getUpgradeCity(false);
- if( pUpgradeCity != NULL && pUpgradeCity == pCity )
- {
- // Wait for upgrade, this unit is top upgrade priority
- logBBAI(" ...skipping turn while waiting for upgrades");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- if( (iCargo > 0) )
- {
- if( pCity != NULL )
- {
- if( (GC.getGameINLINE().getGameTurn() - pCity->getGameTurnAcquired()) <= 1 )
- {
- if( pCity->getPreviousOwner() != NO_PLAYER )
- {
- // 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
- if( GET_TEAM(getTeam()).countEnemyPowerByArea(plot()->area()) > 0 )
- {
- getGroup()->unloadAll();
- if( iEscorts > 2 )
- {
- if( getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA) > 1 && getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA) > 0 )
- {
- getGroup()->AI_separateAI(UNITAI_ATTACK_SEA);
- getGroup()->AI_separateAI(UNITAI_RESERVE_SEA);
- iEscorts = getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA);
- }
- }
- iCargo = getGroup()->getCargo();
- }
- }
- }
- }
- }
- if( (iCargo > 0) && (iEscorts == 0) )
- {
- if (AI_group(UNITAI_ASSAULT_SEA,-1,-1,-1,/*bIgnoreFaster*/true,false,false,/*iMaxPath*/1,false,/*bCargoOnly*/true,false,MISSIONAI_ASSAULT))
- {
- return;
- }
- if( plot()->plotCount(PUF_isUnitAIType, UNITAI_ESCORT_SEA, -1, getOwnerINLINE(), NO_TEAM, PUF_isGroupHead, -1, -1) > 0 )
- {
- // Loaded but with no escort, wait for escorts in plot to join us
- logBBAI(" ...waiting for escorts");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- if( (kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 3) > 0) || (kOwner.AI_getWaterDanger(plot(), 4, false) > 0) )
- {
- // Loaded but with no escort, wait for others joining us soon or avoid dangerous waters
- logBBAI(" ...waiting for joiners");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- if (bLandWar)
- {
- if ( iCargo > 0 )
- {
- if( (eAreaAIType == AREAAI_DEFENSIVE) || (pCity != NULL && pCity->AI_isDanger()))
- {
- // Unload cargo when on defense or if small load of troops and can reach enemy city over land (generally less risky)
- getGroup()->unloadAll();
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- if (iCargo >= iTargetReinforcementSize)
- {
- getGroup()->AI_separateEmptyTransports();
- if( !(getGroup()->hasCargo()) )
- {
- // this unit was empty group leader
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- // Send ready transports
- if (AI_assaultSeaReinforce(false))
- {
- return;
- }
- if( iCargo >= iTargetInvasionSize )
- {
- if (AI_assaultSeaTransport(false))
- {
- return;
- }
- }
- }
- }
- else
- {
- if ( (eAreaAIType == AREAAI_ASSAULT) || (getGroup()->AI_getMissionAIType() == MISSIONAI_ASSAULT))
- {
- if( iCargo >= iTargetInvasionSize )
- {
- bAttack = true;
- }
- }
-
- if( (eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) )
- {
- if( (bFull && iCargo > cargoSpace()) || (iCargo >= iTargetReinforcementSize) )
- {
- bReinforce = true;
- }
- }
- }
- if( !bAttack && !bReinforce && (plot()->getTeam() == getTeam()) )
- {
- if( iEscorts > 3 && iEscorts > (2*getGroup()->countNumUnitAIType(UNITAI_ASSAULT_SEA)) )
- {
- // If we have too many escorts, try freeing some for others
- getGroup()->AI_separateAI(UNITAI_ATTACK_SEA);
- getGroup()->AI_separateAI(UNITAI_RESERVE_SEA);
- iEscorts = getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA);
- if( iEscorts > 3 && iEscorts > (2*getGroup()->countNumUnitAIType(UNITAI_ASSAULT_SEA)) )
- {
- logBBAI(" ...freeing up escorts");
- getGroup()->AI_separateAI(UNITAI_ESCORT_SEA);
- }
- }
- }
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- if( kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
- {
- // Wait for units which are joining our group this turn
- logBBAI(" ...waiting for joiners 2");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if( !bFull )
- {
- if( bAttack )
- {
- eMissionAIType = MISSIONAI_LOAD_ASSAULT;
- if( kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
- {
- // Wait for cargo which will load this turn
- logBBAI(" ...waiting for nearby cargo to load");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- else if( kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_ASSAULT) > 0 )
- {
- // Wait for cargo which is on the way
- logBBAI(" ...waiting for any cargo on the way");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- if( !bAttack && !bReinforce )
- {
- if ( iCargo > 0 )
- {
- if (AI_group(UNITAI_ASSAULT_SEA,-1,-1,-1,/*bIgnoreFaster*/true,false,false,/*iMaxPath*/5,false,/*bCargoOnly*/true,false,MISSIONAI_ASSAULT))
- {
- return;
- }
- }
- else if (plot()->getTeam() == getTeam() && getGroup()->getNumUnits() > 1)
- {
- CvCity* pCity = plot()->getPlotCity();
- if( pCity != NULL && (GC.getGameINLINE().getGameTurn() - pCity->getGameTurnAcquired()) > 10 )
- {
- if( pCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, UNITAI_ATTACK_CITY, -1, getOwnerINLINE()) < iTargetReinforcementSize )
- {
- // Not attacking, no cargo so release any escorts, attack ships, etc and split transports
- getGroup()->AI_makeForceSeparate();
- }
- }
- }
- }
- }
-
- if (!bIsCity)
- {
- if( iCargo >= iTargetInvasionSize )
- {
- bAttack = true;
- }
- if ((iCargo >= iTargetReinforcementSize) || (bFull && iCargo > cargoSpace()))
- {
- bReinforce = true;
- }
-
- CvPlot* pAdjacentPlot = NULL;
- for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
- if( pAdjacentPlot != NULL )
- {
- if( iCargo > 0 )
- {
- CvCity* pAdjacentCity = pAdjacentPlot->getPlotCity();
- if( pAdjacentCity != NULL)
- {
- if ( GET_TEAM(getTeam()).AI_getWarPlan(pAdjacentPlot->getTeam()) != NO_WARPLAN)
- {
- bAttack = true;
- }
-
- if (pAdjacentCity->getOwner() == getOwnerINLINE() && pAdjacentCity->getPreviousOwner() != NO_PLAYER )
- {
- if( (GC.getGameINLINE().getGameTurn() - pAdjacentCity->getGameTurnAcquired()) < 5 )
- {
- // If just captured city and we have some cargo, dump units in city
- getGroup()->pushMission(MISSION_MOVE_TO, pAdjacentPlot->getX_INLINE(), pAdjacentPlot->getY_INLINE(), 0, false, false, MISSIONAI_ASSAULT, pAdjacentPlot);
- return;
- }
- }
- }
- }
- else
- {
- if (pAdjacentPlot->isOwned() && isEnemy(pAdjacentPlot->getTeam()))
- {
- if( pAdjacentPlot->getNumDefenders(getOwnerINLINE()) > 2 )
- {
- // if we just made a dropoff in enemy territory, release sea bombard units to support invaders
- if ((getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA) + getGroup()->countNumUnitAIType(UNITAI_RESERVE_SEA)) > 0)
- {
- bool bMissionPushed = false;
-
- if (AI_seaBombardRange(1))
- {
- bMissionPushed = true;
- }
- CvSelectionGroup* pOldGroup = getGroup();
- //Release any Warships to finish the job.
- getGroup()->AI_separateAI(UNITAI_ATTACK_SEA);
- getGroup()->AI_separateAI(UNITAI_RESERVE_SEA);
- /************************************************************************************************/
- /* UNOFFICIAL_PATCH 05/11/09 jdog5000 */
- /* */
- /* Bugfix */
- /************************************************************************************************/
- /* original bts code
- if (pOldGroup == getGroup() && getUnitType() == UNITAI_ASSAULT_SEA)
- {
- if (AI_retreatToCity(true))
- {
- bMissionPushed = true;
- }
- }
- */
- // Fixed bug in next line with checking unit type instead of unit AI
- if (pOldGroup == getGroup() && AI_getUnitAIType() == UNITAI_ASSAULT_SEA)
- {
- // Need to be sure all units can move
- if( getGroup()->canAllMove() )
- {
- if (AI_retreatToCity(true))
- {
- bMissionPushed = true;
- }
- }
- }
- /************************************************************************************************/
- /* UNOFFICIAL_PATCH END */
- /************************************************************************************************/
- if (bMissionPushed)
- {
- return;
- }
- }
- }
- }
- }
- }
- }
-
- if(iCargo > 0)
- {
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- if( kOwner.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
- {
- if( iEscorts < GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), 2, false) )
- {
- // Wait for units which are joining our group this turn (hopefully escorts)
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- }
- if (bIsBarbarian)
- {
- if (getGroup()->isFull() || iCargo > iTargetInvasionSize)
- {
- if (AI_assaultSeaTransport(false))
- {
- return;
- }
- }
- else
- {
- if (AI_pickup(UNITAI_ATTACK_CITY, true, 5))
- {
- return;
- }
- if (AI_pickup(UNITAI_ATTACK, true, 5))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if( !(getGroup()->getCargo()) )
- {
- AI_barbAttackSeaMove();
- return;
- }
- if( AI_safety() )
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- else
- {
- if (bAttack || bReinforce)
- {
- if( bIsCity )
- {
- getGroup()->AI_separateEmptyTransports();
- }
- if( !(getGroup()->hasCargo()) )
- {
- // this unit was empty group leader
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- FAssert(getGroup()->hasCargo());
- //BBAI TODO: Check that group has escorts, otherwise usually wait
- if( bAttack )
- {
- if( bReinforce && (AI_getBirthmark()%2 == 0) )
- {
- if (AI_assaultSeaReinforce())
- {
- return;
- }
- bReinforce = false;
- }
- if (AI_assaultSeaTransport())
- {
- return;
- }
- }
- // If not enough troops for own invasion,
- if( bReinforce )
- {
- if (AI_assaultSeaReinforce())
- {
- return;
- }
- }
- }
- if( bNoWarPlans && (iCargo >= iTargetReinforcementSize) )
- {
- bAttackBarbarian = true;
- getGroup()->AI_separateEmptyTransports();
- if( !(getGroup()->hasCargo()) )
- {
- // this unit was empty group leader
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- FAssert(getGroup()->hasCargo());
- if (AI_assaultSeaReinforce(bAttackBarbarian))
- {
- return;
- }
- FAssert(getGroup()->hasCargo());
- if (AI_assaultSeaTransport(bAttackBarbarian))
- {
- return;
- }
- }
- }
- if ((bFull || bReinforce) && !bAttack)
- {
- // Group with nearby transports with units on board
- /* original code
- if (AI_group(UNITAI_ASSAULT_SEA, -1, -1, -1, true, false, false, 2, false, true, false, MISSIONAI_ASSAULT))
- {
- return;
- } */ // disabled by K-Mod. This is redundant.
- if (AI_group(UNITAI_ASSAULT_SEA, -1, -1, -1, true, false, false, 10, false, true, false, MISSIONAI_ASSAULT))
- {
- return;
- }
- }
- else if( !bFull )
- {
- bool bHasOneLoad = (getGroup()->getCargo() >= cargoSpace());
- bool bHasCargo = getGroup()->hasCargo();
- if (AI_pickup(UNITAI_ATTACK_CITY, !bHasCargo, (bHasOneLoad ? 3 : 7)))
- {
- return;
- }
- if (AI_pickup(UNITAI_ATTACK, !bHasCargo, (bHasOneLoad ? 3 : 7)))
- {
- return;
- }
-
- if (AI_pickup(UNITAI_COUNTER, !bHasCargo, (bHasOneLoad ? 3 : 7)))
- {
- return;
- }
- if (AI_pickup(UNITAI_ATTACK_CITY, !bHasCargo))
- {
- return;
- }
- if( !bHasCargo )
- {
- if(AI_pickupStranded(UNITAI_ATTACK_CITY))
- {
- return;
- }
- if(AI_pickupStranded(UNITAI_ATTACK))
- {
- return;
- }
- if(AI_pickupStranded(UNITAI_COUNTER))
- {
- return;
- }
- if( (getGroup()->countNumUnitAIType(AI_getUnitAIType()) == 1) )
- {
- // Try picking up any thing
- if(AI_pickupStranded())
- {
- return;
- }
- }
- }
- }
- if (bIsCity && bLandWar && getGroup()->hasCargo())
- {
- // Enemy units in this player's territory
- if( kOwner.AI_countNumAreaHostileUnits(area(),true,false,false,false) > (getGroup()->getCargo()/2))
- {
- getGroup()->unloadAll();
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
-
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- void CvUnitAI::AI_settlerSeaMove()
- {
- PROFILE_FUNC();
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
-
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d, cargo %d) starting settleSeaMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits(), getGroup()->getCargo());
- }
- bool bEmpty = !getGroup()->hasCargo();
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = kOwner.AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
- {
- if( bEmpty )
- {
- if (AI_anyAttack(1, 65))
- {
- return;
- }
- }
- // Retreat to primary area first
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (bEmpty)
- {
- if (AI_anyAttack(1, 65))
- {
- return;
- }
- }
-
- int iSettlerCount = getUnitAICargo(UNITAI_SETTLE);
- int iWorkerCount = getUnitAICargo(UNITAI_WORKER);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 12/07/08 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- if( hasCargo() && (iSettlerCount == 0) && (iWorkerCount == 0))
- {
- // Dump troop load at first oppurtunity after pick up
- if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
- {
- getGroup()->unloadAll();
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- else
- {
- if( !(isFull()) )
- {
- if(AI_pickupStranded(NO_UNITAI, 1))
- {
- return;
- }
- }
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 06/02/09 jdog5000 */
- /* */
- /* Settler AI */
- /************************************************************************************************/
- // Don't send transport with settler and no defense
- if( (iSettlerCount > 0) && (iSettlerCount + iWorkerCount == cargoSpace()) )
- {
- // No defenders for settler
- if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
- {
- getGroup()->unloadAll();
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- if ((iSettlerCount > 0) && (isFull() ||
- ((getUnitAICargo(UNITAI_CITY_DEFENSE) > 0) &&
- (kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SETTLER) == 0))))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- if (AI_settlerSeaTransport())
- {
- return;
- }
- }
- else if ((getTeam() != plot()->getTeam()) && bEmpty)
- {
- if (AI_pillageRange(3))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- if (plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() && !hasCargo())
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- AreaAITypes eAreaAI = area()->getAreaAIType(getTeam());
- if ((eAreaAI == AREAAI_ASSAULT) || (eAreaAI == AREAAI_ASSAULT_MASSING))
- {
- CvArea* pWaterArea = plot()->waterArea();
- FAssert(pWaterArea != NULL);
- if (pWaterArea != NULL)
- {
- if (kOwner.AI_totalWaterAreaUnitAIs(pWaterArea, UNITAI_SETTLER_SEA) > 1)
- {
- if (kOwner.AI_unitValue(getUnitType(), UNITAI_ASSAULT_SEA, pWaterArea) > 0)
- {
- AI_setUnitAIType(UNITAI_ASSAULT_SEA);
- AI_assaultSeaMove();
- return;
- }
- }
- }
- }
- }
-
- if ((iWorkerCount > 0)
- && kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SETTLER) == 0)
- {
- if (isFull() || (iSettlerCount == 0))
- {
- if (AI_settlerSeaFerry())
- {
- return;
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Settler AI */
- /************************************************************************************************/
- /* original bts code
- if (AI_pickup(UNITAI_SETTLE))
- {
- return;
- }
- */
- if( !(getGroup()->hasCargo()) )
- {
- if(AI_pickupStranded(UNITAI_SETTLE))
- {
- return;
- }
- }
- if( !(getGroup()->isFull()) )
- {
- if( kOwner.AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SETTLER) > 0 )
- {
- // Wait for units on the way
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if( iSettlerCount > 0 )
- {
- if (AI_pickup(UNITAI_CITY_DEFENSE))
- {
- return;
- }
- }
- else if( cargoSpace() - 2 >= getCargo() + iWorkerCount )
- {
- if (AI_pickup(UNITAI_SETTLE, true))
- {
- return;
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- /*
- if ((GC.getGame().getGameTurn() - getGameTurnCreated()) < 8)
- {
- if ((plot()->getPlotCity() == NULL) || GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(plot()->area(), UNITAI_SETTLE) == 0)
- {
- if (AI_explore())
- {
- return;
- }
- }
- }
- */
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/18/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- /* original bts code
- if (AI_pickup(UNITAI_WORKER))
- {
- return;
- }
- */
- if( !getGroup()->hasCargo() )
- {
- // Rescue stranded non-settlers
- if(AI_pickupStranded())
- {
- return;
- }
- }
-
- if( cargoSpace() - 2 < getCargo() + iWorkerCount )
- {
- // If full of workers and not going anywhere, dump them if a settler is available
- if( (iSettlerCount == 0) && (plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, UNITAI_SETTLE, -1, getOwnerINLINE(), NO_TEAM, PUF_isFiniteRange) > 0) )
- {
- getGroup()->unloadAll();
- if (AI_pickup(UNITAI_SETTLE, true))
- {
- return;
- }
- return;
- }
- }
-
- if( !(getGroup()->isFull()) )
- {
- if (AI_pickup(UNITAI_WORKER))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
-
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_missionarySeaMove()
- {
- PROFILE_FUNC();
- // Tholal AI - catch for upgraded units
- if (cargoSpace() == 0)
- {
- AI_setUnitAIType(UNITAI_EXPLORE_SEA);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- // End Tholal AI
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
- {
- // Retreat to primary area first
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (getUnitAICargo(UNITAI_MISSIONARY) > 0)
- {
- if (AI_specialSeaTransportMissionary())
- {
- return;
- }
- }
- else if (!(getGroup()->hasCargo()))
- {
- if (AI_pillageRange(4))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/14/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- if( !(getGroup()->isFull()) )
- {
- if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SPECIAL) > 0 )
- {
- // Wait for units on the way
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- if (AI_pickup(UNITAI_MISSIONARY, true))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
-
- if (AI_explore())
- {
- return;
- }
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_spySeaMove()
- {
- PROFILE_FUNC();
- CvCity* pCity;
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
- {
- // Retreat to primary area first
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (getUnitAICargo(UNITAI_SPY) > 0)
- {
- if (AI_specialSeaTransportSpy())
- {
- return;
- }
- pCity = plot()->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY, pCity->plot());
- return;
- }
- }
- }
- else if (!(getGroup()->hasCargo()))
- {
- if (AI_pillageRange(5))
- {
- return;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/14/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- if( !(getGroup()->isFull()) )
- {
- if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SPECIAL) > 0 )
- {
- // Wait for units on the way
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- if (AI_pickup(UNITAI_SPY, true))
- {
- return;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_carrierSeaMove()
- {
- PROFILE_FUNC();
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
- {
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
-
- if (AI_heal(50))
- {
- return;
- }
- if (!isEnemy(plot()->getTeam()))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) > 0)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- else
- {
- if (AI_seaBombardRange(1))
- {
- return;
- }
- }
- if (AI_group(UNITAI_CARRIER_SEA, -1, /*iMaxOwnUnitAI*/ 1))
- {
- return;
- }
- if (getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA) + getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA) == 0)
- {
- if (plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- }
- if (getCargo() > 0)
- {
- if (AI_carrierSeaTransport())
- {
- return;
- }
- if (AI_blockade())
- {
- return;
- }
- if (AI_shadow(UNITAI_ASSAULT_SEA))
- {
- return;
- }
- }
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- if (AI_retreatToCity(true))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_missileCarrierSeaMove()
- {
- PROFILE_FUNC();
- bool bIsStealth = (getInvisibleType() != NO_INVISIBLE);
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 06/14/09 Solver & jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if( getDamage() > 0 ) // extra risk to leaving when wounded
- {
- iOurDefense *= 2;
- }
- if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
- {
- if (AI_shadow(UNITAI_ASSAULT_SEA, 1, 50, false, true, getMoves()))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
-
- if (plot()->isCity() && plot()->getTeam() == getTeam())
- {
- if (AI_heal())
- {
- return;
- }
- }
- if (((plot()->getTeam() != getTeam()) && getGroup()->hasCargo()) || getGroup()->AI_isFull())
- {
- if (bIsStealth)
- {
- if (AI_carrierSeaTransport())
- {
- return;
- }
- }
- else
- {
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 06/14/09 jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- if (AI_shadow(UNITAI_ASSAULT_SEA, 1, 50, true, false, 12))
- {
- return;
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
-
- if (AI_carrierSeaTransport())
- {
- return;
- }
- }
- }
- // if (AI_pickup(UNITAI_ICBM))
- // {
- // return;
- // }
- //
- // if (AI_pickup(UNITAI_MISSILE_AIR))
- // {
- // return;
- // }
- if (AI_retreatToCity())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- }
- void CvUnitAI::AI_attackAirMove()
- {
- PROFILE_FUNC();
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- CvCity* pCity = plot()->getPlotCity();
- bool bSkiesClear = true;
- int iDX, iDY;
- // Check for sufficient defenders to stay
- int iDefenders = plot()->plotCount(PUF_canDefend, -1, -1, plot()->getOwner());
- int iAttackAirCount = plot()->plotCount(PUF_canAirAttack, -1, -1, NO_PLAYER, getTeam());
- iAttackAirCount += 2 * plot()->plotCount(PUF_isUnitAIType, UNITAI_ICBM, -1, NO_PLAYER, getTeam());
- if( plot()->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()) )
- {
- iDefenders -= 1;
- }
- if( pCity != NULL )
- {
- if( pCity->getDefenseModifier(true) < 40 )
- {
- iDefenders -= 1;
- }
- if( pCity->getOccupationTimer() > 1 )
- {
- iDefenders -= 1;
- }
- }
- if( iAttackAirCount > iDefenders )
- {
- if (AI_airOffensiveCity())
- {
- return;
- }
- }
- // Check for direct threat to current base
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if (iEnemyOffense > iOurDefense || iOurDefense == 0)
- {
- // Too risky, pull back
- if (AI_airOffensiveCity())
- {
- return;
- }
- if( canAirDefend() )
- {
- if (AI_airDefensiveCity())
- {
- return;
- }
- }
- }
- else if( iEnemyOffense > iOurDefense/3 )
- {
- if( getDamage() == 0 )
- {
- if( collateralDamage() == 0 && canAirDefend() )
- {
- if (pCity != NULL)
- {
- // Check for whether city needs this unit to air defend
- if( !(pCity->AI_isAirDefended(true,-1)) )
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- }
- }
- // Attack the invaders!
- if (AI_defendBaseAirStrike())
- {
- return;
- }
-
- if (AI_defensiveAirStrike())
- {
- return;
- }
- if (AI_airStrike())
- {
- return;
- }
- // If no targets, no sense staying in risky place
- if (AI_airOffensiveCity())
- {
- return;
- }
- if( canAirDefend() )
- {
- if (AI_airDefensiveCity())
- {
- return;
- }
- }
- }
- if( healTurns(plot()) > 1 )
- {
- // If very damaged, no sense staying in risky place
- if (AI_airOffensiveCity())
- {
- return;
- }
- if( canAirDefend() )
- {
- if (AI_airDefensiveCity())
- {
- return;
- }
- }
- }
-
- }
- }
- if( getDamage() > 0 )
- {
- if (((100*currHitPoints()) / maxHitPoints()) < 40)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- else
- {
- CvPlot *pLoopPlot;
- int iSearchRange = airRange();
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- if (!bSkiesClear) break;
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (bestInterceptor(pLoopPlot) != NULL)
- {
- bSkiesClear = false;
- break;
- }
- }
- }
- }
- if (!bSkiesClear)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- CvArea* pArea = area();
- int iAttackValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_ATTACK_AIR, pArea);
- int iCarrierValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_CARRIER_AIR, pArea);
- if (iCarrierValue > 0)
- {
- int iCarriers = kPlayer.AI_totalUnitAIs(UNITAI_CARRIER_SEA);
- if (iCarriers > 0)
- {
- UnitTypes eBestCarrierUnit = NO_UNIT;
- kPlayer.AI_bestAreaUnitAIValue(UNITAI_CARRIER_SEA, NULL, &eBestCarrierUnit);
- if (eBestCarrierUnit != NO_UNIT)
- {
- int iCarrierAirNeeded = iCarriers * GC.getUnitInfo(eBestCarrierUnit).getCargoSpace();
- if (kPlayer.AI_totalUnitAIs(UNITAI_CARRIER_AIR) < iCarrierAirNeeded)
- {
- AI_setUnitAIType(UNITAI_CARRIER_AIR);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- }
- int iDefenseValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_DEFENSE_AIR, pArea);
- if (iDefenseValue > iAttackValue)
- {
- if (kPlayer.AI_bestAreaUnitAIValue(UNITAI_ATTACK_AIR, pArea) > iAttackValue)
- {
- AI_setUnitAIType(UNITAI_DEFENSE_AIR);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/6/08 jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- /* original BTS code
- if (AI_airBombDefenses())
- {
- return;
- }
- if (GC.getGameINLINE().getSorenRandNum(4, "AI Air Attack Move") == 0)
- {
- if (AI_airBombPlots())
- {
- return;
- }
- }
- if (AI_airStrike())
- {
- return;
- }
-
- if (canAirAttack())
- {
- if (AI_airOffensiveCity())
- {
- return;
- }
- }
-
- if (canRecon(plot()))
- {
- if (AI_exploreAir())
- {
- return;
- }
- }
- if (canAirDefend())
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- */
- bool bDefensive = false;
- if( pArea != NULL )
- {
- bDefensive = pArea->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE;
- }
- if (GC.getGameINLINE().getSorenRandNum(bDefensive ? 3 : 6, "AI Air Attack Move") == 0)
- {
- if( AI_defensiveAirStrike() )
- {
- return;
- }
- }
- if (GC.getGameINLINE().getSorenRandNum(4, "AI Air Attack Move") == 0)
- {
- // only moves unit in a fort
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- }
- // Support ground attacks
- if (AI_airBombDefenses())
- {
- return;
- }
- if (GC.getGameINLINE().getSorenRandNum(bDefensive ? 6 : 4, "AI Air Attack Move") == 0)
- {
- if (AI_airBombPlots())
- {
- return;
- }
- }
- if (AI_airStrike())
- {
- return;
- }
-
- if (canAirAttack())
- {
- if (AI_airOffensiveCity())
- {
- return;
- }
- }
- else
- {
- if( canAirDefend() )
- {
- if (AI_airDefensiveCity())
- {
- return;
- }
- }
- }
- // BBAI TODO: Support friendly attacks on common enemies, if low risk?
- if (canAirDefend())
- {
- if( bDefensive || GC.getGameINLINE().getSorenRandNum(2, "AI Air Attack Move") == 0 )
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- }
-
- if (canRecon(plot()))
- {
- if (AI_exploreAir())
- {
- return;
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
-
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_defenseAirMove()
- {
- PROFILE_FUNC();
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- CvCity* pCity = plot()->getPlotCity();
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
-
- // includes forts
- if (plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
-
- if (3*iEnemyOffense > 4*iOurDefense || iOurDefense == 0)
- {
- // Too risky, pull out
- // AI_airDefensiveCity will leave some air defense, pull extras out
- if (AI_airDefensiveCity())
- {
- return;
- }
- }
- else if ( iEnemyOffense > iOurDefense/3 )
- {
- if (getDamage() > 0)
- {
- if( healTurns(plot()) > 1 + GC.getGameINLINE().getSorenRandNum(2, "AI Air Defense Move") )
- {
- // Can't help current situation, only risk losing unit
- if (AI_airDefensiveCity())
- {
- return;
- }
- }
- // Stay to defend in the future
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (canAirDefend() && pCity != NULL)
- {
- // Check for whether city needs this unit to air defend
- if( !(pCity->AI_isAirDefended(true,-1)) )
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- // Consider adding extra defenders
- if( collateralDamage() == 0 && (!pCity->AI_isAirDefended(false,-2)) )
- {
- if( GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") == 0 )
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- }
- }
- // Attack the invaders!
- if (AI_defendBaseAirStrike())
- {
- return;
- }
-
- if (AI_defensiveAirStrike())
- {
- return;
- }
- if (AI_airStrike())
- {
- return;
- }
- if (AI_airDefensiveCity())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (getDamage() > 0)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
-
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/17/08 Solver & jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- /* original BTS code
- if ((GC.getGameINLINE().getSorenRandNum(2, "AI Air Defense Move") == 0))
- {
- if ((pCity != NULL) && pCity->AI_isDanger())
- {
- if (AI_airStrike())
- {
- return;
- }
- }
- else
- {
- if (AI_airBombDefenses())
- {
- return;
- }
- if (AI_airStrike())
- {
- return;
- }
-
- if (AI_getBirthmark() % 2 == 0)
- {
- if (AI_airBombPlots())
- {
- return;
- }
- }
- }
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- }
- bool bNoWar = (GET_TEAM(getTeam()).getAtWarCount(false) == 0);
-
- if (canRecon(plot()))
- {
- if (GC.getGame().getSorenRandNum(bNoWar ? 2 : 4, "AI defensive air recon") == 0)
- {
- if (AI_exploreAir())
- {
- return;
- }
- }
- }
- if (AI_airDefensiveCity())
- {
- return;
- }
- */
- if((GC.getGameINLINE().getSorenRandNum(4, "AI Air Defense Move") == 0))
- {
- // only moves unit in a fort
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- }
- if( canAirDefend() )
- {
- // Check for whether city needs this unit for base air defenses
- int iBaseAirDefenders = 0;
- if( iEnemyOffense > 0 )
- {
- iBaseAirDefenders++;
- }
- if( pCity != NULL )
- {
- iBaseAirDefenders += pCity->AI_neededAirDefenders()/2;
- }
-
- if( plot()->countAirInterceptorsActive(getTeam()) < iBaseAirDefenders )
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- }
- CvArea* pArea = area();
- bool bDefensive = false;
- bool bOffensive = false;
- if( pArea != NULL )
- {
- bDefensive = (pArea->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE);
- bOffensive = (pArea->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE);
- }
- if( (iEnemyOffense > 0) || bDefensive )
- {
- if( canAirDefend() )
- {
- if( pCity != NULL )
- {
- // Consider adding extra defenders
- if( !(pCity->AI_isAirDefended(false,-1)) )
- {
- if ((GC.getGameINLINE().getSorenRandNum((bOffensive ? 3 : 2), "AI Air Defense Move") == 0))
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- }
- }
- else
- {
- if ((GC.getGameINLINE().getSorenRandNum((bOffensive ? 3 : 2), "AI Air Defense Move") == 0))
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- }
- }
- if((GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") > 0))
- {
- if (AI_defensiveAirStrike())
- {
- return;
- }
- if (AI_airStrike())
- {
- return;
- }
- }
- }
- else
- {
- if ((GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") > 0))
- {
- // Clear out any enemy fighters, support offensive units
- if (AI_airBombDefenses())
- {
- return;
- }
- if (GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") == 0)
- {
- // Hit enemy land stacks near our cities
- if (AI_defensiveAirStrike())
- {
- return;
- }
- }
- if (AI_airStrike())
- {
- return;
- }
-
- if (AI_getBirthmark() % 2 == 0 || bOffensive)
- {
- if (AI_airBombPlots())
- {
- return;
- }
- }
- }
- }
- if (AI_airDefensiveCity())
- {
- return;
- }
- // BBAI TODO: how valuable is recon information to AI in war time?
- if (canRecon(plot()))
- {
- if (GC.getGame().getSorenRandNum(bDefensive ? 6 : 3, "AI defensive air recon") == 0)
- {
- if (AI_exploreAir())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (canAirDefend())
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_carrierAirMove()
- {
- PROFILE_FUNC();
- // XXX maybe protect land troops?
- if (getDamage() > 0)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (isCargo())
- {
- int iRand = GC.getGameINLINE().getSorenRandNum(3, "AI Air Carrier Move");
- if (iRand == 2 && canAirDefend())
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- else if (AI_airBombDefenses())
- {
- return;
- }
- else if (iRand == 1)
- {
- if (AI_airBombPlots())
- {
- return;
- }
- if (AI_airStrike())
- {
- return;
- }
- }
- else
- {
- if (AI_airStrike())
- {
- return;
- }
- if (AI_airBombPlots())
- {
- return;
- }
- }
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- if (canAirDefend())
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_airCarrier())
- {
- return;
- }
- if (AI_airDefensiveCity())
- {
- return;
- }
- if (canAirDefend())
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_missileAirMove()
- {
- PROFILE_FUNC();
- CvCity* pCity = plot()->getPlotCity();
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- // includes forts
- if (!isCargo() && plot()->isCity(true))
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
-
- if (iEnemyOffense > (iOurDefense/2) || iOurDefense == 0)
- {
- if (AI_airOffensiveCity())
- {
- return;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
-
- if (isCargo())
- {
- int iRand = GC.getGameINLINE().getSorenRandNum(3, "AI Air Missile plot bombing");
- if (iRand != 0)
- {
- if (AI_airBombPlots())
- {
- return;
- }
- }
- iRand = GC.getGameINLINE().getSorenRandNum(3, "AI Air Missile Carrier Move");
- if (iRand == 0)
- {
- if (AI_airBombDefenses())
- {
- return;
- }
- if (AI_airStrike())
- {
- return;
- }
- }
- else
- {
- if (AI_airStrike())
- {
- return;
- }
- if (AI_airBombDefenses())
- {
- return;
- }
- }
- if (AI_airBombPlots())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_airStrike())
- {
- return;
- }
- if (AI_missileLoad(UNITAI_MISSILE_CARRIER_SEA))
- {
- return;
- }
- if (AI_missileLoad(UNITAI_RESERVE_SEA, 1))
- {
- return;
- }
- if (AI_missileLoad(UNITAI_ATTACK_SEA, 1))
- {
- return;
- }
- if (AI_airBombDefenses())
- {
- return;
- }
- if (!isCargo())
- {
- if (AI_airOffensiveCity())
- {
- return;
- }
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_networkAutomated()
- {
- FAssertMsg(canBuildRoute(), "canBuildRoute is expected to be true");
- if (!(getGroup()->canDefend()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0)
- if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot()))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- if (AI_retreatToCity()) // XXX maybe not do this??? could be working productively somewhere else...
- {
- return;
- }
- }
- }
- if (AI_improveBonus(20))
- {
- return;
- }
- if (AI_improveBonus(10))
- {
- return;
- }
- if (AI_connectBonus())
- {
- return;
- }
- if (AI_connectCity())
- {
- return;
- }
- if (AI_improveBonus())
- {
- return;
- }
- if (AI_routeTerritory(true))
- {
- return;
- }
- if (AI_connectBonus(false))
- {
- return;
- }
- if (AI_routeCity())
- {
- return;
- }
- if (AI_routeTerritory())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_cityAutomated()
- {
- CvCity* pCity;
- if (!(getGroup()->canDefend()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0)
- if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot()))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- if (AI_retreatToCity()) // XXX maybe not do this??? could be working productively somewhere else...
- {
- return;
- }
- }
- }
- pCity = NULL;
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- pCity = plot()->getWorkingCity();
- }
- if (pCity == NULL)
- {
- pCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE()); // XXX do team???
- }
- if (pCity != NULL)
- {
- if (AI_improveCity(pCity))
- {
- return;
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- // XXX make sure we include any new UnitAITypes...
- int CvUnitAI::AI_promotionValue(PromotionTypes ePromotion)
- {
- int iValue;
- int iTemp;
- int iExtra;
- int iI;
- UnitAITypes eUnitAI = AI_getUnitAIType();
- int iLevel = getLevel();
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- iValue = 0;
- bool bFinancialTrouble = kPlayer.AI_isFinancialTrouble();
- CvPromotionInfo& kPromotion = GC.getPromotionInfo(ePromotion);
- if (kPromotion.isLeader())
- {
- // Don't consume the leader as a regular promotion
- return 0;
- }
- if (kPromotion.isBlitz())
- {
- iValue += (firstStrikes() + getExtraFirstStrikes()) * 100;
- if (baseMoves() > 1)
- {
- iValue += 5 * baseMoves();
- if (eUnitAI == UNITAI_ATTACK_CITY)
- {
- iValue += 50;
- }
- }
- /*
- if ((AI_getUnitAIType() == UNITAI_RESERVE && baseMoves() > 1) ||
- AI_getUnitAIType() == UNITAI_PARADROP)
- {
- iValue += 10;
- }
- else
- {
- //FfH: Modified by Kael 06/28/2008
- // iValue += 2;
- iValue += 5 * baseMoves();
- //FfH: End Modify
- }
- */
- }
- // Tholal AI - account for new FFH promotion tags
- // ToDo - add logic for tags that arent selectable but could be in mods (flying, Dispellable, Immortal, immunetofear, bImmuneToMagic,
- iValue += (kPromotion.getResistMagic() * iLevel) / 5;
- if (kPromotion.isIgnoreBuildingDefense())
- {
- if (eUnitAI == UNITAI_ATTACK_CITY)
- {
- iValue += 25;
- }
- }
- if (kPromotion.isSeeInvisible())
- {
- if (eUnitAI == UNITAI_CITY_DEFENSE)
- {
- iValue += 50;
- }
- else
- {
- iValue += 25;
- }
- }
- if (kPromotion.isInvisible())
- {
- if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_ATTACK_CITY) || (eUnitAI == UNITAI_COUNTER) || (eUnitAI == UNITAI_EXPLORE))
- {
- iValue += 25;
- }
- }
- if (kPromotion.isTargetWeakestUnit())
- {
- if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_ATTACK_CITY) || (eUnitAI == UNITAI_COUNTER))
- {
- iValue += 25;
- }
- }
- if (kPromotion.isTargetWeakestUnitCounter())
- {
- if ((eUnitAI == UNITAI_CITY_DEFENSE) || (eUnitAI == UNITAI_COUNTER) || (eUnitAI == UNITAI_CITY_COUNTER))
- {
- iValue += 25;
- }
- }
- int iCombatHeal = kPromotion.getCombatHealPercent();
- if (iCombatHeal > 0)
- {
- if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_ATTACK_CITY) || (eUnitAI == UNITAI_COUNTER))
- {
- iValue += (iCombatHeal * (iLevel + 1));
- }
- else
- {
- iValue += iCombatHeal;
- }
- }
- iValue += (kPromotion.getCombatCapturePercent() * (iLevel + 2));
- if (kPromotion.isFear())
- {
- iValue += 100;
- }
- //Bounty Hunter
- iValue += kPromotion.getGoldFromCombat() * (iLevel / (bFinancialTrouble ? 1: 2));
- //Twincast
- if (kPromotion.isTwincast())
- {
- if (isSummoner())
- {
- iValue += getLevel() * 8;
- }
- }
- // HARDCODED promotions
- // Inquisitor
- if (ePromotion == ((PromotionTypes)GC.getInfoTypeForString("PROMOTION_INQUISITOR")))
- {
- if (kPlayer.AI_isDoVictoryStrategy(AI_VICTORY_RELIGION2))
- {
- int iNeededInquisitors = (kPlayer.getNumCities() / 5);
- iNeededInquisitors = std::max(1, iNeededInquisitors);
- if (kPlayer.AI_getNumAIUnits(UNITAI_INQUISITOR) < iNeededInquisitors)
- {
- iValue += 140;
- }
- }
- }
- //Metamagic for Tower Victory Strategies
- if (ePromotion == ((PromotionTypes)GC.getInfoTypeForString("PROMOTION_METAMAGIC1")) || ePromotion == ((PromotionTypes)GC.getInfoTypeForString("PROMOTION_METAMAGIC2")))
- {
- if (kPlayer.AI_isDoVictoryStrategy(AI_VICTORY_TOWERMASTERY1))
- {
- if ((eUnitAI == UNITAI_MANA_UPGRADE))
- {
- iValue += 100;
- }
- }
- }
- // Nature 1
- if (ePromotion == ((PromotionTypes)GC.getInfoTypeForString("PROMOTION_NATURE1")))
- {
- if (GC.getCivilizationInfo(getCivilizationType()).getDefaultRace() == (GC.getInfoTypeForString("PROMOTION_ELF") || GC.getInfoTypeForString("PROMOTION_DARK_ELF")))
- {
- iValue += 30;
- }
- if (kPlayer.getStateReligion() != NO_RELIGION)
- {
- if (kPlayer.getStateReligion() == ((ReligionTypes)GC.getInfoTypeForString("RELIGION_FELLOWSHIP_OF_LEAVES")))
- {
- iValue += 25;
- }
- }
- }
- // End Tholal AI
- if (kPromotion.isAmphib())
- {
- if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_ATTACK_CITY))
- {
- iValue += 5;
- }
- else
- {
- iValue++;
- }
- }
- if (kPromotion.isRiver())
- {
- if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_ATTACK_CITY))
- {
- iValue += 5;
- }
- else
- {
- iValue++;
- }
- }
- if (kPromotion.isEnemyRoute())
- {
- if (eUnitAI == UNITAI_PILLAGE || isBlitz())
- {
- iValue += 25;
- }
- else if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_ATTACK_CITY))
- {
- iValue += 15;
- }
- else if (eUnitAI == UNITAI_PARADROP || eUnitAI == UNITAI_EXPLORE)
- {
- iValue += 10;
- }
- else
- {
- iValue += 4;
- }
- }
- if (kPromotion.isAlwaysHeal())
- {
- if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_ATTACK_CITY) ||
- (eUnitAI == UNITAI_PILLAGE) ||
- (eUnitAI == UNITAI_COUNTER) ||
- (eUnitAI == UNITAI_ATTACK_SEA) ||
- (eUnitAI == UNITAI_PIRATE_SEA) ||
- (eUnitAI == UNITAI_ESCORT_SEA) ||
- (eUnitAI == UNITAI_PARADROP) ||
- (eUnitAI == UNITAI_HERO))
- {
- iValue += 12;
- }
- else
- {
- iValue += 8;
- }
- }
- if (kPromotion.isHillsDoubleMove())
- {
- if (eUnitAI == UNITAI_EXPLORE)
- {
- iValue += 20;
- }
- else
- {
- iValue += 10;
- }
- }
- if (kPromotion.isImmuneToFirstStrikes()
- && !immuneToFirstStrikes())
- {
- if ((eUnitAI == UNITAI_ATTACK_CITY))
- {
- iValue += 20;
- }
- else if ((eUnitAI == UNITAI_ATTACK))
- {
- iValue += 8;
- }
- else
- {
- iValue += 4;
- }
- }
- iTemp = kPromotion.getVisibilityChange();
- if ((eUnitAI == UNITAI_EXPLORE_SEA) ||
- (eUnitAI == UNITAI_EXPLORE))
- {
- iValue += (iTemp * 40);
- }
- else if (eUnitAI == UNITAI_PIRATE_SEA)
- {
- iValue += (iTemp * 25);
- }
- // mobility
- iTemp = 0;
- if (eUnitAI != UNITAI_CITY_DEFENSE && eUnitAI != UNITAI_CITY_COUNTER && eUnitAI != UNITAI_CITY_SPECIAL && eUnitAI != UNITAI_MAGE)
- {
- iTemp += 20;
- iTemp += (isAlive() ? 10 : 20); //slight bonus for non-alive units since they cant be Hasted
- if (m_pUnitInfo->getMoves() == 1)
- {
- iTemp += 20 + (iLevel * 6);
- }
- if (isBlitz() || eUnitAI == UNITAI_PILLAGE || isWaterWalking())
- {
- iTemp+= 20;
- }
- }
- iValue += iTemp * kPromotion.getMovesChange();
- iTemp = kPromotion.getMoveDiscountChange();
- if (eUnitAI == UNITAI_PILLAGE)
- {
- iValue += (iTemp * 10);
- }
- else
- {
- iValue += (iTemp * 2);
- }
- iTemp = kPromotion.getAirRangeChange();
- if (eUnitAI == UNITAI_ATTACK_AIR ||
- eUnitAI == UNITAI_CARRIER_AIR)
- {
- iValue += (iTemp * 20);
- }
- else if (eUnitAI == UNITAI_DEFENSE_AIR)
- {
- iValue += (iTemp * 10);
- }
- iTemp = kPromotion.getInterceptChange();
- if (eUnitAI == UNITAI_DEFENSE_AIR)
- {
- iValue += (iTemp * 3);
- }
- else if (eUnitAI == UNITAI_CITY_SPECIAL || eUnitAI == UNITAI_CARRIER_AIR)
- {
- iValue += (iTemp * 2);
- }
- else
- {
- iValue += (iTemp / 10);
- }
- iTemp = kPromotion.getEvasionChange();
- if (eUnitAI == UNITAI_ATTACK_AIR || eUnitAI == UNITAI_CARRIER_AIR)
- {
- iValue += (iTemp * 3);
- }
- else
- {
- iValue += (iTemp / 10);
- }
- iTemp = kPromotion.getFirstStrikesChange() * 2;
- iTemp += kPromotion.getChanceFirstStrikesChange();
- /*
- if ((eUnitAI == UNITAI_RESERVE) ||
- (eUnitAI == UNITAI_COUNTER) ||
- (eUnitAI == UNITAI_CITY_DEFENSE) ||
- (eUnitAI == UNITAI_CITY_COUNTER) ||
- (eUnitAI == UNITAI_CITY_SPECIAL) ||
- (eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_HERO))*/
- {
- iTemp *= iLevel;
- iExtra = getExtraChanceFirstStrikes() + getExtraFirstStrikes() * 2;
- iTemp *= 100 + iExtra * 15;
- iTemp /= 100;
- iValue += iTemp;
- }
- /*
- else
- {
- iValue += (iTemp * 5);
- }
- */
- iTemp = kPromotion.getWithdrawalChange();
- if (iTemp != 0)
- {
- iExtra = (m_pUnitInfo->getWithdrawalProbability() + (getExtraWithdrawal() * 4));
- iTemp *= (100 + iExtra);
- iTemp /= 100;
- if ((eUnitAI == UNITAI_ATTACK_CITY) ||
- (eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_ATTACK_SEA) ||
- (eUnitAI == UNITAI_HERO))
- {
- iValue += (iTemp * 4) / 3;
- }
- else if ((eUnitAI == UNITAI_COLLATERAL) ||
- (eUnitAI == UNITAI_RESERVE) ||
- (eUnitAI == UNITAI_RESERVE_SEA) ||
- getLeaderUnitType() != NO_UNIT)
- {
- iValue += iTemp * 1;
- }
- else
- {
- iValue += (iTemp / 4);
- }
- }
- iTemp = kPromotion.getCollateralDamageChange();
- if (iTemp != 0)
- {
- iExtra = (getExtraCollateralDamage());//collateral has no strong synergy (not like retreat)
- iTemp *= (100 + iExtra);
- iTemp /= 100;
- if (eUnitAI == UNITAI_COLLATERAL)
- {
- iValue += (iTemp * 2);
- }
- else if (eUnitAI == UNITAI_ATTACK_CITY)
- {
- iValue += iTemp;
- }
- else
- {
- iValue += (iTemp / 8);
- }
- }
- iTemp = kPromotion.getBombardRateChange();
- if (eUnitAI == UNITAI_ATTACK_CITY)
- {
- iValue += (iTemp * 2);
- }
- else
- {
- iValue += (iTemp / 8);
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/26/10 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- iTemp = kPromotion.getEnemyHealChange();
- if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_ATTACK_CITY) ||
- (eUnitAI == UNITAI_PILLAGE) ||
- (eUnitAI == UNITAI_ATTACK_SEA) ||
- (eUnitAI == UNITAI_PARADROP) ||
- (eUnitAI == UNITAI_PIRATE_SEA) ||
- (AI_getGroupflag() == GROUPFLAG_CONQUEST))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- iValue += iTemp;
- }
- else
- {
- iValue += (iTemp / 2);
- }
- iTemp = kPromotion.getNeutralHealChange();
- iValue += (iTemp / 2);
- iTemp = kPromotion.getFriendlyHealChange();
- if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
- (eUnitAI == UNITAI_CITY_COUNTER) ||
- (eUnitAI == UNITAI_CITY_SPECIAL))
- {
- iValue += iTemp;
- }
- else
- {
- iValue += (iTemp / 4);
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/26/10 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if ( getDamage() > 0 || ((AI_getBirthmark() % 8 == 0) && (eUnitAI == UNITAI_COUNTER ||
- eUnitAI == UNITAI_PILLAGE ||
- eUnitAI == UNITAI_ATTACK_CITY ||
- eUnitAI == UNITAI_MEDIC ||
- eUnitAI == UNITAI_RESERVE )) )
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- iTemp = kPromotion.getSameTileHealChange() + getSameTileHeal();
- iExtra = getSameTileHeal();
- iTemp *= (100 + iExtra * 5);
- iTemp /= 100;
- if (iTemp > 0)
- {
- if (healRate(plot()) < iTemp)
- {
- iValue += iTemp * ((getGroup()->getNumUnits() > 4) ? 4 : 2);
- }
- else
- {
- iValue += (iTemp / 8);
- }
- }
- iTemp = kPromotion.getAdjacentTileHealChange();
- iExtra = getAdjacentTileHeal();
- iTemp *= (100 + iExtra * 5);
- iTemp /= 100;
- if ((eUnitAI == UNITAI_MEDIC))
- {
- iTemp *= 2;
- }
- if (getSameTileHeal() >= iTemp)
- {
- iValue += (iTemp * ((getGroup()->getNumUnits() > 9) ? 4 : 2));
- }
- else
- {
- iValue += (iTemp / 4);
- }
- }
- //FfH: Modified by Kael 11/14/2009 0.41k
- // try to use Warlords to create super-medic units
- // if (kPromotion.getAdjacentTileHealChange() > 0 || kPromotion.getSameTileHealChange() > 0)
- // {
- // PromotionTypes eLeader = NO_PROMOTION;
- // for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
- // {
- // if (GC.getPromotionInfo((PromotionTypes)iI).isLeader())
- // {
- // eLeader = (PromotionTypes)iI;
- // }
- // }
- //
- // if (isHasPromotion(eLeader) && eLeader != NO_PROMOTION)
- // {
- // iValue += kPromotion.getAdjacentTileHealChange() + kPromotion.getSameTileHealChange();
- // }
- // }
- //FfH: End Modify
- // lfgr AI 04/2021: Summoners no longer prefer CombatPercent.
- // Combat I-V's granted empower promotions are counted below anyway.
- iTemp = kPromotion.getCombatPercent();
- if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_COUNTER) ||
- (eUnitAI == UNITAI_CITY_COUNTER) ||
- (eUnitAI == UNITAI_ATTACK_SEA) ||
- (eUnitAI == UNITAI_RESERVE_SEA) ||
- (eUnitAI == UNITAI_PARADROP) ||
- (eUnitAI == UNITAI_PIRATE_SEA) ||
- (eUnitAI == UNITAI_ESCORT_SEA) ||
- (eUnitAI == UNITAI_CARRIER_SEA) ||
- (eUnitAI == UNITAI_ATTACK_AIR) ||
- (eUnitAI == UNITAI_CARRIER_AIR) ||
- //isSummoner() ||
- (eUnitAI == UNITAI_HERO))
- {
- iValue += (iTemp * 2);
- }
- else
- {
- iValue += (iTemp * 1);
- }
- if (isDirectDamageCaster())
- {
- iValue += kPromotion.getSpellDamageModify() * 4;
- }
- iTemp = kPromotion.getCityAttackPercent();
- if (iTemp != 0)
- {
- if (m_pUnitInfo->getUnitAIType(UNITAI_ATTACK) || m_pUnitInfo->getUnitAIType(UNITAI_ATTACK_CITY) || m_pUnitInfo->getUnitAIType(UNITAI_ATTACK_CITY_LEMMING))
- {
- iExtra = (m_pUnitInfo->getCityAttackModifier() + (getExtraCityAttackPercent() * 2));
- iTemp *= (100 + iExtra);
- iTemp /= 100;
- if (eUnitAI == UNITAI_ATTACK_CITY)
- {
- iValue += (iTemp * 1);
- }
- else
- {
- iValue -= iTemp / 4;
- }
- }
- }
- if (kPromotion.isImmuneToDefensiveStrike())
- {
- if (eUnitAI == UNITAI_ATTACK_CITY)
- {
- iValue += 50;
- }
- }
- iTemp = kPromotion.getCityDefensePercent();
- if (iTemp != 0)
- {
- if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
- (eUnitAI == UNITAI_CITY_SPECIAL))
- {
- iExtra = m_pUnitInfo->getCityDefenseModifier() + (getExtraCityDefensePercent() * 2);
- iValue += ((iTemp * (100 + iExtra)) / 100);
- }
- else
- {
- iValue += (iTemp / 4);
- }
- }
- if (kPromotion.isDoubleFortifyBonus())
- {
- if (eUnitAI == UNITAI_CITY_DEFENSE)
- {
- iValue += 50;
- }
- }
- iTemp = kPromotion.getHillsAttackPercent();
- if (iTemp != 0)
- {
- iExtra = getExtraHillsAttackPercent();
- iTemp *= (100 + iExtra * 2);
- iTemp /= 100;
- if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_COUNTER))
- {
- iValue += (iTemp / 4);
- }
- else
- {
- iValue += (iTemp / 16);
- }
- }
- iTemp = kPromotion.getHillsDefensePercent();
- if (iTemp != 0)
- {
- iExtra = (m_pUnitInfo->getHillsDefenseModifier() + (getExtraHillsDefensePercent() * 2));
- iTemp *= (100 + iExtra);
- iTemp /= 100;
- if (eUnitAI == UNITAI_CITY_DEFENSE)
- {
- if (plot()->isCity() && plot()->isHills())
- {
- iValue += (iTemp * 2) / 3;
- }
- }
- else if (eUnitAI == UNITAI_COUNTER)
- {
- if (plot()->isHills())
- {
- iValue += (iTemp / 4);
- }
- else
- {
- iValue++;
- }
- }
- else
- {
- iValue += (iTemp / 16);
- }
- }
- iTemp = kPromotion.getRevoltProtection();
- if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
- (eUnitAI == UNITAI_CITY_COUNTER) ||
- (eUnitAI == UNITAI_CITY_SPECIAL))
- {
- if (iTemp > 0)
- {
- PlayerTypes eOwner = plot()->calculateCulturalOwner();
- if (eOwner != NO_PLAYER && GET_PLAYER(eOwner).getTeam() != kPlayer.getTeam())
- {
- iValue += (iTemp / 2);
- }
- }
- }
- iTemp = kPromotion.getCollateralDamageProtection();
- if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
- (eUnitAI == UNITAI_CITY_COUNTER) ||
- (eUnitAI == UNITAI_CITY_SPECIAL))
- {
- iValue += (iTemp / 3);
- }
- else if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_COUNTER))
- {
- iValue += (iTemp / 4);
- }
- else
- {
- iValue += (iTemp / 8);
- }
- iTemp = kPromotion.getPillageChange();
- if (eUnitAI == UNITAI_PILLAGE ||
- eUnitAI == UNITAI_ATTACK_SEA ||
- eUnitAI == UNITAI_PIRATE_SEA)
- {
- iValue += (iTemp / 4);
- }
- else
- {
- iValue += (iTemp / 16);
- }
- iTemp = kPromotion.getUpgradeDiscount();
- iValue += (iTemp / 16);
- iTemp = kPromotion.getExperiencePercent();
- if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_ATTACK_SEA) ||
- (eUnitAI == UNITAI_PIRATE_SEA) ||
- (eUnitAI == UNITAI_RESERVE_SEA) ||
- (eUnitAI == UNITAI_ESCORT_SEA) ||
- (eUnitAI == UNITAI_CARRIER_SEA) ||
- (eUnitAI == UNITAI_MISSILE_CARRIER_SEA))
- {
- iValue += (iTemp * 1);
- }
- else
- {
- iValue += (iTemp / 2);
- }
- iTemp = kPromotion.getKamikazePercent();
- if (eUnitAI == UNITAI_ATTACK_CITY)
- {
- iValue += (iTemp / 16);
- }
- else
- {
- iValue += (iTemp / 64);
- }
- //>>>>Better AI: Added by Denev 2010/03/25
- iTemp = kPromotion.getCargoChange();
- if (eUnitAI == UNITAI_ASSAULT_SEA || eUnitAI == UNITAI_SETTLER_SEA)
- {
- iValue += (iTemp * 24);
- }
- //<<<<Better AI: End Add
- for (iI = 0; iI < GC.getNumTerrainInfos(); iI++)
- {
- iTemp = kPromotion.getTerrainAttackPercent(iI);
- if (iTemp != 0)
- {
- iExtra = getExtraTerrainAttackPercent((TerrainTypes)iI);
- iTemp *= (100 + iExtra * 2);
- iTemp /= 100;
- if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_COUNTER))
- {
- iValue += (iTemp / 4);
- }
- else
- {
- iValue += (iTemp / 16);
- }
- }
- iTemp = kPromotion.getTerrainDefensePercent(iI);
- if (iTemp != 0)
- {
- iExtra = getExtraTerrainDefensePercent((TerrainTypes)iI);
- iTemp *= (100 + iExtra);
- iTemp /= 100;
- if (eUnitAI == UNITAI_COUNTER)
- {
- if (plot()->getTerrainType() == (TerrainTypes)iI)
- {
- iValue += (iTemp / 4);
- }
- else
- {
- iValue++;
- }
- }
- else
- {
- iValue += (iTemp / 16);
- }
- }
- if (kPromotion.getTerrainDoubleMove(iI))
- {
- if (eUnitAI == UNITAI_EXPLORE)
- {
- iValue += 20;
- }
- else if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_PILLAGE))
- {
- iValue += 10;
- }
- else
- {
- iValue += 1;
- }
- }
- }
- for (iI = 0; iI < GC.getNumFeatureInfos(); iI++)
- {
- iTemp = kPromotion.getFeatureAttackPercent(iI);
- if (iTemp != 0)
- {
- iExtra = getExtraFeatureAttackPercent((FeatureTypes)iI);
- iTemp *= (100 + iExtra * 2);
- iTemp /= 100;
- if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_COUNTER))
- {
- iValue += (iTemp / 4);
- }
- else
- {
- iValue += (iTemp / 16);
- }
- }
- iTemp = kPromotion.getFeatureDefensePercent(iI);
- if (iTemp != 0)
- {
- iExtra = getExtraFeatureDefensePercent((FeatureTypes)iI);
- iTemp *= (100 + iExtra * 2);
- iTemp /= 100;
- if (!noDefensiveBonus())
- {
- if (eUnitAI == UNITAI_COUNTER)
- {
- if (plot()->getFeatureType() == (FeatureTypes)iI)
- {
- iValue += (iTemp / 4);
- }
- else
- {
- iValue++;
- }
- }
- else
- {
- iValue += (iTemp / 16);
- }
- }
- }
- if (kPromotion.getFeatureDoubleMove(iI))
- {
- if (eUnitAI == UNITAI_EXPLORE)
- {
- iValue += 20;
- }
- else if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_PILLAGE))
- {
- iValue += 10;
- }
- else
- {
- iValue += 1;
- }
- }
- }
- int iTempValue = 0;
- for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
- {
- int iPromoCombatValue = kPromotion.getUnitCombatModifierPercent(iI);
- if (iPromoCombatValue > 0)
- {
- int iTempPromoValue = 0;
- // prepare counters for the Favorite Unit Combats of whoever we have warplans against
- for (int iK = 0; iK < MAX_PLAYERS; iK++)
- {
- CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iK);
- if (kLoopPlayer.isAlive())
- {
- if (GET_TEAM(getTeam()).AI_getWarPlan(kLoopPlayer.getTeam()) != NO_WARPLAN)
- {
- if (GC.getLeaderHeadInfo(kLoopPlayer.getLeaderType()).getFavoriteUnitCombat() != NO_UNITCOMBAT)
- {
- if (GC.getLeaderHeadInfo(kLoopPlayer.getLeaderType()).getFavoriteUnitCombat() == iI)
- {
- iTempPromoValue += 5;
- }
- }
- }
- }
- }
- // extra value if we already have modifiers against this Unit Combat type
- if (unitCombatModifier((UnitCombatTypes)iI) > 0)
- {
- iTempPromoValue += iPromoCombatValue * iLevel;
- }
- else // otherwise...
- {
- // first make sure we dont have a counter to a different combat type already
- bool bHasOtherCombatCounter = false;
- for (int iJ = 0; iJ < GC.getNumUnitCombatInfos(); iJ++)
- {
- if (iJ != iI)
- {
- if (unitCombatModifier((UnitCombatTypes)iJ) > 0)
- {
- bHasOtherCombatCounter = true;
- break;
- }
- }
- }
- if (!bHasOtherCombatCounter)
- {
- iTempPromoValue += iPromoCombatValue;
- }
- else
- {
- iTempPromoValue = 0;
- }
- }
- iTempValue += iTempPromoValue;
- }
- }
- if ((eUnitAI == UNITAI_COUNTER) || (eUnitAI == UNITAI_CITY_COUNTER))
- {
- iValue += iTempValue * 2;
- }
- else if ((eUnitAI == UNITAI_ATTACK) || (eUnitAI == UNITAI_ATTACK_CITY))
- {
- if (AI_getBirthmark() % 2 == 0)
- {
- iValue += iTempValue;
- }
- }
- else
- {
- iValue += iTempValue / 2;
- }
- // Slaying
- if (kPromotion.getPromotionCombatType() != -1)
- {
- // first make sure we dont have a counter to a different combat type already
- // note - doesnt count PromoCombats :(
- /*
- bool bHasOtherCombatCounter = false;
- for (int iJ = 0; iJ < GC.getNumUnitCombatInfos(); iJ++)
- {
- if (unitCombatModifier((UnitCombatTypes)iJ) > 10)
- {
- logBBAI("has other combat promo");
- bHasOtherCombatCounter = true;
- break;
- }
- }
- */
- int iPromoCombatBonus = kPromotion.getPromotionCombatMod();
- for (int iI = 0; iI < MAX_PLAYERS; iI++)
- {
- if( GET_PLAYER((PlayerTypes)iI).isAlive() )
- {
- if (GET_TEAM(getTeam()).isAtWar(GET_PLAYER((PlayerTypes)iI).getTeam()))
- {
- if (GC.getCivilizationInfo((GET_PLAYER((PlayerTypes)iI).getCivilizationType())).getDefaultRace() == kPromotion.getPromotionCombatType())
- {
- logBBAI("%d bonus to slaying promo for enemy civ", iPromoCombatBonus);
- iValue += iPromoCombatBonus * 2;
- }
- }
- }
- }
- //if (!bHasOtherCombatCounter)
- {
- if ((eUnitAI == UNITAI_CITY_COUNTER) || (eUnitAI == UNITAI_COUNTER) || (eUnitAI == UNITAI_ATTACK))
- {
- iValue += iPromoCombatBonus;
- }
- else
- {
- iValue += iPromoCombatBonus / 2;
- }
- }
- }
- // unit combat type captures (subdue animal)
- if (kPromotion.getCaptureUnitCombat() != NO_UNITCOMBAT)
- {
- iValue += 25;
- if (unitCombatModifier(UnitCombatTypes(kPromotion.getCaptureUnitCombat())) > 0)
- {
- iValue += 15 * iLevel;
- }
- }
- for (iI = 0; iI < NUM_DOMAIN_TYPES; iI++)
- {
- //WTF? why float and cast to int?
- //iTemp = ((int)((kPromotion.getDomainModifierPercent(iI) + getExtraDomainModifier((DomainTypes)iI)) * 100.0f));
- iTemp = kPromotion.getDomainModifierPercent(iI);
- if (eUnitAI == UNITAI_COUNTER)
- {
- iValue += (iTemp * 1);
- }
- else if ((eUnitAI == UNITAI_ATTACK) ||
- (eUnitAI == UNITAI_RESERVE))
- {
- iValue += (iTemp / 2);
- }
- else
- {
- iValue += (iTemp / 8);
- }
- }
- //FfH: Added by Kael 07/30/2007
- iTemp = kPromotion.getDefensiveStrikeChance() + kPromotion.getDefensiveStrikeDamage();
- iTemp /= 2;
- if ((eUnitAI == UNITAI_CITY_DEFENSE) ||
- (eUnitAI == UNITAI_CITY_COUNTER) ||
- (eUnitAI == UNITAI_COUNTER))
- {
- iTemp *= 2;
- }
- iValue += iTemp;
-
- // Tholal AI - mage promotion: loop through spells, check that they require ePromotion, add value for spell, check various arcane leader and civ Traits
- if (isChanneler())
- {
- // traits - HARDCODE
- bool bSundered = kPlayer.hasTrait((TraitTypes)GC.getInfoTypeForString("TRAIT_SUNDERED"));
- bool bArcane = kPlayer.hasTrait((TraitTypes)GC.getInfoTypeForString("TRAIT_ARCANE"));
- int iSummonDurationBonus = kPlayer.getSummonDuration();
-
- /* - all sorts of traits give free promos - need way to properly sort out ones that are useful to mages
- int iNumMageTraits = 0;
- for (int iJ = 0; iJ < GC.getNumTraitInfos(); iJ++)
- {
- if (GC.getTraitInfo((TraitTypes)iJ).isFreePromotionUnitCombat(GC.getDefineINT("UNITCOMBAT_ADEPT")))
- {
- if (kPlayer.hasTrait((TraitTypes)iJ))
- {
- iNumMageTraits++;
- }
- }
- }
- */
- // summoners like promotions that give bonuses to their summons
- if (kPromotion.getPromotionSummonPerk() != NO_PROMOTION)
- {
- if (isSummoner())
- {
- iValue += 35;
-
- // mobility is especially valuable
- if (GC.getPromotionInfo((PromotionTypes)kPromotion.getPromotionSummonPerk()).getMovesChange() > 0)
- {
- iValue += 35;
- }
- }
- }
- for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
- {
- CvSpellInfo &kSpellInfo = GC.getSpellInfo((SpellTypes)iSpell);
- if (kSpellInfo.getPromotionPrereq1() != NO_PROMOTION)
- {
- if (kSpellInfo.getPromotionPrereq1() == ePromotion)
- {
- iValue += GC.getGameINLINE().getSorenRandNum(10, "AI Spell Promote") + kPlayer.AI_getMojoFactor(); // added this to try and get a better distribution of spells
- if (!isDirectDamageCaster()) // if we dont already have a damage spell
- {
- iValue += kSpellInfo.getDamage() * kSpellInfo.getRange();
- iValue += kSpellInfo.getDamageLimit() / 5;
- }
- if (kSpellInfo.getCreateUnitType() != NO_UNIT)
- {
- int iTempValue = (GC.getUnitInfo((UnitTypes)kSpellInfo.getCreateUnitType()).getCombat());
- CvUnitInfo &kCreateUnitInfo = GC.getUnitInfo((UnitTypes)kSpellInfo.getCreateUnitType());
-
- if (kCreateUnitInfo.getNumSeeInvisibleTypes() > 0)
- {
- iTempValue += 2;
- }
- if (kCreateUnitInfo.getBombardRate() > 0)
- {
- iTempValue += 2;
- }
- for (int iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
- {
- iTempValue += (kCreateUnitInfo.getDamageTypeCombat(iI) * 2);
- }
- iTempValue += kCreateUnitInfo.getTier();
- // account for Bonus Affinities
- for (int iBonuses = 0; iBonuses < GC.getNumBonusInfos(); iBonuses++)
- {
- if (kCreateUnitInfo.getBonusAffinity((BonusTypes)iBonuses) != 0)
- {
- iTempValue += kPlayer.countOwnedBonuses((BonusTypes)iBonuses);
- }
- }
- int iModValue = 0; //iNumMageTraits;
- if (bSundered || bArcane)
- {
- iModValue += 1;
- }
- if (!kSpellInfo.isPermanentUnitCreate())
- {
- iModValue += iSummonDurationBonus;
- }
- // heroes make powerful summoners
- if (eUnitAI == UNITAI_HERO || !isSummoner())
- {
- iModValue += 2;
- }
- iValue += (iTempValue * (4 + iModValue));
- }
- if (kSpellInfo.getAddPromotionType1() != NO_PROMOTION)
- {
- if (AI_getGroupflag()==GROUPFLAG_CONQUEST)// && !isBuffer())
- {
- iValue += 25;
- if (GC.getPromotionInfo((PromotionTypes)kSpellInfo.getAddPromotionType1()).getAIWeight() < 0) // its a negative effect spell
- {
- iValue += kSpellInfo.getRange() * 50;
- }
- }
- else
- {
- iValue += 15;
- }
- // extra value for haste if we can use enemy roads
- // ToDo - use this format to pull other tidbits about the promotion
- if (GC.getPromotionInfo((PromotionTypes)kSpellInfo.getAddPromotionType1()).getMovesChange() > 0)
- {
- if (isEnemyRoute())
- {
- iValue += 15;
- }
- }
- }
- /* - promotiontype2 is only used to add fatigued to centaurs; promotiontype3 isnt used at all
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
- {
- if (AI_getGroupflag()==GROUPFLAG_CONQUEST && !isBuffer())
- {
- iValue += 25;
- }
- else
- {
- iValue += 15;
- }
- }
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
- {
- if (AI_getGroupflag()==GROUPFLAG_CONQUEST && !isBuffer())
- {
- iValue += 25;
- }
- else
- {
- iValue += 15;
- }
- }
- */
- if (kSpellInfo.getRemovePromotionType1() != NO_PROMOTION)
- {
- if (kSpellInfo.isResistable())
- {
- if (AI_getGroupflag()==GROUPFLAG_CONQUEST || eUnitAI == UNITAI_MAGE)
- {
- iValue += 25;
- }
- }
- else // if its not resistable, that means its a spell you cast on your own troops
- {
- if (isBuffer() || AI_getGroupflag() == GROUPFLAG_PERMDEFENSE)
- {
- iValue += 25;
- }
- else
- {
- iValue += 15;
- }
- }
- }
- if (kSpellInfo.getRemovePromotionType2() != NO_PROMOTION)
- {
- if (kSpellInfo.isResistable())
- {
- if (AI_getGroupflag()==GROUPFLAG_CONQUEST || eUnitAI == UNITAI_MAGE)
- {
- iValue += 25;
- }
- }
- else // if its not resistable, that means its a spell you cast on your own troops
- {
- if (isBuffer() || AI_getGroupflag() == GROUPFLAG_PERMDEFENSE)
- {
- iValue += 25;
- }
- else
- {
- iValue += 15;
- }
- }
- }
- if (kSpellInfo.getRemovePromotionType3() != NO_PROMOTION)
- {
- if (kSpellInfo.isResistable())
- {
- if (AI_getGroupflag()==GROUPFLAG_CONQUEST || eUnitAI == UNITAI_MAGE)
- {
- iValue += 25;
- }
- }
- else // if its not resistable, that means its a spell you cast on your own troops
- {
- if (isBuffer() || AI_getGroupflag() == GROUPFLAG_PERMDEFENSE)
- {
- iValue += 25;
- }
- else
- {
- iValue += 15;
- }
- }
- }
- if (kSpellInfo.getCreateBuildingType() != NO_BUILDING)
- {
- if (eUnitAI == UNITAI_MAGE || AI_getGroupflag() == GROUPFLAG_PERMDEFENSE)
- {
- iValue += 50;
- }
- }
- // Bloom - not currently used for any selectable spell promotions in base FFH
- if (kSpellInfo.getCreateFeatureType() != NO_FEATURE)
- {
- if (plot()->getOwner() == getOwner())
- {
- if (eUnitAI == UNITAI_TERRAFORMER)
- {
- iValue += 35;
- }
- else
- {
- iValue += 10;
- }
- }
- }
- // Blaze
- if (kSpellInfo.getCreateImprovementType() != NO_IMPROVEMENT)
- {
- if (AI_getGroupflag()==GROUPFLAG_CONQUEST || eUnitAI == UNITAI_TERRAFORMER)
- {
- iValue += 35;
- }
- else
- {
- iValue += 10;
- }
- }
- if (kSpellInfo.isDispel())
- {
- iValue += 25;
- }
- if (kSpellInfo.isPush())
- {
- iValue += 20;
- }
- if (kSpellInfo.getImmobileTurns() != 0)
- {
- iValue += 30 * kSpellInfo.getImmobileTurns();
- }
- if (kSpellInfo.isAllowAutomateTerrain())
- {
- if (eUnitAI == UNITAI_TERRAFORMER)
- {
- iValue += 50;
- }
- else
- {
- iValue += 10;
- }
- }
- if (kSpellInfo.isResistable())
- {
- if (eUnitAI != UNITAI_WARWIZARD && eUnitAI != UNITAI_HERO)
- {
- iValue /= 2;
- }
- }
- }
- }
- }
- iValue += ((kPromotion.getAIWeight() / 10) * (getChannelingLevel() + 1));
- }
- // End Tholal AI
- //FfH: End Add
- if (iValue > 0)
- {
- iValue += GC.getGameINLINE().getSorenRandNum(15, "AI Promote");
- }
- return iValue;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_shadow(UnitAITypes eUnitAI, int iMax, int iMaxRatio, bool bWithCargoOnly, bool bOutsideCityOnly, int iMaxPath)
- {
- PROFILE_FUNC();
- CvUnit* pLoopUnit;
- CvUnit* pBestUnit;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- iBestValue = 0;
- pBestUnit = NULL;
- for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
- {
- if (pLoopUnit != this)
- {
- if (AI_plotValid(pLoopUnit->plot()))
- {
- if (pLoopUnit->isGroupHead())
- {
- if (!(pLoopUnit->isCargo()))
- {
- if (pLoopUnit->AI_getUnitAIType() == eUnitAI)
- {
- if ((pLoopUnit->getGroup()->baseMoves() <= getGroup()->baseMoves()) || (eUnitAI == UNITAI_SETTLE))
- {
- if (!bWithCargoOnly || pLoopUnit->getGroup()->hasCargo())
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 12/08/08 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- if( bOutsideCityOnly && pLoopUnit->plot()->isCity() )
- {
- continue;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- int iShadowerCount = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, MISSIONAI_SHADOW, getGroup());
- if (((-1 == iMax) || (iShadowerCount < iMax)) &&
- ((-1 == iMaxRatio) || (iShadowerCount == 0) || (((100 * iShadowerCount) / std::max(1, pLoopUnit->getGroup()->countNumUnitAIType(eUnitAI))) <= iMaxRatio)))
- {
- if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
- {
- if (generatePath(pLoopUnit->plot(), 0, true, &iPathTurns))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 12/08/08 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- /* original bts code
- //if (iPathTurns <= iMaxPath) XXX
- */
- if (iPathTurns <= iMaxPath)
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- iValue = 1 + pLoopUnit->getGroup()->getCargo();
- iValue *= 1000;
- iValue /= 1 + iPathTurns;
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopUnit;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestUnit != NULL)
- {
- if (atPlot(pBestUnit->plot()))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_SHADOW, NULL, pBestUnit);
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_SHADOW, NULL, pBestUnit);
- return true;
- }
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- // Added new options to aid transport grouping
- // Returns true if a group was joined or a mission was pushed...
- 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)
- {
- PROFILE_FUNC();
- CvUnit* pLoopUnit;
- CvUnit* pBestUnit;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- // if we are on a transport, then do not regroup
- if (isCargo())
- {
- return false;
- }
- if (!bAllowRegrouping)
- {
- if (getGroup()->getNumUnits() > 1)
- {
- return false;
- }
- }
- if ((getDomainType() == DOMAIN_LAND) && !canMoveAllTerrain())
- {
- if (area()->getNumAIUnits(getOwnerINLINE(), eUnitAI) == 0)
- {
- return false;
- }
- }
- if (!AI_canGroupWithAIType(eUnitAI))
- {
- return false;
- }
- // lfgr fix: copied this check from AI_counterMove(), else it is possible that a group is created and then splitted indefinitely
- // "Should never have group lead by counter unit"
- if( getGroup()->getHeadUnitAI() == UNITAI_COUNTER && getGroup()->getNumUnits() == 1 )
- {
- if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
- {
- return false;
- }
- }
- // lfgr fix end
- int iOurImpassableCount = 0;
- CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pImpassUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- iOurImpassableCount = std::max(iOurImpassableCount, GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(pImpassUnit->getUnitType()));
- }
- iBestValue = MAX_INT;
- pBestUnit = NULL;
- // Loop over groups, ai_allowgroup blocks non-head units anyway
- CvSelectionGroup* pLoopGroup = NULL;
- for(pLoopGroup = GET_PLAYER(getOwnerINLINE()).firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = GET_PLAYER(getOwnerINLINE()).nextSelectionGroup(&iLoop))
- {
- pLoopUnit = pLoopGroup->getHeadUnit();
- if( pLoopUnit == NULL )
- {
- continue;
- }
- CvPlot* pPlot = pLoopUnit->plot();
- if (pLoopUnit->AI_getUnitAIType() == eUnitAI)
- {
- if (AI_plotValid(pPlot))
- {
- if (iMaxPath > 0 || pPlot == plot())
- {
- if (!isEnemy(pPlot->getTeam()))
- {
- if (AI_allowGroup(pLoopUnit, eUnitAI))
- {
- if ((iMaxGroup == -1) || ((pLoopGroup->getNumUnits() + GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, MISSIONAI_GROUP, getGroup())) <= (iMaxGroup + ((bStackOfDoom) ? AI_stackOfDoomExtra() : 0))))
- {
- if ((iMaxOwnUnitAI == -1) || (pLoopGroup->countNumUnitAIType(AI_getUnitAIType()) <= (iMaxOwnUnitAI + ((bStackOfDoom) ? AI_stackOfDoomExtra() : 0))))
- {
- if ((iMinUnitAI == -1) || (pLoopGroup->countNumUnitAIType(eUnitAI) >= iMinUnitAI))
- {
- if (!bIgnoreFaster || (pLoopGroup->baseMoves() <= baseMoves()))
- {
- if (!bIgnoreOwnUnitType || (pLoopUnit->getUnitType() != getUnitType()))
- {
- if (!bWithCargoOnly || pLoopUnit->getGroup()->hasCargo())
- {
- if( !bInCityOnly || pLoopUnit->plot()->isCity() )
- {
- if( (eIgnoreMissionAIType == NO_MISSIONAI) || (eIgnoreMissionAIType != pLoopUnit->getGroup()->AI_getMissionAIType()) )
- {
- if (!(pPlot->isVisibleEnemyUnit(this)))
- {
- if( iOurImpassableCount > 0 || AI_getUnitAIType() == UNITAI_ASSAULT_SEA )
- {
- int iTheirImpassableCount = 0;
- pUnitNode = pLoopGroup->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pImpassUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopGroup->nextUnitNode(pUnitNode);
- iTheirImpassableCount = std::max(iTheirImpassableCount, GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(pImpassUnit->getUnitType()));
- }
- if( iOurImpassableCount != iTheirImpassableCount )
- {
- continue;
- }
- }
- if (generatePath(pPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= iMaxPath)
- {
- iValue = 1000 / (iPathTurns + 1);
- iValue *= 4 + pLoopGroup->getCargo();
- iValue /= pLoopGroup->getNumUnits();
- if (iValue < iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopUnit;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- if (pBestUnit != NULL)
- {
- if (atPlot(pBestUnit->plot()))
- {
- joinGroup(pBestUnit->getGroup());
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
- return true;
- }
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- bool CvUnitAI::AI_groupMergeRange(UnitAITypes eUnitAI, int iMaxRange, bool bBiggerOnly, bool bAllowRegrouping, bool bIgnoreFaster)
- {
- PROFILE_FUNC();
- // if we are on a transport, then do not regroup
- if (isCargo())
- {
- return false;
- }
- if (!bAllowRegrouping)
- {
- if (getGroup()->getNumUnits() > 1)
- {
- return false;
- }
- }
- if ((getDomainType() == DOMAIN_LAND) && !canMoveAllTerrain())
- {
- if (area()->getNumAIUnits(getOwnerINLINE(), eUnitAI) == 0)
- {
- return false;
- }
- }
- if (!AI_canGroupWithAIType(eUnitAI))
- {
- return false;
- }
- // cached values
- CvPlot* pPlot = plot();
- CvSelectionGroup* pGroup = getGroup();
- // best match
- CvUnit* pBestUnit = NULL;
- int iBestValue = MAX_INT;
- // iterate over plots at each range
- for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
- {
- for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
- {
- CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL && pLoopPlot->getArea() == pPlot->getArea())
- {
- CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
- CvSelectionGroup* pLoopGroup = pLoopUnit->getGroup();
- if (pLoopUnit->AI_getUnitAIType() == eUnitAI)
- {
- if (AI_allowGroup(pLoopUnit, eUnitAI))
- {
- if (!bIgnoreFaster || (pLoopUnit->getGroup()->baseMoves() <= baseMoves()))
- {
- if (!bBiggerOnly || (pLoopGroup->getNumUnits() >= pGroup->getNumUnits()))
- {
- /*************************************************************************************************/
- /** SPEED TWEAK Sephi **/
- /** We don't have to check for a path to distant shores if we want to move only short distance **/
- /** anyway, so approx maximum distance for a possible path by iMaxPath **/
- /*************************************************************************************************/
- // int iPathTurns;
- // if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- // {
- // if (iPathTurns <= (iMaxRange + 2))
- // {
- // int iValue = 1000 * (iPathTurns + 1);
- // iValue /= pLoopGroup->getNumUnits();
- // if (iValue < iBestValue)
- // {
- // iBestValue = iValue;
- // pBestUnit = pLoopUnit;
- // }
- // }
- // }
- int XDist=pLoopPlot->getX_INLINE() - plot()->getX_INLINE();
- int YDist=pLoopPlot->getY_INLINE() - plot()->getY_INLINE();
- if (((XDist*XDist)+(YDist*YDist))<(iMaxRange + 2)*(iMaxRange + 2)*4)
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= (iMaxRange + 2))
- {
- int iValue = 1000 * (iPathTurns + 1);
- iValue /= pLoopGroup->getNumUnits();
- if (iValue < iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopUnit;
- }
- }
- }
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestUnit != NULL)
- {
- if (atPlot(pBestUnit->plot()))
- {
- pGroup->mergeIntoGroup(pBestUnit->getGroup());
- return true;
- }
- else
- {
- if (getGroup()->getNumUnits() > 1)
- {
- pGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
- return true;
- }
- else
- {
- pGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
- return true;
- }
- }
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/18/10 jdog5000 */
- /* */
- /* War tactics AI, Unit AI */
- /************************************************************************************************/
- // Returns true if we loaded onto a transport or a mission was pushed...
- bool CvUnitAI::AI_load(UnitAITypes eUnitAI, MissionAITypes eMissionAI, UnitAITypes eTransportedUnitAI, int iMinCargo, int iMinCargoSpace, int iMaxCargoSpace, int iMaxCargoOurUnitAI, int iFlags, int iMaxPath, int iMaxTransportPath)
- {
- PROFILE_FUNC();
- CvUnit* pLoopUnit;
- CvUnit* pBestUnit;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- if (getCargo() > 0)
- {
- return false;
- }
- if (isCargo())
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
-
- if ((getDomainType() == DOMAIN_LAND) && !canMoveAllTerrain())
- {
- if (area()->getNumAIUnits(getOwnerINLINE(), eUnitAI) == 0)
- {
- return false;
- }
- }
- iBestValue = MAX_INT;
- pBestUnit = NULL;
-
- const int iLoadMissionAICount = 4;
- MissionAITypes aeLoadMissionAI[iLoadMissionAICount] = {MISSIONAI_LOAD_ASSAULT, MISSIONAI_LOAD_SETTLER, MISSIONAI_LOAD_SPECIAL, MISSIONAI_ATTACK_SPY};
- int iCurrentGroupSize = getGroup()->getNumUnits();
- for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
- {
- if (pLoopUnit != this)
- {
- if (AI_plotValid(pLoopUnit->plot()))
- {
- if (canLoadUnit(pLoopUnit, pLoopUnit->plot()))
- {
- // special case ASSAULT_SEA UnitAI, so that, if a unit is marked escort, but can load units, it will load them
- // transport units might have been built as escort, this most commonly happens with galleons
- UnitAITypes eLoopUnitAI = pLoopUnit->AI_getUnitAIType();
- if (eLoopUnitAI == eUnitAI)// || (eUnitAI == UNITAI_ASSAULT_SEA && eLoopUnitAI == UNITAI_ESCORT_SEA))
- {
- int iCargoSpaceAvailable = pLoopUnit->cargoSpaceAvailable(getSpecialUnitType(), getDomainType());
- iCargoSpaceAvailable -= GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, aeLoadMissionAI, iLoadMissionAICount, getGroup());
- if (iCargoSpaceAvailable > 0)
- {
- if ((eTransportedUnitAI == NO_UNITAI) || (pLoopUnit->getUnitAICargo(eTransportedUnitAI) > 0))
- {
- if ((iMinCargo == -1) || (pLoopUnit->getCargo() >= iMinCargo))
- {
- // Use existing count of cargo space available
- if ((iMinCargoSpace == -1) || (iCargoSpaceAvailable >= iMinCargoSpace))
- {
- if ((iMaxCargoSpace == -1) || (iCargoSpaceAvailable <= iMaxCargoSpace))
- {
- if ((iMaxCargoOurUnitAI == -1) || (pLoopUnit->getUnitAICargo(AI_getUnitAIType()) <= iMaxCargoOurUnitAI))
- {
- // Don't block city defense from getting on board
- if (true)
- {
- if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
- {
- CvPlot* pUnitTargetPlot = pLoopUnit->getGroup()->AI_getMissionAIPlot();
- if ((pUnitTargetPlot == NULL) || (pUnitTargetPlot->getTeam() == getTeam()) || (!pUnitTargetPlot->isOwned() || !isPotentialEnemy(pUnitTargetPlot->getTeam(), pUnitTargetPlot)))
- {
- /*************************************************************************************************/
- /** SPEED TWEAK Sephi **/
- /** We don't have to check for a path to distant shores if we want to move only short distance **/
- /** anyway, so approx maximum distance for a possible path by iMaxPath **/
- /*************************************************************************************************/
- // if (generatePath(pLoopUnit->plot(), iFlags, true, &iPathTurns))
- // {
- // if (iPathTurns <= iMaxPath)
- // {
- // // prefer a transport that can hold as much of our group as possible
- // iValue = (std::max(0, iCurrentGroupSize - iCargoSpaceAvailable) * 5) + iPathTurns;
- // if (iValue < iBestValue)
- // {
- // iBestValue = iValue;
- // pBestUnit = pLoopUnit;
- // }
- // }
- // }
- int XDist=pLoopUnit->plot()->getX_INLINE() - plot()->getX_INLINE();
- int YDist=pLoopUnit->plot()->getY_INLINE() - plot()->getY_INLINE();
- if (((XDist*XDist)+(YDist*YDist))<iMaxPath*iMaxPath*4)
- {
- if (generatePath(pLoopUnit->plot(), iFlags, true, &iPathTurns))
- {
- if (iPathTurns <= iMaxPath || (iMaxPath == 0 && plot() == pLoopUnit->plot()))
- {
- // prefer a transport that can hold as much of our group as possible
- iValue = (std::max(0, iCurrentGroupSize - iCargoSpaceAvailable) * 5) + iPathTurns;
- if (iValue < iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopUnit;
- }
- }
- }
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if( pBestUnit != NULL && iMaxTransportPath < MAX_INT )
- {
- // Can transport reach enemy in requested time
- bool bFoundEnemyPlotInRange = false;
- int iPathTurns;
- int iRange = iMaxTransportPath * pBestUnit->baseMoves();
- CvPlot* pAdjacentPlot = NULL;
- for( int iDX = -iRange; (iDX <= iRange && !bFoundEnemyPlotInRange); iDX++ )
- {
- for( int iDY = -iRange; (iDY <= iRange && !bFoundEnemyPlotInRange); iDY++ )
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if( pLoopPlot != NULL )
- {
- if( pLoopPlot->isCoastalLand() )
- {
- if( pLoopPlot->isOwned() )
- {
- if( isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot) && !isBarbarian() )
- {
- if( pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE()) > 0 )
- {
- // Transport cannot enter land plot without cargo, so generate path only works properly if
- // land units are already loaded
-
- for( int iI = 0; (iI < NUM_DIRECTION_TYPES && !bFoundEnemyPlotInRange); iI++ )
- {
- pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), (DirectionTypes)iI);
- if (pAdjacentPlot != NULL)
- {
- if( pAdjacentPlot->isWater() )
- {
- if( pBestUnit->generatePath(pAdjacentPlot, 0, true, &iPathTurns) )
- {
- if (pBestUnit->getPathLastNode()->m_iData1 == 0)
- {
- iPathTurns++;
- }
- if( iPathTurns <= iMaxTransportPath )
- {
- bFoundEnemyPlotInRange = true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if( !bFoundEnemyPlotInRange )
- {
- pBestUnit = NULL;
- }
- }
- if (pBestUnit != NULL)
- {
- if (atPlot(pBestUnit->plot()))
- {
- CvSelectionGroup* pOtherGroup = NULL;
- getGroup()->setTransportUnit(pBestUnit, &pOtherGroup); // XXX is this dangerous (not pushing a mission...) XXX air units?
- // If part of large group loaded, then try to keep loading the rest
- if( eUnitAI == UNITAI_ASSAULT_SEA && eMissionAI == MISSIONAI_LOAD_ASSAULT )
- {
- if( pOtherGroup != NULL && pOtherGroup->getNumUnits() > 0 )
- {
- if( pOtherGroup->getHeadUnitAI() == AI_getUnitAIType() )
- {
- pOtherGroup->getHeadUnit()->AI_load( eUnitAI, eMissionAI, eTransportedUnitAI, iMinCargo, iMinCargoSpace, iMaxCargoSpace, iMaxCargoOurUnitAI, iFlags, 0, iMaxTransportPath );
- }
- else if( eTransportedUnitAI == NO_UNITAI && iMinCargo < 0 && iMinCargoSpace < 0 && iMaxCargoSpace < 0 && iMaxCargoOurUnitAI < 0 )
- {
- pOtherGroup->getHeadUnit()->AI_load( eUnitAI, eMissionAI, NO_UNITAI, -1, -1, -1, -1, iFlags, 0, iMaxTransportPath );
- }
- }
- }
- return true;
- }
- else
- {
- // BBAI TODO: To split or not to split?
- int iCargoSpaceAvailable = pBestUnit->cargoSpaceAvailable(getSpecialUnitType(), getDomainType());
- FAssertMsg(iCargoSpaceAvailable > 0, "best unit has no space");
- // split our group to fit on the transport
- CvSelectionGroup* pOtherGroup = NULL;
- CvSelectionGroup* pSplitGroup = getGroup()->splitGroup(iCargoSpaceAvailable, this, &pOtherGroup);
- FAssertMsg(pSplitGroup != NULL, "splitGroup failed");
- FAssertMsg(m_iGroupID == pSplitGroup->getID(), "splitGroup failed to put unit in the new group");
- if (pSplitGroup != NULL)
- {
- CvPlot* pOldPlot = pSplitGroup->plot();
- pSplitGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), iFlags, false, false, eMissionAI, NULL, pBestUnit);
- bool bMoved = (pSplitGroup->plot() != pOldPlot);
- if (!bMoved && pOtherGroup != NULL)
- {
- joinGroup(pOtherGroup);
- }
- return bMoved;
- }
- }
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_guardCityBestDefender()
- {
- CvCity* pCity;
- CvPlot* pPlot;
- pPlot = plot();
- pCity = pPlot->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- if (pPlot->getBestDefender(getOwnerINLINE()) == this)
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
- return true;
- }
- }
- }
- return false;
- }
- bool CvUnitAI::AI_guardCityMinDefender(bool bSearch)
- {
- PROFILE_FUNC();
- CvCity* pPlotCity = plot()->getPlotCity();
- if ((pPlotCity != NULL) && (pPlotCity->getOwnerINLINE() == getOwnerINLINE()))
- {
- int iCityDefenderCount;
- // lfgr AI 06/2020: Non-city-defender units now may also call this. If they do, they count every unit.
- // City defenders still only count their own.
- if( AI_getUnitAIType() == UNITAI_CITY_DEFENSE ) {
- iCityDefenderCount = pPlotCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE());
- }
- else {
- iCityDefenderCount = pPlotCity->plot()->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE());
- }
- if ((iCityDefenderCount - 1) < pPlotCity->AI_minDefenders()) // LFGR_TODO: Use -stacksize instead of -1?
- {
- if ((iCityDefenderCount <= 2) || (GC.getGame().getSorenRandNum(5, "AI shuffle defender") != 0)) // LFGR_TODO: make "AI shuffle defender" optional?
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
- return true;
- }
- }
- }
- if (bSearch)
- {
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestGuardPlot = NULL;
- CvCity* pLoopCity;
- int iLoop;
- int iCurrentTurn = GC.getGame().getGameTurn();
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check area for land units
- if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
- {
- continue;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- int iDefendersHave = pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE());
- int iDefendersNeed = pLoopCity->AI_minDefenders();
- if (iDefendersHave < iDefendersNeed)
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- iDefendersHave += GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GUARD_CITY, getGroup());
- if (iDefendersHave < iDefendersNeed + 1)
- {
- /*************************************************************************************************/
- /** SPEED TWEAK Sephi **/
- /** We don't have to check for a path to distant shores if we want to move only short distance **/
- /** anyway, so approx maximum distance for a possible path by iMaxPath **/
- /*************************************************************************************************/
- // int iPathTurns;
- // if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- // {
- // if (iPathTurns <= 10)
- // {
- // int iValue = (iDefendersNeed - iDefendersHave) * 20;
- // iValue += 2 * std::min(15, iCurrentTurn - pLoopCity->getGameTurnAcquired());
- // if (pLoopCity->isOccupation())
- // {
- // iValue += 5;
- // }
- // iValue -= iPathTurns;
- // if (iValue > iBestValue)
- // {
- // iBestValue = iValue;
- // pBestPlot = getPathEndTurnPlot();
- // pBestGuardPlot = pLoopCity->plot();
- // }
- // }
- // }
- int XDist=pLoopCity->plot()->getX_INLINE() - plot()->getX_INLINE();
- int YDist=pLoopCity->plot()->getY_INLINE() - plot()->getY_INLINE();
- if (((XDist*XDist)+(YDist*YDist))<200)
- {
- int iPathTurns;
- if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- if (iPathTurns <= 10)
- {
- int iValue = (iDefendersNeed - iDefendersHave) * 20;
- iValue += 2 * std::min(15, iCurrentTurn - pLoopCity->getGameTurnAcquired());
- if (pLoopCity->isOccupation())
- {
- iValue += 5;
- }
- iValue -= iPathTurns;
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestGuardPlot = pLoopCity->plot();
- }
- }
- }
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestGuardPlot))
- {
- FAssert(pBestGuardPlot == pBestPlot);
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
- return true;
- }
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_guardCity(bool bLeave, bool bSearch, int iMaxPath)
- {
- PROFILE_FUNC();
- CLLNode<IDInfo>* pUnitNode;
- CvCity* pCity;
- CvCity* pLoopCity;
- CvUnit* pLoopUnit;
- CvPlot* pPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestGuardPlot;
- bool bDefend;
- int iExtra;
- int iCount;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- FAssert(getDomainType() == DOMAIN_LAND);
- //FAssert(getGroup()->canDefend());
- if (!getGroup()->canDefend())
- {
- return false;
- }
- pPlot = plot();
- pCity = pPlot->getPlotCity();
- int pCities = GET_PLAYER(getOwnerINLINE()).getNumCities();
- if (pCities > 1)
- {
- if ((getGroup()->getNumUnits() > (pCities * 5)) && (GET_TEAM(getTeam()).getAtWarCount(true) > 0))
- {
- return false;
- }
- }
- if ((pCity != NULL) && (pCity->getOwnerINLINE() == getOwnerINLINE())) // XXX check for other team?
- {
- if (bLeave && !(pCity->AI_isDanger()))
- {
- iExtra = 1;
- }
- else
- {
- iExtra = (bSearch ? 0 : -GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pPlot, 2));
- }
- bDefend = false;
- if (pPlot->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE()) == 1) // XXX check for other team's units?
- {
- bDefend = true;
- }
- else if (!(pCity->AI_isDefended(((AI_isCityAIType()) ? -1 : 0) + iExtra))) // XXX check for other team's units?
- {
- if (AI_isCityAIType())
- {
- bDefend = true;
- }
- else
- {
- iCount = 0;
- pUnitNode = pPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pPlot->nextUnitNode(pUnitNode);
- if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
- {
- if (pLoopUnit->isGroupHead())
- {
- if (!(pLoopUnit->isCargo()))
- {
- if (pLoopUnit->canDefend())
- {
- if (!(pLoopUnit->AI_isCityAIType()))
- {
- if (!(pLoopUnit->isHurt()))
- {
- if (pLoopUnit->isWaiting())
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 05/24/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- //FAssert(pLoopUnit != this);
- if( pLoopUnit != this )
- {
- iCount++;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- }
- }
- else
- {
- if (pLoopUnit->getGroup()->getMissionType(0) != MISSION_SKIP)
- {
- iCount++;
- }
- }
- }
- }
- }
- }
- }
- if (!(pCity->AI_isDefended(iCount + iExtra))) // XXX check for other team's units?
- {
- bDefend = true;
- }
- }
- }
- if (bDefend)
- {
- CvSelectionGroup* pOldGroup = getGroup();
- CvUnit* pEjectedUnit = getGroup()->AI_ejectBestDefender(pPlot);
- if (pEjectedUnit != NULL)
- {
- if (pPlot->plotCount(PUF_isCityAIType, -1, -1, getOwnerINLINE()) == 0)
- {
- //if (pEjectedUnit->cityDefenseModifier() > 0)
- //if (pEjectedUnit->isUnitAllowedPermDefense())
- {
- logBBAI(" ...setting %S (%d) to city defense from ai_guardcity function", pEjectedUnit->getNameKey(), pEjectedUnit->getID());
- pEjectedUnit->AI_setUnitAIType(UNITAI_CITY_DEFENSE);
- }
- }
- pEjectedUnit->getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
- if (pEjectedUnit->getGroup() == pOldGroup || pEjectedUnit == this)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- //This unit is not suited for defense, skip the mission
- //to protect this city but encourage others to defend instead.
- getGroup()->pushMission(MISSION_SKIP);
- if (!isHurt())
- {
- finishMoves();
- }
- }
- return true;
- }
- }
- if (bSearch)
- {
- iBestValue = MAX_INT;
- pBestPlot = NULL;
- pBestGuardPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check area for land units
- if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
- {
- continue;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- 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?
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if ((GC.getGame().getGameTurn() - pLoopCity->getGameTurnAcquired() < 10) || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GUARD_CITY, getGroup()) < 2)
- {
- /*************************************************************************************************/
- /** SPEED TWEAK Sephi **/
- /** We don't have to check for a path to distant shores if we want to move only short distance **/
- /** anyway, so approx maximum distance for a possible path by iMaxPath **/
- /*************************************************************************************************/
- // if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- // {
- // if (iPathTurns <= iMaxPath)
- // {
- // iValue = iPathTurns;
- // if (iValue < iBestValue)
- // {
- // iBestValue = iValue;
- // pBestPlot = getPathEndTurnPlot();
- // pBestGuardPlot = pLoopCity->plot();
- // FAssert(!atPlot(pBestPlot));
- // }
- // }
- // }
- int XDist=pLoopCity->plot()->getX_INLINE() - plot()->getX_INLINE();
- int YDist=pLoopCity->plot()->getY_INLINE() - plot()->getY_INLINE();
- if (((XDist*XDist)+(YDist*YDist))<iMaxPath*iMaxPath*4)
- {
- if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- if (iPathTurns <= iMaxPath)
- {
- iValue = iPathTurns;
- if (iValue < iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestGuardPlot = pLoopCity->plot();
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- }
- }
- }
- if (pBestPlot != NULL)
- {
- break;
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
- {
- FAssert(!atPlot(pBestPlot));
- // split up group if we are going to defend, so rest of group has opportunity to do something else
- // if (getGroup()->getNumUnits() > 1)
- // {
- // getGroup()->AI_separate(); // will change group
- // }
- //
- // getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
- // return true;
- CvSelectionGroup* pOldGroup = getGroup();
- CvUnit* pEjectedUnit = getGroup()->AI_ejectBestDefender(pPlot);
- if (pEjectedUnit != NULL)
- {
- pEjectedUnit->getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL);
- if (pEjectedUnit->getGroup() == pOldGroup || pEjectedUnit == this)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- //This unit is not suited for defense, skip the mission
- //to protect this city but encourage others to defend instead.
- if (atPlot(pBestGuardPlot))
- {
- getGroup()->pushMission(MISSION_SKIP);
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL);
- }
- return true;
- }
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_guardCityAirlift()
- {
- PROFILE_FUNC();
- CvCity* pCity;
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- int iValue;
- int iBestValue;
- int iLoop;
- if (getGroup()->getNumUnits() > 1)
- {
- return false;
- }
- pCity = plot()->getPlotCity();
- if (pCity == NULL)
- {
- return false;
- }
- if (pCity->getMaxAirlift() == 0)
- {
- return false;
- }
- iBestValue = 0;
- pBestPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (pLoopCity != pCity)
- {
- if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
- {
- 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?
- {
- iValue = pLoopCity->getPopulation();
- if (pLoopCity->AI_isDanger())
- {
- iValue *= 2;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- FAssert(pLoopCity != pCity);
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_guardBonus(int iMinValue)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestGuardPlot;
- ImprovementTypes eImprovement;
- BonusTypes eNonObsoleteBonus;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iI;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestGuardPlot = NULL;
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
- {
- eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());
- //FfH: Modified by Kael 03/22/2008
- // if (eNonObsoleteBonus != NO_BONUS)
- // {
- // eImprovement = pLoopPlot->getImprovementType();
- //
- // if ((eImprovement != NO_IMPROVEMENT) && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
- // {
- // iValue = GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus);
- // iValue += std::max(0, 200 * GC.getBonusInfo(eNonObsoleteBonus).getAIObjective());
- //
- // if (pLoopPlot->getPlotGroupConnectedBonus(getOwnerINLINE(), eNonObsoleteBonus) == 1)
- // {
- // iValue *= 2;
- // }
- iValue = 0;
- eImprovement = pLoopPlot->getImprovementType();
- if (eImprovement != NO_IMPROVEMENT)
- {
- if (eNonObsoleteBonus != NO_BONUS && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
- {
- iValue += GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus);
- iValue += std::max(0, 200 * GC.getBonusInfo(eNonObsoleteBonus).getAIObjective());
- if (pLoopPlot->getPlotGroupConnectedBonus(getOwnerINLINE(), eNonObsoleteBonus) == 1)
- {
- iValue *= 2;
- }
- }
- iValue += GC.getImprovementInfo(eImprovement).getRangeDefenseModifier() * GC.getImprovementInfo(eImprovement).getRange() * 200;
- iValue += GC.getImprovementInfo(eImprovement).getHealRateChange() * 10;
- iValue += GC.getImprovementInfo(eImprovement).getDefenseModifier();
- //FfH: End Modify
- if (iValue > iMinValue)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- // BBAI TODO: Multiple defenders for higher value resources?
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_BONUS, getGroup()) == 0)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestGuardPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- //FfH: Modified by Kael 10/29/2007
- // }
- //FfH: End Modify
- if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
- {
- if (atPlot(pBestGuardPlot))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
- return true;
- }
- }
- return false;
- }
- int CvUnitAI::AI_getPlotDefendersNeeded(CvPlot* pPlot, int iExtra)
- {
- int iNeeded = iExtra;
- BonusTypes eNonObsoleteBonus = pPlot->getNonObsoleteBonusType(getTeam());
- // Super Forts begin *AI_defense*
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
-
- if (eNonObsoleteBonus != NO_BONUS)
- {
- if (kPlayer.AI_bonusVal(eNonObsoleteBonus, -1) > 10)
- {
- ++iNeeded;
- }
- }
- if (kPlayer.AI_getPlotDanger(pPlot) > 0)
- {
- ++iNeeded;
- if ((kPlayer.AI_getPlotCanalValue(pPlot) > 0)
- || (kPlayer.AI_getPlotChokeValue(pPlot) > 0)
- || (kPlayer.AI_getPlotAirbaseValue(pPlot) > 0))
- {
- ++iNeeded;
- }
- }
- // Super Forts end
- /* Original Code
- if (eNonObsoleteBonus != NO_BONUS)
- {
- iNeeded += (GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus) + 10) / 19;
- }
- int iDefense = pPlot->defenseModifier(getTeam(), true);
- iNeeded += (iDefense + 25) / 50;
- if (iNeeded == 0)
- {
- return 0;
- }
- iNeeded += GET_PLAYER(getOwnerINLINE()).AI_getPlotAirbaseValue(pPlot) / 50;
- int iNumHostiles = 0;
- int iNumPlots = 0;
- int iRange = 2;
- for (int iX = -iRange; iX <= iRange; iX++)
- {
- for (int iY = -iRange; iY <= iRange; iY++)
- {
- CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iX, iY);
- if (pLoopPlot != NULL)
- {
- iNumHostiles += pLoopPlot->getNumVisibleEnemyDefenders(this);
- if ((pLoopPlot->getTeam() != getTeam()) || pLoopPlot->isCoastalLand())
- {
- iNumPlots++;
- if (isEnemy(pLoopPlot->getTeam()))
- {
- iNumPlots += 4;
- }
- }
- }
- }
- }
- if ((iNumHostiles == 0) && (iNumPlots < 4))
- {
- if (iNeeded > 1)
- {
- iNeeded = 1;
- }
- else
- {
- iNeeded = 0;
- }
- } */
- return iNeeded;
- }
- bool CvUnitAI::AI_guardFort(bool bSearch)
- {
- PROFILE_FUNC();
- if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
- {
- return false;
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- ImprovementTypes eImprovement = plot()->getImprovementType();
- if (eImprovement != NO_IMPROVEMENT)
- {
- if (GC.getImprovementInfo(eImprovement).isActsAsCity())
- {
- // Super Forts begin *AI_defense* - just tweaked a number here (iExtra now 1 instead of 0)
- if (plot()->plotCount(PUF_isCityAIType, -1, -1, getOwnerINLINE()) <= AI_getPlotDefendersNeeded(plot(), 1))
- // Super Forts end
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, plot());
- return true;
- }
- }
- }
- }
- if (!bSearch)
- {
- return false;
- }
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestGuardPlot = NULL;
-
- // Tholal note: to be used in the future - try and keep defense units with city defense in cities, and hills defense in hills
- bool bUnitHillsDefense = false;
- bool bUnitCityDefense = false;
- for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot) && !atPlot(pLoopPlot))
- {
- if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
- {
- ImprovementTypes eImprovement = pLoopPlot->getImprovementType();
- if (eImprovement != NO_IMPROVEMENT)
- {
- if (GC.getImprovementInfo(eImprovement).isActsAsCity())
- {
- // Super Forts begin *AI_defense* - just tweaked a number here (iExtra now 1 instead of 0)
- int iValue = AI_getPlotDefendersNeeded(pLoopPlot, 1);
- // Super Forts end
- if (iValue > 0)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_BONUS, getGroup()) < iValue)
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue *= 1000;
- iValue /= (iPathTurns + 2);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestGuardPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
- {
- if (atPlot(pBestGuardPlot))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
- return true;
- }
- }
- return false;
- }
- // Super Forts begin *AI_defense* - this is designed to ensure each fort has one defender (or improvements that require a fortified unit to upgrade)
- bool CvUnitAI::AI_guardFortMinDefender(bool bSearch)
- {
- PROFILE_FUNC();
- // LFGR_TODO: Make sure the fort is not about to be conquered
-
- if(!GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS))
- {
- return false;
- }
- if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
- {
- return false;
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- ImprovementTypes eImprovement = plot()->getImprovementType();
- if (eImprovement != NO_IMPROVEMENT)
- {
- if (GC.getImprovementInfo(eImprovement).isActsAsCity() || GC.getImprovementInfo(eImprovement).isUpgradeRequiresFortify())
- {
- // lfgr fix 03/2021: Stop non-CityAIType units getting stranded, prefer CityAIType units
- if (plot()->plotCount(PUF_isPreferredDefenderAIType, AI_getUnitAIType(), -1, getOwnerINLINE()) <= 1)
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, plot());
- return true;
- }
- }
- }
- }
-
- if (!bSearch)
- {
- return false;
- }
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestGuardPlot = NULL;
- for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot) && !atPlot(pLoopPlot))
- {
- if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
- {
- ImprovementTypes eImprovement = pLoopPlot->getImprovementType();
- if (eImprovement != NO_IMPROVEMENT)
- {
- if (GC.getImprovementInfo(eImprovement).isActsAsCity() || GC.getImprovementInfo(eImprovement).isUpgradeRequiresFortify())
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- // lfgr fix 03/2021: Stop non-CityAIType units getting stranded, prefer CityAIType units
- if (pLoopPlot->plotCount(PUF_isPreferredDefenderAIType, AI_getUnitAIType(), -1, getOwnerINLINE()) == 0)
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_BONUS, getGroup()) == 0)
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- int iValue = 1000;
- iValue /= (iPathTurns + 2);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestGuardPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
- {
- if (atPlot(pBestGuardPlot))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
- return true;
- }
- }
- return false;
- }
- // Super Forts end
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_guardCitySite()
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestGuardPlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iI;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestGuardPlot = NULL;
- for (iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
- {
- pLoopPlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_CITY, getGroup()) == 0)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestGuardPlot = pLoopPlot;
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
- {
- if (atPlot(pBestGuardPlot))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_guardSpy(int iRandomPercent)
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- CvPlot* pBestGuardPlot;
- int iValue;
- int iBestValue;
- int iLoop;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestGuardPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check area for land units
- if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
- {
- continue;
- }
- iValue = 0;
- if( GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_SPACE4) )
- {
- if( pLoopCity->isCapital() )
- {
- iValue += 30;
- }
- else if( pLoopCity->isProductionProject() )
- {
- iValue += 5;
- }
- }
- if( GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE3) )
- {
- if( pLoopCity->getCultureLevel() >= (GC.getNumCultureLevelInfos() - 2))
- {
- iValue += 10;
- }
- }
-
- if (pLoopCity->isProductionUnit())
- {
- if (isLimitedUnitClass((UnitClassTypes)(GC.getUnitInfo(pLoopCity->getProductionUnit()).getUnitClassType())))
- {
- iValue += 4;
- }
- }
- else if (pLoopCity->isProductionBuilding())
- {
- if (isLimitedWonderClass((BuildingClassTypes)(GC.getBuildingInfo(pLoopCity->getProductionBuilding()).getBuildingClassType())))
- {
- iValue += 5;
- }
- }
- else if (pLoopCity->isProductionProject())
- {
- if (isLimitedProject(pLoopCity->getProductionProject()))
- {
- iValue += 6;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (iValue > 0)
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GUARD_SPY, getGroup()) == 0)
- {
- int iPathTurns;
- if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- iValue *= 100 + GC.getGameINLINE().getSorenRandNum(iRandomPercent, "AI Guard Spy");
- //iValue /= 100;
- iValue /= iPathTurns + 1;
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestGuardPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
- {
- if (atPlot(pBestGuardPlot))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_SPY, pBestGuardPlot);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_SPY, pBestGuardPlot);
- return true;
- }
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 10/25/09 jdog5000 */
- /* */
- /* Espionage AI */
- /************************************************************************************************/
- /*
- // Never used BTS functions ...
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_destroySpy()
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvCity* pBestCity;
- CvPlot* pBestPlot;
- int iValue;
- int iBestValue;
- int iLoop;
- int iI;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestCity = NULL;
- for (iI = 0; iI < MAX_CIV_PLAYERS; iI++)
- {
- if (GET_PLAYER((PlayerTypes)iI).isAlive())
- {
- if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_ANNOYED)
- {
- for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ATTACK_SPY, getGroup()) == 0)
- {
- if (generatePath(pLoopCity->plot(), 0, true))
- {
- iValue = (pLoopCity->getPopulation() * 2);
- iValue += pLoopCity->getYieldRate(YIELD_PRODUCTION);
- if (atPlot(pLoopCity->plot()))
- {
- iValue *= 4;
- iValue /= 3;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestCity = pLoopCity;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestCity != NULL))
- {
- if (atPlot(pBestCity->plot()))
- {
- if (canDestroy(pBestCity->plot()))
- {
- if (pBestCity->getProduction() > ((pBestCity->getProductionNeeded() * 2) / 3))
- {
- if (pBestCity->isProductionUnit())
- {
- if (isLimitedUnitClass((UnitClassTypes)(GC.getUnitInfo(pBestCity->getProductionUnit()).getUnitClassType())))
- {
- getGroup()->pushMission(MISSION_DESTROY);
- return true;
- }
- }
- else if (pBestCity->isProductionBuilding())
- {
- if (isLimitedWonderClass((BuildingClassTypes)(GC.getBuildingInfo(pBestCity->getProductionBuilding()).getBuildingClassType())))
- {
- getGroup()->pushMission(MISSION_DESTROY);
- return true;
- }
- }
- else if (pBestCity->isProductionProject())
- {
- if (isLimitedProject(pBestCity->getProductionProject()))
- {
- getGroup()->pushMission(MISSION_DESTROY);
- return true;
- }
- }
- }
- }
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY, pBestCity->plot());
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestCity->plot());
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_sabotageSpy()
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestSabotagePlot;
- bool abPlayerAngry[MAX_PLAYERS];
- ImprovementTypes eImprovement;
- BonusTypes eNonObsoleteBonus;
- int iValue;
- int iBestValue;
- int iI;
- for (iI = 0; iI < MAX_PLAYERS; iI++)
- {
- abPlayerAngry[iI] = false;
- if (GET_PLAYER((PlayerTypes)iI).isAlive())
- {
- if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_ANNOYED)
- {
- abPlayerAngry[iI] = true;
- }
- }
- }
- }
- iBestValue = 0;
- pBestPlot = NULL;
- pBestSabotagePlot = NULL;
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->isOwned())
- {
- if (pLoopPlot->getTeam() != getTeam())
- {
- if (abPlayerAngry[pLoopPlot->getOwnerINLINE()])
- {
- eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(pLoopPlot->getTeam());
- if (eNonObsoleteBonus != NO_BONUS)
- {
- eImprovement = pLoopPlot->getImprovementType();
- if ((eImprovement != NO_IMPROVEMENT) && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
- {
- if (canSabotage(pLoopPlot))
- {
- iValue = GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus);
- if (pLoopPlot->isConnectedToCapital() && (pLoopPlot->getPlotGroupConnectedBonus(pLoopPlot->getOwnerINLINE(), eNonObsoleteBonus) == 1))
- {
- iValue *= 3;
- }
- if (iValue > 25)
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ATTACK_SPY, getGroup()) == 0)
- {
- if (generatePath(pLoopPlot, 0, true))
- {
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestSabotagePlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestSabotagePlot != NULL))
- {
- if (atPlot(pBestSabotagePlot))
- {
- getGroup()->pushMission(MISSION_SABOTAGE);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestSabotagePlot);
- return true;
- }
- }
- return false;
- }
- bool CvUnitAI::AI_pickupTargetSpy()
- {
- PROFILE_FUNC();
- CvCity* pCity;
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- CvPlot* pBestPickupPlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- pCity = plot()->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- if (pCity->isCoastal(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY, pCity->plot());
- return true;
- }
- }
- }
- iBestValue = MAX_INT;
- pBestPlot = NULL;
- pBestPickupPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- if (pLoopCity->isCoastal(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- iValue = iPathTurns;
- if (iValue < iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestPickupPlot = pLoopCity->plot();
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestPickupPlot != NULL))
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestPickupPlot);
- return true;
- }
- return false;
- }
- */
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_chokeDefend()
- {
- CvCity* pCity;
- int iPlotDanger;
- //FAssert(AI_isCityAIType());
- // XXX what about amphib invasions?
- pCity = plot()->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- if (pCity->AI_neededDefenders() > 1)
- {
- if (pCity->AI_isDefended(pCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isNotCityAIType)))
- {
- iPlotDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3);
- if (iPlotDanger <= 4)
- {
- if (AI_anyAttack(1, 65, std::max(0, (iPlotDanger - 1))))
- {
- return true;
- }
- }
- }
- }
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_heal(int iDamagePercent, int iMaxPath)
- {
- PROFILE_FUNC();
- CLLNode<IDInfo>* pEntityNode;
- std::vector<CvUnit*> aeDamagedUnits;
- CvSelectionGroup* pGroup;
- CvUnit* pLoopUnit;
- int iTotalDamage;
- int iTotalHitpoints;
- int iHurtUnitCount;
- bool bRetreat;
- if (plot()->getFeatureType() != NO_FEATURE)
- {
- // Mongoose FeatureDamageFix BEGIN
- if (GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() > 0)
- // Mongoose FeatureDamageFix END
- {
- //Pass through
- //(actively seeking a safe spot may result in unit getting stuck)
- return false;
- }
- }
- //FfH: Added by Kael 10/01/2007 (so the AI won't try to sit and heal in areas where they cant heal)
- if (healRate(plot()) == 0)
- {
- return false;
- }
- //FfH: End Add
- pGroup = getGroup();
- if (iDamagePercent == 0)
- {
- iDamagePercent = 10;
- }
- bRetreat = false; // Tholal Note: This variable is never used
- if (getGroup()->getNumUnits() == 1)
- {
- if (getDamage() > 0)
- {
- if (plot()->isCity() || (healTurns(plot()) == 1)
- // Tholal AI (by Red Key) - allow barbarian animals to heal
- || (isBarbarian() && isAnimal())
- || (plot()->defenseModifier(getTeam(), false) > 0)) // units on defensive terrain should also try to heal
- // End Tholal AI
- {
- if (!(isAlwaysHeal()))
- {
- getGroup()->pushMission(MISSION_HEAL);
- return true;
- }
- }
- else
- {
- if (AI_seekDefensiveGround(1, true))
- {
- return true;
- }
- }
- }
- return false;
- }
- iMaxPath = std::min(iMaxPath, 4);
- pEntityNode = getGroup()->headUnitNode();
- iTotalDamage = 0;
- iTotalHitpoints = 0;
- iHurtUnitCount = 0;
- while (pEntityNode != NULL)
- {
- pLoopUnit = ::getUnit(pEntityNode->m_data);
- FAssert(pLoopUnit != NULL);
- pEntityNode = pGroup->nextUnitNode(pEntityNode);
- int iDamageThreshold = (pLoopUnit->maxHitPoints() * iDamagePercent) / 100;
- if (NO_UNIT != getLeaderUnitType())
- {
- iDamageThreshold /= 2;
- }
- if (pLoopUnit->getDamage() > 0)
- {
- iHurtUnitCount++;
- }
- iTotalDamage += pLoopUnit->getDamage();
- iTotalHitpoints += pLoopUnit->maxHitPoints();
- if (pLoopUnit->getDamage() > iDamageThreshold)
- {
- bRetreat = true;
- if (!(pLoopUnit->hasMoved()))
- {
- if (!(pLoopUnit->isAlwaysHeal()))
- {
- if (pLoopUnit->healTurns(pLoopUnit->plot()) <= iMaxPath)
- {
- aeDamagedUnits.push_back(pLoopUnit);
- }
- }
- }
- }
- }
- if (iHurtUnitCount == 0)
- {
- return false;
- }
- bool bPushedMission = false;
- if (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()))
- {
- FAssertMsg(((int) aeDamagedUnits.size()) <= iHurtUnitCount, "damaged units array is larger than our hurt unit count");
- for (unsigned int iI = 0; iI < aeDamagedUnits.size(); iI++)
- {
- CvUnit* pUnitToHeal = aeDamagedUnits[iI];
- if (pGroup->getNumUnits() > 2)
- {
- pUnitToHeal->joinGroup(NULL);
- }
- pUnitToHeal->getGroup()->pushMission(MISSION_HEAL);
- // note, removing the head unit from a group will force the group to be completely split if non-human
- if (pUnitToHeal == this)
- {
- bPushedMission = true;
- }
- iHurtUnitCount--;
- }
- }
- if ((iHurtUnitCount * 2) > pGroup->getNumUnits())
- {
- FAssertMsg(pGroup->getNumUnits() > 0, "group now has zero units");
- if (AI_moveIntoCity(2))
- {
- return true;
- }
- else if (healRate(plot()) > 10)
- {
- pGroup->pushMission(MISSION_HEAL);
- return true;
- }
- }
- return bPushedMission;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_afterAttack()
- {
- if (!isMadeAttack())
- {
- return false;
- }
- if (!canFight())
- {
- return false;
- }
- if (isBlitz())
- {
- return false;
- }
- if (getDomainType() == DOMAIN_LAND)
- {
- if (AI_guardCity(false, true, 1))
- {
- return true;
- }
- }
- if (AI_pillageRange(1))
- {
- return true;
- }
- if (AI_retreatToCity(false, false, 1))
- {
- return true;
- }
- if (AI_hide())
- {
- return true;
- }
- if (AI_goody(1))
- {
- return true;
- }
- if (AI_pillageRange(2))
- {
- return true;
- }
- if (AI_defend())
- {
- return true;
- }
- if (AI_safety())
- {
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_goldenAge()
- {
- if (canGoldenAge(plot()))
- {
- logBBAI(" %S (%d) starting Golden Age (%d units used)", getName().GetCString(), getID(), GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge());
- getGroup()->pushMission(MISSION_GOLDEN_AGE);
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_spreadReligion()
- {
- PROFILE_FUNC();
-
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
- // CvCity* pLoopCity;
- CvPlot* pBestPlot;
- CvPlot* pBestSpreadPlot;
- ReligionTypes eReligion;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iPlayerMultiplierPercent;
- int iLoop;
- int iI;
- bool bCultureVictory = kOwner.AI_isDoVictoryStrategy(AI_VICTORY_CULTURE2);
- eReligion = NO_RELIGION;
- if (kOwner.getStateReligion() != NO_RELIGION)
- {
- if (m_pUnitInfo->getReligionSpreads(kOwner.getStateReligion()) > 0)
- {
- eReligion = kOwner.getStateReligion();
- }
- }
- if (eReligion == NO_RELIGION)
- {
- for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
- {
- //if (bCultureVictory || GET_TEAM(getTeam()).hasHolyCity((ReligionTypes)iI))
- {
- if (m_pUnitInfo->getReligionSpreads((ReligionTypes)iI) > 0)
- {
- eReligion = ((ReligionTypes)iI);
- break;
- }
- }
- }
- }
- if (eReligion == NO_RELIGION)
- {
- return false;
- }
- bool bHasHolyCity = GET_TEAM(getTeam()).hasHolyCity(eReligion);
- bool bHasAnyHolyCity = bHasHolyCity;
- if (!bHasAnyHolyCity)
- {
- for (iI = 0; !bHasAnyHolyCity && iI < GC.getNumReligionInfos(); iI++)
- {
- bHasAnyHolyCity = GET_TEAM(getTeam()).hasHolyCity((ReligionTypes)iI);
- }
- }
- iBestValue = 0;
- pBestPlot = NULL;
- pBestSpreadPlot = NULL;
- for (iI = 0; iI < MAX_PLAYERS; iI++)
- {
- const CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
- if (kLoopPlayer.isAlive() && !kLoopPlayer.isBarbarian())
- {
- iPlayerMultiplierPercent = 0;
- if (kLoopPlayer.getTeam() != getTeam() && canEnterTerritory(kLoopPlayer.getTeam()))
- {
- if (bHasHolyCity)
- {
- iPlayerMultiplierPercent = 100;
- if (!bCultureVictory || (eReligion == kOwner.getStateReligion()))
- {
- if (kLoopPlayer.getStateReligion() == NO_RELIGION)
- {
- if (0 == (kLoopPlayer.getNonStateReligionHappiness()))
- {
- iPlayerMultiplierPercent += 600;
- }
- }
- else if (kLoopPlayer.getStateReligion() == eReligion)
- {
- iPlayerMultiplierPercent += 300;
- }
- else
- {
- if (kLoopPlayer.hasHolyCity(kLoopPlayer.getStateReligion()))
- {
- iPlayerMultiplierPercent += 50;
- }
- else
- {
- iPlayerMultiplierPercent += 300;
- }
- }
-
- int iReligionCount = kLoopPlayer.countTotalHasReligion();
- //int iCityCount = kOwner.getNumCities();
- int iCityCount = kLoopPlayer.getNumCities(); // K-Mod!
- //magic formula to produce normalized adjustment factor based on religious infusion
- int iAdjustment = (100 * (iCityCount + 1));
- iAdjustment /= ((iCityCount + 1) + iReligionCount);
- iAdjustment = (((iAdjustment - 25) * 4) / 3);
-
- iAdjustment = std::max(10, iAdjustment);
-
- iPlayerMultiplierPercent *= iAdjustment;
- iPlayerMultiplierPercent /= 100;
- }
- }
- }
- else if (iI == getOwnerINLINE())
- {
- iPlayerMultiplierPercent = 100;
- }
- else if (bHasHolyCity && kLoopPlayer.getTeam() == getTeam())
- {
- iPlayerMultiplierPercent = 80;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
-
- if (iPlayerMultiplierPercent > 0)
- {
- for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kLoopPlayer.nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()) && pLoopCity->area() == area() && (pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam())))
- {
- if (canSpread(pLoopCity->plot(), eReligion))
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (kOwner.AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD, getGroup()) == 0)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- iValue = (7 + (pLoopCity->getPopulation() * 4));
- bool bOurCity = false;
- if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
- {
- iValue *= (bCultureVictory ? 16 : 4);
- bOurCity = true;
- }
- else if (pLoopCity->getTeam() == getTeam())
- {
- iValue *= 3;
- bOurCity = true;
- }
- else
- {
- iValue *= iPlayerMultiplierPercent;
- iValue /= 100;
- }
- int iCityReligionCount = pLoopCity->getReligionCount();
- int iReligionCountFactor = iCityReligionCount;
- if (bOurCity)
- {
- // count cities with no religion the same as cities with 2 religions
- // prefer a city with exactly 1 religion already
- iValue *= 2; // Tholal AI - better to spread to our cities first
- if (iCityReligionCount == 0)
- {
- iReligionCountFactor = 2;
- }
- else if (iCityReligionCount == 1)
- {
- iValue *= 2;
- }
- }
- else
- {
- // absolutely prefer cities with zero religions
- if (iCityReligionCount == 0)
- {
- iValue *= 2;
- }
- // not our city, so prefer the lowest number of religions (increment so no divide by zero)
- iReligionCountFactor++;
- }
- iValue /= iReligionCountFactor;
- FAssert(iPathTurns > 0);
- bool bForceMove = false;
- if (isHuman())
- {
- //If human, prefer to spread to the player where automated from.
- if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
- {
- iValue *= 10;
- if (pLoopCity->isRevealed(getTeam(), false))
- {
- bForceMove = true;
- }
- }
- }
- iValue *= 1000;
- iValue /= (iPathTurns + 2);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = bForceMove ? pLoopCity->plot() : getPathEndTurnPlot();
- pBestSpreadPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestSpreadPlot != NULL))
- {
- if (atPlot(pBestSpreadPlot))
- {
- getGroup()->pushMission(MISSION_SPREAD, eReligion);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_SPREAD, pBestSpreadPlot);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_spreadCorporation()
- {
- PROFILE_FUNC();
- CorporationTypes eCorporation = NO_CORPORATION;
- for (int iI = 0; iI < GC.getNumCorporationInfos(); ++iI)
- {
- if (m_pUnitInfo->getCorporationSpreads((CorporationTypes)iI) > 0)
- {
- eCorporation = ((CorporationTypes)iI);
- break;
- }
- }
- if (NO_CORPORATION == eCorporation)
- {
- return false;
- }
- bool bHasHQ = (GET_TEAM(getTeam()).hasHeadquarters((CorporationTypes)iI));
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestSpreadPlot = NULL;
- CvTeam& kTeam = GET_TEAM(getTeam());
- for (int iI = 0; iI < MAX_PLAYERS; iI++)
- {
- CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/21/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if (kLoopPlayer.isAlive() && (bHasHQ || (getTeam() == kLoopPlayer.getTeam())))
- if (kLoopPlayer.isAlive() && ((bHasHQ && canEnterTerritory(GET_PLAYER((PlayerTypes)iI).getTeam())) || (getTeam() == kLoopPlayer.getTeam())))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- int iLoopPlayerCorpCount = kLoopPlayer.countCorporations(eCorporation);
- CvTeam& kLoopTeam = GET_TEAM(kLoopPlayer.getTeam());
- int iLoop;
- for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check same area
- if ( pLoopCity->area() == area() && canSpreadCorporation(pLoopCity->plot(), eCorporation))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD_CORPORATION, getGroup()) == 0)
- {
- int iPathTurns;
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- // BBAI TODO: Serious need for more intelligent self spread, keep certain corps from
- // enemies based on their victory pursuits (culture ...)
- int iValue = (10 + pLoopCity->getPopulation() * 2);
- if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
- {
- iValue *= 4;
- }
- else if (kLoopTeam.isVassal(getTeam()))
- {
- iValue *= 3;
- }
- else if (kTeam.isVassal(kLoopTeam.getID()))
- {
- if (iLoopPlayerCorpCount == 0)
- {
- iValue *= 10;
- }
- else
- {
- iValue *= 3;
- iValue /= 2;
- }
- }
- else if (pLoopCity->getTeam() == getTeam())
- {
- iValue *= 2;
- }
- if (iLoopPlayerCorpCount == 0)
- {
- //Generally prefer to heavily target one player
- iValue /= 2;
- }
- bool bForceMove = false;
- if (isHuman())
- {
- //If human, prefer to spread to the player where automated from.
- if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
- {
- iValue *= 10;
- if (pLoopCity->isRevealed(getTeam(), false))
- {
- bForceMove = true;
- }
- }
- }
- FAssert(iPathTurns > 0);
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = bForceMove ? pLoopCity->plot() : getPathEndTurnPlot();
- pBestSpreadPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestSpreadPlot != NULL))
- {
- if (atPlot(pBestSpreadPlot))
- {
- if (canSpreadCorporation(pBestSpreadPlot, eCorporation))
- {
- getGroup()->pushMission(MISSION_SPREAD_CORPORATION, eCorporation);
- }
- else
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_SPREAD_CORPORATION, pBestSpreadPlot);
- }
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_SPREAD_CORPORATION, pBestSpreadPlot);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- return true;
- }
- }
- return false;
- }
- bool CvUnitAI::AI_spreadReligionAirlift()
- {
- PROFILE_FUNC();
- CvPlot* pBestPlot;
- ReligionTypes eReligion;
- int iValue;
- int iBestValue;
- int iI;
- if (getGroup()->getNumUnits() > 1)
- {
- return false;
- }
- CvCity* pCity = plot()->getPlotCity();
- if (pCity == NULL)
- {
- return false;
- }
- if (pCity->getMaxAirlift() == 0)
- {
- return false;
- }
- //bool bCultureVictory = GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_CULTURE2);
- eReligion = NO_RELIGION;
- if (eReligion == NO_RELIGION)
- {
- if (GET_PLAYER(getOwnerINLINE()).getStateReligion() != NO_RELIGION)
- {
- if (m_pUnitInfo->getReligionSpreads(GET_PLAYER(getOwnerINLINE()).getStateReligion()) > 0)
- {
- eReligion = GET_PLAYER(getOwnerINLINE()).getStateReligion();
- }
- }
- }
- if (eReligion == NO_RELIGION)
- {
- for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
- {
- //if (bCultureVictory || GET_TEAM(getTeam()).hasHolyCity((ReligionTypes)iI))
- {
- if (m_pUnitInfo->getReligionSpreads((ReligionTypes)iI) > 0)
- {
- eReligion = ((ReligionTypes)iI);
- break;
- }
- }
- }
- }
- if (eReligion == NO_RELIGION)
- {
- return false;
- }
- iBestValue = 0;
- pBestPlot = NULL;
- for (int iI = 0; iI < MAX_PLAYERS; iI++)
- {
- CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
- if (kLoopPlayer.isAlive() && (getTeam() == kLoopPlayer.getTeam()))
- {
- int iLoop;
- for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
- {
- if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
- {
- if (canSpread(pLoopCity->plot(), eReligion))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD, getGroup()) == 0)
- {
- iValue = (7 + (pLoopCity->getPopulation() * 4));
- int iCityReligionCount = pLoopCity->getReligionCount();
- int iReligionCountFactor = iCityReligionCount;
- // count cities with no religion the same as cities with 2 religions
- // prefer a city with exactly 1 religion already
- if (iCityReligionCount == 0)
- {
- iReligionCountFactor = 2;
- }
- else if (iCityReligionCount == 1)
- {
- iValue *= 2;
- }
- iValue /= iReligionCountFactor;
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_SPREAD, pBestPlot);
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_spreadCorporationAirlift()
- {
- PROFILE_FUNC();
- if (getGroup()->getNumUnits() > 1)
- {
- return false;
- }
- CvCity* pCity = plot()->getPlotCity();
- if (pCity == NULL)
- {
- return false;
- }
- if (pCity->getMaxAirlift() == 0)
- {
- return false;
- }
- CorporationTypes eCorporation = NO_CORPORATION;
- for (int iI = 0; iI < GC.getNumCorporationInfos(); ++iI)
- {
- if (m_pUnitInfo->getCorporationSpreads((CorporationTypes)iI) > 0)
- {
- eCorporation = ((CorporationTypes)iI);
- break;
- }
- }
- if (NO_CORPORATION == eCorporation)
- {
- return false;
- }
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- for (int iI = 0; iI < MAX_PLAYERS; iI++)
- {
- CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
- if (kLoopPlayer.isAlive() && (getTeam() == kLoopPlayer.getTeam()))
- {
- int iLoop;
- for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
- {
- if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
- {
- if (canSpreadCorporation(pLoopCity->plot(), eCorporation))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD_CORPORATION, getGroup()) == 0)
- {
- int iValue = (pLoopCity->getPopulation() * 4);
- if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
- {
- iValue *= 4;
- }
- else
- {
- iValue *= 3;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_SPREAD, pBestPlot);
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_discover(bool bThisTurnOnly, bool bFirstResearchOnly)
- {
- TechTypes eDiscoverTech;
- bool bIsFirstTech;
- int iPercentWasted = 0;
- int iBonusPoints = 0;
- if (canDiscover(plot()))
- {
- eDiscoverTech = getDiscoveryTech();
- bIsFirstTech = (GC.getGameINLINE().countKnownTechNumTeams(eDiscoverTech) == 0);
- if (bFirstResearchOnly && !bIsFirstTech)
- {
- return false;
- }
- iPercentWasted = (100 - ((getDiscoverResearch(eDiscoverTech) * 100) / getDiscoverResearch(NO_TECH)));
- FAssert(((iPercentWasted >= 0) && (iPercentWasted <= 100)));
- if (bIsFirstTech)
- {
- // techs that give free techs
- if (GC.getTechInfo(eDiscoverTech).getFirstFreeTechs() > 0)
- {
- iBonusPoints +=25;
- }
- // techs that give a free unit (generally a Great Person)
- if (GET_PLAYER(getOwnerINLINE()).getTechFreeUnit(eDiscoverTech) != NO_UNIT)
- {
- iBonusPoints += 25;
- }
- // Religion founding techs
- for (int iReligion = 0; iReligion < GC.getNumReligionInfos(); iReligion++)
- {
- ReligionTypes eReligion = (ReligionTypes)iReligion;
- CvReligionInfo& kReligionInfo = GC.getReligionInfo(eReligion);
- const TechTypes eReligionTech = (TechTypes)GC.getReligionInfo(eReligion).getTechPrereq();
- if (eReligionTech == eDiscoverTech)
- {
- if (!GC.getGameINLINE().isReligionFounded(eReligion))
- {
- if (!GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_RELIGION2))
- {
- iBonusPoints += 25;
- }
- }
- }
- }
- }
- if (getDiscoverResearch(eDiscoverTech) >= GET_TEAM(getTeam()).getResearchLeft(eDiscoverTech))
- {
- if ((iPercentWasted < (45 + iBonusPoints)) && bFirstResearchOnly && bIsFirstTech)
- {
- if( gUnitLogLevel >= 2 )
- {
- 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);
- }
- getGroup()->pushMission(MISSION_DISCOVER);
- return true;
- }
- if (iPercentWasted < ((bIsFirstTech ? 31 : 11) + iBonusPoints))
- {
- if( gUnitLogLevel >= 2 )
- {
- 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);
- }
- getGroup()->pushMission(MISSION_DISCOVER);
- return true;
- }
- }
- else if (bThisTurnOnly)
- {
- return false;
- }
- if (iPercentWasted <= 11)
- {
- if (GET_PLAYER(getOwnerINLINE()).getCurrentResearch() == eDiscoverTech)
- {
- if( gUnitLogLevel >= 2 )
- {
- 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);
- }
- getGroup()->pushMission(MISSION_DISCOVER);
- return true;
- }
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_lead(std::vector<UnitAITypes>& aeUnitAITypes)
- {
- PROFILE_FUNC();
- FAssertMsg(!isHuman(), "isHuman did not return false as expected");
- FAssertMsg(AI_getUnitAIType() != NO_UNITAI, "AI_getUnitAIType() is not expected to be equal with NO_UNITAI");
- FAssert(NO_PLAYER != getOwnerINLINE());
- CvPlayer& kOwner = GET_PLAYER(getOwnerINLINE());
- bool bNeedLeader = false;
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD & RevDCM 09/03/10 jdog5000 */
- /* phungus420 */
- /* Great People AI, Unit AI */
- /************************************************************************************************/
- int iLoop;
- bool bBestUnitLegend = false;
- CvUnit* pLoopUnit = NULL;
- CvUnit* pBestUnit = NULL;
- CvPlot* pBestPlot = NULL;
- // AI may use Warlords to create super-medic units
- CvUnit* pBestStrUnit = NULL;
- CvPlot* pBestStrPlot = NULL;
- CvUnit* pBestHealUnit = NULL;
- CvPlot* pBestHealPlot = NULL;
-
- for (int iI = 0; iI < MAX_CIV_TEAMS; iI++)
- {
- CvTeamAI& kLoopTeam = GET_TEAM((TeamTypes)iI);
- if (isEnemy((TeamTypes)iI))
- {
- if (kLoopTeam.countNumUnitsByArea(area()) > 0)
- {
- bNeedLeader = true;
- break;
- }
- }
- }
- if (bNeedLeader)
- {
- int iBestStrength = 0;
- int iBestHealing = 0;
- int iCombatStrength;
- bool bValid;
- bool bLegend;
- for (pLoopUnit = kOwner.firstUnit(&iLoop); pLoopUnit; pLoopUnit = kOwner.nextUnit(&iLoop))
- {
- if(pLoopUnit != NULL)
- {
- bValid = false;
- bLegend = false;
- if (GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() > 0
- && GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() < 7)
- {
- if (canLead(pLoopUnit->plot(), pLoopUnit->getID()) > 0)
- {
- bValid = true;
- bLegend = true;
- }
- }
- if( !bValid )
- {
- for (uint iI = 0; iI < aeUnitAITypes.size(); iI++)
- {
- if (pLoopUnit->AI_getUnitAIType() == aeUnitAITypes[iI] || NO_UNITAI == aeUnitAITypes[iI])
- {
- if (canLead(pLoopUnit->plot(), pLoopUnit->getID()) > 0)
- {
- bValid = true;
- break;
- }
- }
- }
- }
- if( bValid )
- {
- if (AI_plotValid(pLoopUnit->plot()))
- {
- if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
- {
- if( pLoopUnit->combatLimit() == 100 )
- {
- if (generatePath(pLoopUnit->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true))
- {
- // pick the unit with the highest current strength
- iCombatStrength = pLoopUnit->currCombatStr(NULL, NULL);
- iCombatStrength *= 10 + (pLoopUnit->getExperience() * 2);
- iCombatStrength /= 15;
- if (pLoopUnit->getUnitCombatType() == NO_UNITCOMBAT)
- {
- iCombatStrength /= 10;
- }
- if(bLegend)
- {
- iCombatStrength *= 10 - GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances();
- iCombatStrength /= 3;
- }
- if (iCombatStrength > iBestStrength)
- {
- iBestStrength = iCombatStrength;
- pBestStrUnit = pLoopUnit;
- pBestStrPlot = getPathEndTurnPlot();
- if(bLegend)
- {
- bBestUnitLegend = true;
- }
- else
- {
- bBestUnitLegend = false;
- }
- }
-
- // or the unit with the best healing ability
- int iHealing = pLoopUnit->getSameTileHeal() + pLoopUnit->getAdjacentTileHeal();
- if (iHealing > iBestHealing)
- {
- iBestHealing = iHealing;
- pBestHealUnit = pLoopUnit;
- pBestHealPlot = getPathEndTurnPlot();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if( AI_getBirthmark() % 3 == 0 && pBestHealUnit != NULL )
- {
- pBestPlot = pBestHealPlot;
- pBestUnit = pBestHealUnit;
- }
- else
- {
- pBestPlot = pBestStrPlot;
- pBestUnit = pBestStrUnit;
- }
- if (pBestPlot)
- {
- if (atPlot(pBestPlot) && pBestUnit)
- {
- if( gUnitLogLevel > 2 )
- {
- CvWString szString;
- getUnitAIString(szString, pBestUnit->AI_getUnitAIType());
- if(bBestUnitLegend)
- {
- 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());
- }
- else
- {
- 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());
- }
- }
- getGroup()->pushMission(MISSION_LEAD, pBestUnit->getID());
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
- return true;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- return false;
- }
- // Returns true if a mission was pushed...
- // iMaxCounts = 1 would mean join a city if there's no existing joined GP of that type.
- bool CvUnitAI::AI_join(int iMaxCount)
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- SpecialistTypes eBestSpecialist;
- int iValue;
- int iBestValue;
- int iLoop;
- int iI;
- int iCount;
- iBestValue = 0;
- pBestPlot = NULL;
- eBestSpecialist = NO_SPECIALIST;
- iCount = 0;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check same area
- if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true) || (plot() == pLoopCity->plot()))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
- {
- bool bDoesJoin = false;
- SpecialistTypes eSpecialist = (SpecialistTypes)iI;
- if (m_pUnitInfo->getGreatPeoples(eSpecialist))
- {
- bDoesJoin = true;
- }
- if (bDoesJoin)
- {
- iCount += pLoopCity->getSpecialistCount(eSpecialist);
- if (iCount >= iMaxCount)
- {
- return false;
- }
- }
- if (canJoin(pLoopCity->plot(), ((SpecialistTypes)iI)))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopCity->plot(), 2) == 0)
- if ( !(GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(pLoopCity->plot(), 2)) )
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- iValue = pLoopCity->AI_specialistValue(((SpecialistTypes)iI), pLoopCity->AI_avoidGrowth(), false);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- eBestSpecialist = ((SpecialistTypes)iI);
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (eBestSpecialist != NO_SPECIALIST))
- {
- if (atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_JOIN, eBestSpecialist);
- 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());
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- // iMaxCount = 1 would mean construct only if there are no existing buildings
- // constructed by this GP type.
- bool CvUnitAI::AI_construct(int iMaxCount, int iMaxSingleBuildingCount, int iThreshold)
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- CvPlot* pBestConstructPlot;
- BuildingTypes eBestBuilding;
- int iValue;
- int iBestValue;
- int iLoop;
- int iI;
- int iCount;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestConstructPlot = NULL;
- eBestBuilding = NO_BUILDING;
- iCount = 0;
- CvPlayer &kPlayer = GET_PLAYER(getOwnerINLINE());
- for (pLoopCity = kPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()) && pLoopCity->area() == area())
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (kPlayer.AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_CONSTRUCT, getGroup()) == 0)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
- {
- BuildingTypes eBuilding = (BuildingTypes)GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iI);
- if (NO_BUILDING != eBuilding)
- {
- bool bDoesBuild = false;
- if ((m_pUnitInfo->getForceBuildings(eBuilding))
- || (m_pUnitInfo->getBuildings(eBuilding)))
- {
- bDoesBuild = true;
- }
- if (bDoesBuild && (pLoopCity->getNumBuilding(eBuilding) > 0))
- {
- iCount++;
- if (iCount >= iMaxCount)
- {
- return false;
- }
- }
- if (bDoesBuild && kPlayer.getBuildingClassCount((BuildingClassTypes)GC.getBuildingInfo(eBuilding).getBuildingClassType()) < iMaxSingleBuildingCount)
- {
- if (canConstruct(pLoopCity->plot(), eBuilding))
- {
- iValue = pLoopCity->AI_buildingValue(eBuilding);
- if (plot()->isCity())
- {
- if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0))
- {
- if (baseCombatStr() > 0)
- iValue = 0;
- }
- }
- // Sephi AI (Religion Victory)
- /*
- if (AI_getUnitAIType()==UNITAI_PROPHET)
- {
- if (pLoopCity->isCapital())
- {
- iValue+=10000;
- }
- }
- */
- // End Sephi AI
- // Tholal AI - Holy Shrines
- if (GC.getBuildingInfo(eBuilding).getHolyCity() != NO_RELIGION)
- {
- if (kPlayer.getStateReligion() != NO_RELIGION)
- {
- if (GC.getBuildingInfo(eBuilding).getHolyCity() == kPlayer.getStateReligion())
- {
- iValue+=20001;
- }
- }
- }
- // End Tholal AI
- if ((iValue > iThreshold) && (iValue > iBestValue))
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestConstructPlot = pLoopCity->plot();
- eBestBuilding = eBuilding;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestConstructPlot != NULL) && (eBestBuilding != NO_BUILDING))
- {
- logBBAI(" %S (%d)constructing %S at %d, %d (value: %d)", getName().GetCString(), getID(), GC.getBuildingInfo(eBestBuilding).getText(), pBestPlot->getX(), pBestPlot->getY(), iBestValue);
- if (atPlot(pBestConstructPlot))
- {
- getGroup()->pushMission(MISSION_CONSTRUCT, eBestBuilding);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if (getGroup()->getNumUnits() > 1)
- {
- joinGroup(NULL);
- }
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_CONSTRUCT, pBestConstructPlot);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_switchHurry()
- {
- CvCity* pCity;
- BuildingTypes eBestBuilding;
- int iValue;
- int iBestValue;
- int iI;
- pCity = plot()->getPlotCity();
- if ((pCity == NULL) || (pCity->getOwnerINLINE() != getOwnerINLINE()))
- {
- return false;
- }
- iBestValue = 0;
- eBestBuilding = NO_BUILDING;
- for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
- {
- if (isWorldWonderClass((BuildingClassTypes)iI))
- {
- BuildingTypes eBuilding = (BuildingTypes)GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iI);
- if (NO_BUILDING != eBuilding)
- {
- if (pCity->canConstruct(eBuilding))
- {
- if (pCity->getBuildingProduction(eBuilding) == 0)
- {
- if (getMaxHurryProduction(pCity) >= pCity->getProductionNeeded(eBuilding))
- {
- iValue = pCity->AI_buildingValue(eBuilding);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestBuilding = eBuilding;
- }
- }
- }
- }
- }
- }
- }
- if (eBestBuilding != NO_BUILDING)
- {
- pCity->pushOrder(ORDER_CONSTRUCT, eBestBuilding, -1, false, false, false);
- if (pCity->getProductionBuilding() == eBestBuilding)
- {
- if (canHurry(plot()))
- {
- getGroup()->pushMission(MISSION_HURRY);
- return true;
- }
- }
- FAssert(false);
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_hurry()
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- CvPlot* pBestHurryPlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestHurryPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check same area
- if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- if (canHurry(pLoopCity->plot()))
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_HURRY, getGroup()) == 0)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- if (pLoopCity->isProductionBuilding())
- {
- if (pLoopCity->getProductionTurnsLeft() > iPathTurns)
- {
- iValue = pLoopCity->getProductionNeeded();
- iValue += pLoopCity->getProductionTurnsLeft() * 5;
- // Tholal ToDo - value based on what building we're making
- if (isWorldWonderClass((BuildingClassTypes)GC.getBuildingInfo(pLoopCity->getProductionBuilding()).getBuildingClassType()))
- {
- iValue *= 4;
- }
- else if (isNationalWonderClass((BuildingClassTypes)GC.getBuildingInfo(pLoopCity->getProductionBuilding()).getBuildingClassType()))
- {
- iValue *= 2;
- }
- iValue -= GC.getUnitInfo(getUnitType()).getBaseHurry();
- iValue -= iPathTurns * 2;
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestHurryPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestHurryPlot != NULL))
- {
- int iProdRemaining = (pBestHurryPlot->getPlotCity()->getProductionNeeded() - pBestHurryPlot->getPlotCity()->getProduction());
- if (atPlot(pBestHurryPlot))
- {
- getGroup()->pushMission(MISSION_HURRY);
- 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);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- 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);
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_HURRY, pBestHurryPlot);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_greatWork()
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- CvPlot* pBestGreatWorkPlot;
- int iValue;
- int iBestValue;
- int iLoop;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestGreatWorkPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check same area
- if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- if (canGreatWork(pLoopCity->plot()))
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GREAT_WORK, getGroup()) == 0)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/03/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- iValue = pLoopCity->AI_calculateCulturePressure(true);
- iValue -= ((100 * pLoopCity->getCulture(pLoopCity->getOwnerINLINE())) / std::max(1, getGreatWorkCulture(pLoopCity->plot())));
- if (iValue > 0)
- {
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestGreatWorkPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestGreatWorkPlot != NULL))
- {
- if (atPlot(pBestGreatWorkPlot))
- {
- getGroup()->pushMission(MISSION_GREAT_WORK);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/09/09 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_GREAT_WORK, pBestGreatWorkPlot);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_offensiveAirlift()
- {
- PROFILE_FUNC();
- CvCity* pCity;
- CvCity* pTargetCity;
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- int iValue;
- int iBestValue;
- int iLoop;
- if (getGroup()->getNumUnits() > 1)
- {
- return false;
- }
- if (area()->getTargetCity(getOwnerINLINE()) != NULL)
- {
- return false;
- }
- pCity = plot()->getPlotCity();
- if (pCity == NULL)
- {
- return false;
- }
- if (pCity->getMaxAirlift() == 0)
- {
- return false;
- }
- iBestValue = 0;
- pBestPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (pLoopCity->area() != pCity->area())
- {
- if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
- {
- pTargetCity = pLoopCity->area()->getTargetCity(getOwnerINLINE());
- if (pTargetCity != NULL)
- {
- /* AreaAITypes eAreaAIType = pTargetCity->area()->getAreaAIType(getTeam());
- if (((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING))
- || pTargetCity->AI_isDanger()) */
- if (GET_PLAYER(getOwnerINLINE()).AI_isLandWar(pTargetCity->area()) || pTargetCity->AI_isDanger()) // K-Mod
- {
- iValue = 10000;
- iValue *= (GET_PLAYER(getOwnerINLINE()).AI_militaryWeight(pLoopCity->area()) + 10);
- iValue /= (GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), AI_getUnitAIType()) + 10);
- iValue += std::max(1, ((GC.getMapINLINE().maxStepDistance() * 2) - GC.getMapINLINE().calculatePathDistance(pLoopCity->plot(), pTargetCity->plot())));
- if (AI_getUnitAIType() == UNITAI_PARADROP)
- {
- CvCity* pNearestEnemyCity = GC.getMapINLINE().findCity(pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), NO_PLAYER, NO_TEAM, false, false, getTeam());
- if (pNearestEnemyCity != NULL)
- {
- int iDistance = plotDistance(pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), pNearestEnemyCity->getX_INLINE(), pNearestEnemyCity->getY_INLINE());
- if (iDistance <= getDropRange())
- {
- iValue *= 5;
- }
- }
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- FAssert(pLoopCity != pCity);
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_paradrop(int iRange)
- {
- PROFILE_FUNC();
- if (getGroup()->getNumUnits() > 1)
- {
- return false;
- }
- int iParatrooperCount = plot()->plotCount(PUF_isUnitAIType, UNITAI_PARADROP, -1, getOwnerINLINE());
- FAssert(iParatrooperCount > 0);
- CvPlot* pPlot = plot();
- if (!canParadrop(pPlot))
- {
- return false;
- }
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- int iSearchRange = AI_searchRange(iRange);
- for (int iDX = -iSearchRange; iDX <= iSearchRange; ++iDX)
- {
- for (int iDY = -iSearchRange; iDY <= iSearchRange; ++iDY)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
- {
- if (canParadropAt(pPlot, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
- {
- int iValue = 0;
- PlayerTypes eTargetPlayer = pLoopPlot->getOwnerINLINE();
- FAssert(NO_PLAYER != eTargetPlayer);
- /************************************************************************************************/
- /* UNOFFICIAL_PATCH 08/01/08 jdog5000 */
- /* */
- /* Bugfix */
- /************************************************************************************************/
- /* original BTS code
- if (NO_BONUS != pLoopPlot->getBonusType())
- {
- iValue += GET_PLAYER(eTargetPlayer).AI_bonusVal(pLoopPlot->getBonusType()) - 10;
- }
- */
- // Bonus values for bonuses the AI has are less than 10 for non-strategic resources... since this is
- // in the AI territory they probably have it
- if (NO_BONUS != pLoopPlot->getNonObsoleteBonusType(getTeam()))
- {
- iValue += std::max(1,GET_PLAYER(eTargetPlayer).AI_bonusVal(pLoopPlot->getBonusType()) - 10);
- }
- /************************************************************************************************/
- /* UNOFFICIAL_PATCH END */
- /************************************************************************************************/
- for (int i = -1; i <= 1; ++i)
- {
- for (int j = -1; j <= 1; ++j)
- {
- CvPlot* pAdjacentPlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), i, j);
- if (NULL != pAdjacentPlot)
- {
- CvCity* pAdjacentCity = pAdjacentPlot->getPlotCity();
- if (NULL != pAdjacentCity)
- {
- if (pAdjacentCity->getOwnerINLINE() == eTargetPlayer)
- {
- int iAttackerCount = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pAdjacentPlot, true);
- int iDefenderCount = pAdjacentPlot->getNumVisibleEnemyDefenders(this);
- iValue += 20 * (AI_attackOdds(pAdjacentPlot, true) - ((50 * iDefenderCount) / (iParatrooperCount + iAttackerCount)));
- }
- }
- }
- }
- }
- if (iValue > 0)
- {
- iValue += pLoopPlot->defenseModifier(getTeam(), ignoreBuildingDefense());
- CvUnit* pInterceptor = bestInterceptor(pLoopPlot);
- if (NULL != pInterceptor)
- {
- int iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
- iInterceptProb *= std::max(0, (100 - evasionProbability()));
- iInterceptProb /= 100;
- iValue *= std::max(0, 100 - iInterceptProb / 2);
- iValue /= 100;
- }
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- FAssert(pBestPlot != pPlot);
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_PARADROP, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 09/01/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_protect(int iOddsThreshold, int iMaxPathTurns)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iValue;
- int iBestValue;
- int iI;
- iBestValue = 0;
- pBestPlot = NULL;
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->isVisibleEnemyUnit(this))
- {
- if (!atPlot(pLoopPlot))
- {
- // BBAI efficiency: Check area for land units
- if( (getDomainType() != DOMAIN_LAND) || (pLoopPlot->area() == area()) || getGroup()->canMoveAllTerrain() )
- {
- // BBAI efficiency: Most of the time, path will exist and odds will be checked anyway. When path doesn't exist, checking path
- // takes longer. Therefore, check odds first.
- iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
- if ((iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold)) && (iValue*50 > iBestValue))
- {
- int iPathTurns;
- if( generatePath(pLoopPlot, 0, true, &iPathTurns) )
- {
- // BBAI TODO: Other units targeting this already (if path turns > 1 or 0)?
- if( iPathTurns <= iMaxPathTurns )
- {
- iValue *= 100;
- iValue /= (2 + iPathTurns);
-
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_patrol()
- {
- PROFILE_FUNC();
- CvPlot* pAdjacentPlot;
- CvPlot* pBestPlot;
- int iValue;
- int iBestValue;
- int iI;
- iBestValue = 0;
- pBestPlot = NULL;
- for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot != NULL)
- {
- if (AI_plotValid(pAdjacentPlot))
- {
- if (!(pAdjacentPlot->isVisibleEnemyUnit(this)))
- {
- if (generatePath(pAdjacentPlot, 0, true))
- {
- iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Patrol"));
- if (isBarbarian())
- {
- if (isAnimal() || AI_getUnitAIType() == UNITAI_ANIMAL) // keep animals out of owned territory
- {
- if (!(pAdjacentPlot->isOwned()))
- {
- iValue += 20000;
- }
-
- if (!(pAdjacentPlot->isAdjacentOwned()))
- {
- iValue += 10000;
- }
- }
- }
- else
- {
- if (pAdjacentPlot->isRevealedGoody(getTeam()))
- {
- iValue += 100000;
- }
- if (pAdjacentPlot->getOwnerINLINE() == getOwnerINLINE())
- {
- iValue += 10000;
- }
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- //pBestPlot = getPathEndTurnPlot();
- pBestPlot = pAdjacentPlot;
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_defend()
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- if (AI_defendPlot(plot()))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- iSearchRange = AI_searchRange(1);
- iBestValue = 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- if (AI_defendPlot(pLoopPlot))
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= 1)
- {
- iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Defend"));
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 12/06/08 jdog5000 */
- /* */
- /* Unit AI */
- /************************************************************************************************/
- if( !(pBestPlot->isCity()) && (getGroup()->getNumUnits() > 1) )
- {
- //getGroup()->AI_makeForceSeparate();
- joinGroup(0); // K-Mod. (AI_makeForceSeparate is a complete waste of time here.)
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_safety()
- {
- PROFILE_FUNC();
- CLLNode<IDInfo>* pUnitNode;
- CvUnit* pLoopUnit;
- CvUnit* pHeadUnit;
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iCount;
- int iPass;
- int iDX, iDY;
- iSearchRange = AI_searchRange(1);
- iBestValue = 0;
- pBestPlot = NULL;
- for (iPass = 0; iPass < 2; iPass++)
- {
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (generatePath(pLoopPlot, ((iPass > 0) ? MOVE_IGNORE_DANGER : 0), true, &iPathTurns))
- {
- if (iPathTurns <= 1)
- {
- iCount = 0;
- pUnitNode = pLoopPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
- if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
- {
- if (pLoopUnit->canDefend())
- {
- pHeadUnit = pLoopUnit->getGroup()->getHeadUnit();
- FAssert(pHeadUnit != NULL);
- FAssert(getGroup()->getHeadUnit() == this);
- if (pHeadUnit != this)
- {
- if (pHeadUnit->isWaiting() || !(pHeadUnit->canMove()))
- {
- FAssert(pLoopUnit != this);
- FAssert(pHeadUnit != getGroup()->getHeadUnit());
- iCount++;
- }
- }
- }
- }
- }
- iValue = (iCount * 100);
- iValue += pLoopPlot->defenseModifier(getTeam(), false);
- if (atPlot(pLoopPlot))
- {
- iValue += 50;
- }
- else
- {
- iValue += GC.getGameINLINE().getSorenRandNum(50, "AI Safety");
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((iPass > 0) ? MOVE_IGNORE_DANGER : 0));
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_hide()
- {
- PROFILE_FUNC();
- CLLNode<IDInfo>* pUnitNode;
- CvUnit* pLoopUnit;
- CvUnit* pHeadUnit;
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- bool bValid;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iCount;
- int iDX, iDY;
- int iI;
- if (getInvisibleType() == NO_INVISIBLE)
- {
- return false;
- }
- iSearchRange = AI_searchRange(1);
- iBestValue = 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- bValid = true;
- for (iI = 0; iI < MAX_TEAMS; iI++)
- {
- if (GET_TEAM((TeamTypes)iI).isAlive())
- {
- if (pLoopPlot->isInvisibleVisible(((TeamTypes)iI), getInvisibleType()))
- {
- bValid = false;
- break;
- }
- }
- }
- if (bValid)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= 1)
- {
- iCount = 1;
- pUnitNode = pLoopPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
- if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
- {
- if (pLoopUnit->canDefend())
- {
- pHeadUnit = pLoopUnit->getGroup()->getHeadUnit();
- FAssert(pHeadUnit != NULL);
- FAssert(getGroup()->getHeadUnit() == this);
- if (pHeadUnit != this)
- {
- if (pHeadUnit->isWaiting() || !(pHeadUnit->canMove()))
- {
- FAssert(pLoopUnit != this);
- FAssert(pHeadUnit != getGroup()->getHeadUnit());
- iCount++;
- }
- }
- }
- }
- }
- iValue = (iCount * 100);
- iValue += pLoopPlot->defenseModifier(getTeam(), false);
- if (atPlot(pLoopPlot))
- {
- iValue += 50;
- }
- else
- {
- iValue += GC.getGameINLINE().getSorenRandNum(50, "AI Hide");
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_goody(int iRange)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- // CvPlot* pAdjacentPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- // int iI;
- if (isBarbarian())
- {
- return false;
- }
- iSearchRange = AI_searchRange(iRange);
- iBestValue = 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->isRevealedGoody(getTeam()))
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= iRange)
- {
- iValue = (10 + GC.getGameINLINE().getSorenRandNum(10000, "AI Goody"));
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- //pBestPlot = getPathEndTurnPlot();
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_explore()
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pAdjacentPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestExplorePlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iI, iJ;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestExplorePlot = NULL;
- bool bNoContact = (GC.getGameINLINE().countCivTeamsAlive() > GET_TEAM(getTeam()).getHasMetCivCount(true));
- if (getDomainType() == DOMAIN_AIR)
- {
- if (canRecon(plot()))
- {
- if (AI_exploreAir())
- {
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- }
- }
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- PROFILE("AI_explore 1");
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- iValue = 0;
- if (pLoopPlot->isRevealedGoody(getTeam()))
- {
- iValue += 100000;
- }
- if (iValue > 0 || GC.getGameINLINE().getSorenRandNum(4, "AI make explore faster ;)") == 0)
- {
- if (!(pLoopPlot->isRevealed(getTeam(), false)))
- {
- iValue += 10000;
- }
- // XXX is this too slow?
- for (iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
- {
- PROFILE("AI_explore 2");
- pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iJ));
- if (pAdjacentPlot != NULL)
- {
- if (!(pAdjacentPlot->isRevealed(getTeam(), false)))
- {
- iValue += 1000;
- }
- else if (bNoContact)
- {
- if (pAdjacentPlot->getRevealedTeam(getTeam(), false) != pAdjacentPlot->getTeam())
- {
- iValue += 100;
- }
- }
- }
- }
- if (iValue > 0)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_EXPLORE, getGroup(), 3) == 0)
- {
- if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
- {
- iValue += GC.getGameINLINE().getSorenRandNum(250 * abs(xDistance(getX_INLINE(), pLoopPlot->getX_INLINE())) + abs(yDistance(getY_INLINE(), pLoopPlot->getY_INLINE())), "AI explore");
- if (pLoopPlot->isAdjacentToLand())
- {
- iValue += 10000;
- }
- if (pLoopPlot->isOwned())
- {
- iValue += 5000;
- }
- iValue /= 3 + std::max(1, iPathTurns);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot->isRevealedGoody(getTeam()) ? getPathEndTurnPlot() : pLoopPlot;
- pBestExplorePlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestExplorePlot != NULL))
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_EXPLORE, pBestExplorePlot);
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_exploreRange(int iRange)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pAdjacentPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestExplorePlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- int iI;
- iSearchRange = AI_searchRange(iRange);
- iBestValue = 0;
- pBestPlot = NULL;
- pBestExplorePlot = NULL;
- int iImpassableCount = GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(getUnitType());
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- PROFILE("AI_exploreRange 1");
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- iValue = 0;
- if (pLoopPlot->isRevealedGoody(getTeam()))
- {
- iValue += 100000;
- }
- if (!(pLoopPlot->isRevealed(getTeam(), false)))
- {
- iValue += 10000;
- }
- for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- PROFILE("AI_exploreRange 2");
- pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot != NULL)
- {
- if (!(pAdjacentPlot->isRevealed(getTeam(), false)))
- {
- iValue += 1000;
- }
- }
- }
- if (iValue > 0)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- PROFILE("AI_exploreRange 3");
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_EXPLORE, getGroup(), 3) == 0)
- {
- PROFILE("AI_exploreRange 4");
- if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
- {
- if (iPathTurns <= iRange)
- {
- iValue += GC.getGameINLINE().getSorenRandNum(10000, "AI Explore");
- if (pLoopPlot->isAdjacentToLand())
- {
- iValue += 10000;
- }
- if (pLoopPlot->isOwned())
- {
- iValue += 5000;
- }
- if (!isHuman())
- {
- int iDirectionModifier = 100;
- if (AI_getUnitAIType() == UNITAI_EXPLORE_SEA && iImpassableCount == 0)
- {
- iDirectionModifier += (50 * (abs(iDX) + abs(iDY))) / iSearchRange;
- if (GC.getGame().circumnavigationAvailable())
- {
- if (GC.getMap().isWrapX())
- {
- if ((iDX * ((AI_getBirthmark() % 2 == 0) ? 1 : -1)) > 0)
- {
- iDirectionModifier *= 150 + ((iDX * 100) / iSearchRange);
- }
- else
- {
- iDirectionModifier /= 2;
- }
- }
- if (GC.getMap().isWrapY())
- {
- if ((iDY * (((AI_getBirthmark() >> 1) % 2 == 0) ? 1 : -1)) > 0)
- {
- iDirectionModifier *= 150 + ((iDY * 100) / iSearchRange);
- }
- else
- {
- iDirectionModifier /= 2;
- }
- }
- }
- iValue *= iDirectionModifier;
- iValue /= 100;
- }
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- if (getDomainType() == DOMAIN_LAND)
- {
- pBestPlot = getPathEndTurnPlot();
- }
- else
- {
- pBestPlot = pLoopPlot;
- }
- pBestExplorePlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestExplorePlot != NULL))
- {
- PROFILE("AI_exploreRange 5");
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_EXPLORE, pBestExplorePlot);
- return true;
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/29/10 jdog5000 */
- /* */
- /* War tactics AI, Efficiency */
- /************************************************************************************************/
- // Returns target city
- CvCity* CvUnitAI::AI_pickTargetCity(int iFlags, int iMaxPathTurns, bool bHuntBarbs )
- {
- PROFILE_FUNC();
- CvCity* pTargetCity;
- CvCity* pLoopCity;
- CvCity* pBestCity;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- int iI;
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
-
- iBestValue = 0;
- pBestCity = NULL;
- if( gUnitLogLevel > 3 )
- {
- logBBAI(" Starting Pick Target City:");
- }
- pTargetCity = area()->getTargetCity(getOwnerINLINE());
- // Don't always go after area target ... don't know how far away it is
- /*
- if (pTargetCity != NULL)
- {
- if (AI_potentialEnemy(pTargetCity->getTeam(), pTargetCity->plot()))
- {
- if (!atPlot(pTargetCity->plot()) && generatePath(pTargetCity->plot(), iFlags, true))
- {
- pBestCity = pTargetCity;
- }
- }
- }
- */
- if (pBestCity == NULL)
- {
- //for (iI = 0; iI < (bHuntBarbs ? MAX_PLAYERS : MAX_CIV_PLAYERS); iI++)
- for (iI = 0; iI < MAX_PLAYERS; iI++)
- {
- if (GET_PLAYER((PlayerTypes)iI).isAlive() && ::isPotentialEnemy(getTeam(), GET_PLAYER((PlayerTypes)iI).getTeam()))
- {
- for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
- {
- // BBAI efficiency: check area for land units before generating path
- //if (pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam()))
- if (kOwner.AI_deduceCitySite(pLoopCity))
- {
- if (AI_plotValid(pLoopCity->plot()) && (pLoopCity->area() == area()) || (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL")))
- {
- if (AI_potentialEnemy(GET_PLAYER((PlayerTypes)iI).getTeam(), pLoopCity->plot()))
- {
- if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), iFlags, true, &iPathTurns))
- {
- if( iPathTurns <= iMaxPathTurns )
- {
- // If city is visible and our force already in position is dominantly powerful or we have a huge force
- // already on the way, pick a different target
- if( iPathTurns > 2 && pLoopCity->isVisible(getTeam(), false) )
- {
- /*
- int iOurOffense = GET_TEAM(getTeam()).AI_getOurPlotStrength(pLoopCity->plot(),2,false,false,true);
- int iEnemyDefense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pLoopCity->plot(),1,true,false);
- if( 100*iOurOffense >= GC.getBBAI_SKIP_BOMBARD_BASE_STACK_RATIO()*iEnemyDefense )
- {
- continue;
- }
- */
- if( kOwner.AI_cityTargetUnitsByPath(pLoopCity, getGroup(), iPathTurns) > std::max( 6, 3 * pLoopCity->plot()->getNumVisibleEnemyDefenders(this) ) )
- {
- continue;
- }
- }
- iValue = 0;
- if (AI_getUnitAIType() == (UNITAI_ATTACK_CITY | UNITAI_ASSAULT_SEA)) //lemming?
- {
- iValue = kOwner.AI_targetCityValue(pLoopCity, false, false);
- }
- else
- {
- iValue = kOwner.AI_targetCityValue(pLoopCity, true, true);
- }
- if (isBarbarian())
- {
- iValue += GC.getGameINLINE().getSorenRandNum(100, "AI Barbarian Modifier");
- }
- if( gUnitLogLevel > 3 )
- {
- logBBAI(" ...valuing city %S (initial value: %d)", pLoopCity->getName().GetCString(), iValue);
- }
- if( pLoopCity == pTargetCity)
- {
- iValue *= 2;
- }
-
- if ((area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE))
- {
- iValue *= 50 + pLoopCity->calculateCulturePercent(getOwnerINLINE());
- iValue /= 50;
- }
- iValue *= 1000;
- // If city is minor civ, less interesting
- if( GET_PLAYER(pLoopCity->getOwnerINLINE()).isMinorCiv() )
- {
- iValue /= 2;
- }
- if (GET_PLAYER(pLoopCity->getOwnerINLINE()).isBarbarian())// && !bHuntBarbs)
- {
- if (!bHuntBarbs)
- {
- iValue /= 2;
- }
- if (pLoopCity->getCultureLevel() > 0)
- {
- iValue /= 10;
- }
- }
- if (!(pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam())))
- {
- iValue /= 4;
- }
- if (pLoopCity->isRevealed(getTeam(), false) && pLoopCity->plot()->getNumDefenders(pLoopCity->getOwner()) == 0)
- {
- iValue *= 4;
- }
- // If stack has poor bombard, direct towards lower defense cities
- iPathTurns += std::min(12, getGroup()->getBombardTurns(pLoopCity)/4);
- iValue /= (4 + iPathTurns*iPathTurns);
- // dont start new wars unless we have a seemingly overwhelming force
- if (!GET_TEAM(getTeam()).isAtWar(pLoopCity->getTeam()))
- {
- int iModifier = 2;
- if (!pLoopCity->plot()->isVisible(getTeam(),false))
- {
- iModifier++;
- }
- // if we don't already have a warplan for this foe, make sure we overwhelm them
- if (GET_TEAM(getTeam()).AI_getWarPlan(pLoopCity->getTeam()) == NO_WARPLAN)
- {
- iModifier = 5;
- }
- // if we're already at war - need to be really powerful to start a new one
- if (GET_TEAM(getTeam()).getAtWarCount(true) > 0)
- {
- iModifier *= 2;
- }
- int iGroupSize = 0;
- if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL"))
- {
- iGroupSize = getGroup()->getCargo();
- }
- else
- {
- iGroupSize = getGroup()->getNumUnits();
- }
- if (iGroupSize <= (iModifier * pLoopCity->plot()->getNumDefenders(pLoopCity->getOwner())))
- {
- if( gUnitLogLevel > 3 )
- {
- logBBAI(" ...zeroing out city value due to small group size(modifier %d - groupsize %d)", iModifier, iGroupSize);
- }
- iValue = 0;
- }
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestCity = pLoopCity;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestCity != NULL)
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" ...targeting city %S (final value: %d) \n", pBestCity->getName().GetCString(), iBestValue);
- }
- }
- return pBestCity;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_goToTargetCity(int iFlags, int iMaxPathTurns, CvCity* pTargetCity )
- {
- PROFILE_FUNC();
- CvPlot* pAdjacentPlot;
- CvPlot* pBestPlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iI;
- if( pTargetCity == NULL )
- {
- pTargetCity = AI_pickTargetCity(iFlags, iMaxPathTurns);
- }
- if (pTargetCity != NULL)
- {
- PROFILE("CvUnitAI::AI_targetCity plot attack");
- iBestValue = 0;
- pBestPlot = NULL;
- if (0 == (iFlags & MOVE_THROUGH_ENEMY))
- {
- for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- pAdjacentPlot = plotDirection(pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot != NULL)
- {
- if (getGroup()->canMoveThrough(pAdjacentPlot) && (pAdjacentPlot->isRevealed(getTeam(), false) || pAdjacentPlot->isAdjacentRevealed(getTeam())))
- {
- if (AI_plotValid(pAdjacentPlot))
- {
- if (!(pAdjacentPlot->isVisibleEnemyUnit(this)))
- {
- if (generatePath(pAdjacentPlot, iFlags, true, &iPathTurns))
- {
- if( iPathTurns <= iMaxPathTurns )
- {
- if ((getDuration() != 1) || // either we're not a temp unit about to expire
- ((bombardRate() <= 0) || // or we cant bombard
- (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
- ))
- {
- iValue = std::max(0, (pAdjacentPlot->defenseModifier(getTeam(), false) + 100));
- if (!(pAdjacentPlot->isRiverCrossing(directionXY(pAdjacentPlot, pTargetCity->plot()))))
- {
- iValue += (12 * -(GC.getRIVER_ATTACK_MODIFIER()));
- }
- if (!isEnemy(pAdjacentPlot->getTeam(), pAdjacentPlot))
- {
- iValue += 100;
- }
- if( atPlot(pAdjacentPlot) )
- {
- iValue += 50;
- }
- iValue = std::max(1, iValue);
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- else
- {
- pBestPlot = pTargetCity->plot();
- }
- if (pBestPlot != NULL)
- {
- FAssert(!(pTargetCity->at(pBestPlot)) || 0 != (iFlags & MOVE_THROUGH_ENEMY)); // no suicide missions...
- if (!atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), iFlags);
- return true;
- }
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_goToTargetBarbCity(int iMaxPathTurns)
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvCity* pBestCity;
- CvPlot* pAdjacentPlot;
- CvPlot* pBestPlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- int iI;
- if (isBarbarian() || GET_TEAM(getTeam()).isBarbarianAlly())
- {
- return false;
- }
- iBestValue = 0;
- pBestCity = NULL;
- for (pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- // BBAI efficiency: check area for land units before generating path
- if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
- {
- continue;
- }
- if (pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam()))
- {
- if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- if (iPathTurns < iMaxPathTurns)
- {
- iValue = GET_PLAYER(getOwnerINLINE()).AI_targetCityValue(pLoopCity, false);
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- iValue /= (1 + pLoopCity->plot()->getNumVisiblePotentialEnemyDefenders(this));
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestCity = pLoopCity;
- }
- }
- }
- }
- }
- }
- if (pBestCity != NULL)
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" %S (unit %d) (groupsize: %d) targeting Barb city %S \n", getName().GetCString(), getID(), getGroup()->getNumUnits(), pBestCity->getName().GetCString());
- }
- iBestValue = 0;
- pBestPlot = NULL;
- for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- pAdjacentPlot = plotDirection(pBestCity->getX_INLINE(), pBestCity->getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot != NULL)
- {
- if (AI_plotValid(pAdjacentPlot))
- {
- if (!(pAdjacentPlot->isVisibleEnemyUnit(this)))
- {
- if (generatePath(pAdjacentPlot, 0, true, &iPathTurns))
- {
- if( iPathTurns <= iMaxPathTurns )
- {
- iValue = std::max(0, (pAdjacentPlot->defenseModifier(getTeam(), false) + 100));
- if (!(pAdjacentPlot->isRiverCrossing(directionXY(pAdjacentPlot, pBestCity->plot()))))
- {
- iValue += (10 * -(GC.getRIVER_ATTACK_MODIFIER()));
- }
- iValue = std::max(1, iValue);
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!(pBestCity->at(pBestPlot))); // no suicide missions...
- if (atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- }
- }
- return false;
- }
- bool CvUnitAI::AI_pillageAroundCity(CvCity* pTargetCity, int iBonusValueThreshold, int iMaxPathTurns )
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestPillagePlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestPillagePlot = NULL;
- //>>>>Unofficial Bug Fix: Modified by Denev 2010/04/04
- // for( int iI = 0; iI < NUM_CITY_PLOTS; iI++ )
- for (int iI = 0; iI < pTargetCity->getNumCityPlots(); iI++)
- //<<<<Unofficial Bug Fix: End Modify
- {
- pLoopPlot = pTargetCity->getCityIndexPlot(iI);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot) && !(pLoopPlot->isBarbarian()))
- {
- if (potentialWarAction(pLoopPlot) && (pLoopPlot->getTeam() == pTargetCity->getTeam()))
- {
- if (getGroup()->canPillage(pLoopPlot))
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup()) == 0)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (getPathLastNode()->m_iData1 == 0)
- {
- iPathTurns++;
- }
- if ( iPathTurns <= iMaxPathTurns )
- {
- iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);
- iValue *= 1000 + 30*(pLoopPlot->defenseModifier(getTeam(),false));
- iValue /= (iPathTurns + 1);
- // if not at war with this plot owner, then devalue plot if we already inside this owner's borders
- // (because declaring war will pop us some unknown distance away)
- if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
- {
- iValue /= 10;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestPillagePlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
- {
- if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
- {
- //getGroup()->groupDeclareWar(pBestPillagePlot, true);
- // rather than declare war, just find something else to do, since we may already be deep in enemy territory
- return false;
- }
-
- if (atPlot(pBestPillagePlot))
- {
- if (isEnemy(pBestPillagePlot->getTeam()))
- {
- getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
- return true;
- }
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_bombardCity()
- {
- PROFILE_FUNC();
- CvCity* pBombardCity;
- bool bGroupCanBombard = false;
-
- CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- {
- if (pLoopUnit->canBombard(plot()))
- {
- bGroupCanBombard = true;
- break;
- }
- }
- }
- if (bGroupCanBombard)
- {
- pBombardCity = bombardTarget(plot());
- // Super Forts begin *bombard* (if statement contains original code for cities, else statement is new code for improvements)
- //FAssertMsg(pBombardCity != NULL, "BombardCity is not assigned a valid value"); //Removed for Super Forts
- if(pBombardCity != NULL)
- {
- // do not bombard cities with no defenders
- int iDefenderStrength = pBombardCity->plot()->AI_sumStrength(NO_PLAYER, getOwnerINLINE(), DOMAIN_LAND, /*bDefensiveBonuses*/ true, /*bTestAtWar*/ true, false);
- if (iDefenderStrength == 0)
- {
- return false;
- }
-
- // do not bombard cities if we have overwelming odds
- int iAttackOdds = getGroup()->AI_attackOdds(pBombardCity->plot(), /*bPotentialEnemy*/ true);
- if ( (iAttackOdds > 95) )
- {
- return false;
- }
- // If we have reasonable odds, check for attacking without waiting for bombards
- if( (iAttackOdds >= GC.getDefineINT("BBAI_SKIP_BOMBARD_BEST_ATTACK_ODDS")) )
- {
- int iBase = std::max(150, GC.getDefineINT("BBAI_SKIP_BOMBARD_BASE_STACK_RATIO"));
- int iComparison = getGroup()->AI_compareStacks(pBombardCity->plot(), /*bPotentialEnemy*/ true, /*bCheckCanAttack*/ true, /*bCheckCanMove*/ true);
-
- // Big troop advantage plus pretty good starting odds, don't wait to allow reinforcements
- /*
- if( iComparison > (iBase - 4*iAttackOdds) )
- {
- if( gUnitLogLevel > 2 ) logBBAI(" Stack skipping bombard of %S with compare %d and starting odds %d", pBombardCity->getName().GetCString(), iComparison, iAttackOdds);
- return false;
- }
- */
- int iMin = std::max(100, GC.getDefineINT("BBAI_SKIP_BOMBARD_MIN_STACK_RATIO"));
- bool bHasWaited = false;
- CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- if( pLoopUnit->getFortifyTurns() > 0 )
- {
- bHasWaited = true;
- break;
- }
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- }
- // Bombard at least one turn to allow bombers/ships to get some shots in too
- if( bHasWaited && (pBombardCity->getDefenseDamage() > 0) )
- {
- int iBombardTurns = getGroup()->getBombardTurns(pBombardCity);
- if( iComparison > std::max(iMin, iBase - 3*iAttackOdds - 3*iBombardTurns) )
- {
- 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);
- return false;
- }
- }
- }
- //getGroup()->pushMission(MISSION_PILLAGE);
- getGroup()->pushMission(MISSION_BOMBARD);
- return true;
- }
- else
- {
- CvPlot* pTargetPlot = bombardImprovementTarget(plot());
- // do not bombard cities with no defenders
- int iDefenderStrength = pTargetPlot->AI_sumStrength(NO_PLAYER, getOwnerINLINE(), DOMAIN_LAND, /*bDefensiveBonuses*/ true, /*bTestAtWar*/ true, false);
- if (iDefenderStrength == 0)
- {
- return false;
- }
-
- // do not bombard cities if we have overwelming odds
- int iAttackOdds = getGroup()->AI_attackOdds(pTargetPlot, /*bPotentialEnemy*/ true);
- if (iAttackOdds > 95)
- {
- return false;
- }
-
- // 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
- // we may not want to suffer high casualties just to save a turn
- //getGroup()->AI_compareStacks(pBombardCity->plot(), /*bPotentialEnemy*/ true, /*bCheckCanAttack*/ true, /*bCheckCanMove*/ true);
- //int iOurStrength = pBombardCity->plot()->AI_sumStrength(getOwnerINLINE(), NO_PLAYER, DOMAIN_LAND, false, false, false)
- if(pTargetPlot->getDefenseDamage() < ((GC.getImprovementInfo(pTargetPlot->getImprovementType()).getDefenseModifier() * 3) / 4))
- {
- getGroup()->pushMission(MISSION_BOMBARD);
- return true;
- }
- }
- // Super Forts end
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_cityAttack(int iRange, int iOddsThreshold, bool bFollow)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- FAssert(canMove());
- if (bFollow)
- {
- iSearchRange = 1;
- }
- else
- {
- iSearchRange = AI_searchRange(iRange);
- }
- iBestValue = 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- // Super Forts begin *AI_offense* - modified if statement so forts will be attacked too
- if (pLoopPlot->isCity(GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)))
- //if (pLoopPlot->isCity() || (pLoopPlot->isCity(true, getTeam()) && pLoopPlot->isVisibleEnemyUnit(this))) - Original Code
- // Super Forts end
- {
- if (AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
- {
- if (!atPlot(pLoopPlot) && ((bFollow) ? canMoveInto(pLoopPlot, true) : (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= iRange))))
- {
- iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
- if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
- {
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
- return true;
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 04/01/10 jdog5000 */
- /* */
- /* War tactics AI, Efficiency */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_anyAttack(int iRange, int iOddsThreshold, int iMinStack, bool bAllowCities, bool bFollow)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- FAssert(canMove());
- if (AI_rangeAttack(iRange))
- {
- return true;
- }
- if (bFollow)
- {
- iSearchRange = 1;
- }
- else
- {
- iSearchRange = AI_searchRange(iRange);
- }
- iBestValue = 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- if( (bAllowCities) || !(pLoopPlot->isCity(false)) )
- {
- if (pLoopPlot->isVisibleEnemyUnit(this))
- {
- if (pLoopPlot->getNumVisibleEnemyDefenders(this) >= iMinStack)
- {
- if (!atPlot(pLoopPlot) && ((bFollow) ? canMoveInto(pLoopPlot, true) : (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= iRange))))
- {
- // Sephi AI - Allows the Function to Check for Summoned Units
- bool bOnlySummons=true;
- CLLNode<IDInfo>* pUnitNode;
- CvUnit* pLoopUnit;
- pUnitNode = pLoopPlot->headUnitNode();
-
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
- if (pLoopUnit->getDuration()==0 || pLoopUnit->isPermanentSummon())
- {
- bOnlySummons=false;
- break;
- }
- }
- if (!bOnlySummons)
- {
- iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
- if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
- {
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- // End Sephi AI
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
- if( gUnitLogLevel >= 2 )
- {
- logBBAI( " Stack %d (led by %S (%d), size %d) attacking plot %d|%d", getGroup()->getID(), getName().GetCString(), getID(),
- getGroup()->getNumUnits(), pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE() );
- }
- return true;
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_rangeAttack(int iRange)
- {
- PROFILE_FUNC();
- FAssert(canMove());
- if (!canRangeStrike())
- {
- return false;
- }
- int iSearchRange = AI_searchRange(iRange);
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- for (int iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (int iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- // Super Forts begin *AI_offense* - modified if statement so forts will be attacked too
- if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity(GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)) && AI_potentialEnemy(pLoopPlot->getTeam())))
- //if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam()))) - Original Code
- // Super Forts end
- {
- if (!atPlot(pLoopPlot) && canRangeStrikeAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
- {
- int iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_RANGE_ATTACK, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0);
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_leaveAttack(int iRange, int iOddsThreshold, int iStrengthThreshold)
- {
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvCity* pCity;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- FAssert(canMove());
- iSearchRange = iRange;
- iBestValue = 0;
- pBestPlot = NULL;
- pCity = plot()->getPlotCity();
- if ((pCity != NULL) && (pCity->getOwnerINLINE() == getOwnerINLINE()))
- {
- int iOurStrength = GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(), 0, false, false);
- int iEnemyStrength = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(), 2, false, false);
- if (iEnemyStrength > 0)
- {
- if (((iOurStrength * 100) / iEnemyStrength) < iStrengthThreshold)
- {
- return false;
- }
- if (plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE()) <= getGroup()->getNumUnits())
- {
- return false;
- }
- }
- }
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- // Super Forts begin *AI_offense* - modified if statement so forts will be attacked too
- if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity(GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)) && AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot)))
- //if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot))) - Original code
- // Super Forts end
- {
- if (pLoopPlot->getNumVisibleEnemyDefenders(this) > 0)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 06/27/10 jdog5000 */
- /* */
- /* Bugfix */
- /************************************************************************************************/
- if (!atPlot(pLoopPlot) && (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= iRange)))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
-
- iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
- if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
- {
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0);
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_blockade()
- {
- PROFILE_FUNC();
- CvCity* pCity;
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestBlockadePlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iI;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestBlockadePlot = NULL;
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (potentialWarAction(pLoopPlot))
- {
- pCity = pLoopPlot->getWorkingCity();
- if (pCity != NULL)
- {
- if (pCity->isCoastal(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
- {
- if (!(pCity->isBarbarian()))
- {
- FAssert(isEnemy(pCity->getTeam()) || GET_TEAM(getTeam()).AI_getWarPlan(pCity->getTeam()) != NO_WARPLAN);
- if (!(pLoopPlot->isVisibleEnemyUnit(this)) && canPlunder(pLoopPlot))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BLOCKADE, getGroup(), 2) == 0)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue = 1;
- iValue += std::min(pCity->getPopulation(), pCity->countNumWaterPlots());
- iValue += GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pCity->plot());
- iValue += (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCity->plot(), MISSIONAI_ASSAULT, getGroup(), 2) * 3);
- if (canBombard(pLoopPlot))
- {
- iValue *= 2;
- }
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- if (iPathTurns == 1)
- {
- //Prefer to have movement remaining to Bombard + Plunder
- iValue *= 1 + std::min(2, getPathLastNode()->m_iData1);
- }
- // if not at war with this plot owner, then devalue plot if we already inside this owner's borders
- // (because declaring war will pop us some unknown distance away)
- if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
- {
- iValue /= 10;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestBlockadePlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestBlockadePlot != NULL))
- {
- FAssert(canPlunder(pBestBlockadePlot));
- if (atPlot(pBestBlockadePlot) && !isEnemy(pBestBlockadePlot->getTeam(), pBestBlockadePlot))
- {
- getGroup()->groupDeclareWar(pBestBlockadePlot, true);
- }
- if (atPlot(pBestBlockadePlot))
- {
- if (canBombard(plot()))
- {
- getGroup()->pushMission(MISSION_BOMBARD, -1, -1, 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
- }
- getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_pirateBlockade()
- {
- PROFILE_FUNC();
- int iPathTurns;
- int iValue;
- int iI;
- std::vector<int> aiDeathZone(GC.getMapINLINE().numPlotsINLINE(), 0);
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot) || (pLoopPlot->isCity() && pLoopPlot->isAdjacentToArea(area())))
- {
- if (pLoopPlot->isOwned() && (pLoopPlot->getTeam() != getTeam()))
- {
- int iBestHostileMoves = 0;
- CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
- if (isEnemy(pLoopUnit->getTeam(), pLoopUnit->plot()))
- {
- if (pLoopUnit->getDomainType() == DOMAIN_SEA && !pLoopUnit->isInvisible(getTeam(), false))
- {
- if (pLoopUnit->canAttack())
- {
- if (pLoopUnit->currEffectiveStr(NULL, NULL, NULL) > currEffectiveStr(pLoopPlot, pLoopUnit, NULL))
- {
- iBestHostileMoves = std::max(iBestHostileMoves, pLoopUnit->getMoves());
- }
- }
- }
- }
- }
- if (iBestHostileMoves > 0)
- {
- for (int iX = -iBestHostileMoves; iX <= iBestHostileMoves; iX++)
- {
- for (int iY = -iBestHostileMoves; iY <= iBestHostileMoves; iY++)
- {
- CvPlot * pRangePlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iX, iY);
- if (pRangePlot != NULL)
- {
- aiDeathZone[GC.getMap().plotNumINLINE(pRangePlot->getX_INLINE(), pRangePlot->getY_INLINE())]++;
- }
- }
- }
- }
- }
- }
- }
- bool bIsInDanger = aiDeathZone[GC.getMap().plotNumINLINE(getX_INLINE(), getY_INLINE())] > 0;
- if (!bIsInDanger)
- {
- if (getDamage() > 0)
- {
- if (!plot()->isOwned() && !plot()->isAdjacentOwned())
- {
- if (AI_retreatToCity(false, false, 1 + getDamage() / 20))
- {
- return true;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- }
- }
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestBlockadePlot = NULL;
- bool bBestIsForceMove = false;
- bool bBestIsMove = false;
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)) && canPlunder(pLoopPlot))
- {
- if (GC.getGame().getSorenRandNum(4, "AI Pirate Blockade") == 0)
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BLOCKADE, getGroup(), 3) == 0)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/17/09 jdog5000 */
- /* */
- /* Pirate AI */
- /************************************************************************************************/
- /* original bts code
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- */
- if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- int iBlockadedCount = 0;
- int iPopulationValue = 0;
- int iRange = GC.getDefineINT("SHIP_BLOCKADE_RANGE") - 1;
- for (int iX = -iRange; iX <= iRange; iX++)
- {
- for (int iY = -iRange; iY <= iRange; iY++)
- {
- CvPlot* pRangePlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iX, iY);
- if (pRangePlot != NULL)
- {
- bool bPlotBlockaded = false;
- if (pRangePlot->isWater() && pRangePlot->isOwned() && isEnemy(pRangePlot->getTeam(), pLoopPlot))
- {
- bPlotBlockaded = true;
- iBlockadedCount += pRangePlot->getBlockadedCount(pRangePlot->getTeam());
- }
- if (!bPlotBlockaded)
- {
- CvCity* pPlotCity = pRangePlot->getPlotCity();
- if (pPlotCity != NULL)
- {
- if (isEnemy(pPlotCity->getTeam(), pLoopPlot))
- {
- int iCityValue = 3 + pPlotCity->getPopulation();
- iCityValue *= (atWar(getTeam(), pPlotCity->getTeam()) ? 1 : 3);
- if (GET_PLAYER(pPlotCity->getOwnerINLINE()).isNoForeignTrade())
- {
- iCityValue /= 2;
- }
- iPopulationValue += iCityValue;
- }
- }
- }
- }
- }
- }
- iValue = iPopulationValue;
- iValue *= 1000;
- iValue /= 16 + iBlockadedCount;
- bool bMove = ((getPathLastNode()->m_iData2 == 1) && getPathLastNode()->m_iData1 > 0);
- if (atPlot(pLoopPlot))
- {
- iValue *= 3;
- }
- else if (bMove)
- {
- iValue *= 2;
- }
- int iDeath = aiDeathZone[GC.getMap().plotNumINLINE(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE())];
- bool bForceMove = false;
- if (iDeath)
- {
- iValue /= 10;
- }
- else if (bIsInDanger && (iPathTurns <= 2) && (0 == iPopulationValue))
- {
- if (getPathLastNode()->m_iData1 == 0)
- {
- if (!pLoopPlot->isAdjacentOwned())
- {
- int iRand = GC.getGame().getSorenRandNum(2500, "AI Pirate Retreat");
- iValue += iRand;
- if (iRand > 1000)
- {
- iValue += GC.getGame().getSorenRandNum(2500, "AI Pirate Retreat");
- bForceMove = true;
- }
- }
- }
- }
- if (!bForceMove)
- {
- iValue /= iPathTurns + 1;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = bForceMove ? pLoopPlot : getPathEndTurnPlot();
- pBestBlockadePlot = pLoopPlot;
- bBestIsForceMove = bForceMove;
- bBestIsMove = bMove;
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestBlockadePlot != NULL))
- {
- FAssert(canPlunder(pBestBlockadePlot));
- if (atPlot(pBestBlockadePlot))
- {
- getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- if (bBestIsForceMove)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/01/09 jdog5000 */
- /* */
- /* Pirate AI */
- /************************************************************************************************/
- /* original bts code
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- */
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- return true;
- }
- else
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/01/09 jdog5000 */
- /* */
- /* Pirate AI */
- /************************************************************************************************/
- /* original bts code
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
- */
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (bBestIsMove)
- {
- getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
- }
- return true;
- }
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_seaBombardRange(int iMaxRange)
- {
- PROFILE_FUNC();
- // cached values
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- CvPlot* pPlot = plot();
- CvSelectionGroup* pGroup = getGroup();
- // can any unit in this group bombard?
- bool bHasBombardUnit = false;
- bool bBombardUnitCanBombardNow = false;
- CLLNode<IDInfo>* pUnitNode = pGroup->headUnitNode();
- while (pUnitNode != NULL && !bBombardUnitCanBombardNow)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pGroup->nextUnitNode(pUnitNode);
- if (pLoopUnit->bombardRate() > 0)
- {
- bHasBombardUnit = true;
- if (pLoopUnit->canMove() && !pLoopUnit->isMadeAttack())
- {
- bBombardUnitCanBombardNow = true;
- }
- }
- }
- if (!bHasBombardUnit)
- {
- return false;
- }
- // best match
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestBombardPlot = NULL;
- int iBestValue = 0;
- // iterate over plots at each range
- for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
- {
- for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
- {
- CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL && AI_plotValid(pLoopPlot))
- {
- CvCity* pBombardCity = bombardTarget(pLoopPlot);
- if (pBombardCity != NULL && isEnemy(pBombardCity->getTeam(), pLoopPlot) && pBombardCity->getDefenseDamage() < GC.getMAX_CITY_DEFENSE_DAMAGE())
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 6/24/08 jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- // Loop construction doesn't guarantee we can get there anytime soon, could be on other side of narrow continent
- if( iPathTurns <= (1 + iMaxRange/std::max(1, baseMoves())) )
- {
- // Check only for supporting our own ground troops first, if none will look for another target
- int iValue = (kPlayer.AI_plotTargetMissionAIs(pBombardCity->plot(), MISSIONAI_ASSAULT, NULL, 2) * 3);
- iValue += (kPlayer.AI_adjacentPotentialAttackers(pBombardCity->plot(), true));
-
- if (iValue > 0)
- {
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
-
- if (iPathTurns == 1)
- {
- //Prefer to have movement remaining to Bombard + Plunder
- iValue *= 1 + std::min(2, getPathLastNode()->m_iData1);
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestBombardPlot = pLoopPlot;
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- }
- }
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 6/24/08 jdog5000 */
- /* */
- /* Naval AI */
- /********************************************************************************/
- // If no troops of ours to support, check for other bombard targets
- if( (pBestPlot == NULL) && (pBestBombardPlot == NULL) )
- {
- if( (AI_getUnitAIType() != UNITAI_ASSAULT_SEA) )
- {
- for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
- {
- for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
- {
- CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
-
- if (pLoopPlot != NULL && AI_plotValid(pLoopPlot))
- {
- CvCity* pBombardCity = bombardTarget(pLoopPlot);
- // Consider city even if fully bombarded, causes ship to camp outside blockading instead of twitching between
- // cities after bombarding to 0
- if (pBombardCity != NULL && isEnemy(pBombardCity->getTeam(), pLoopPlot) && pBombardCity->getTotalDefense(false) > 0)
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- // Loop construction doesn't guarantee we can get there anytime soon, could be on other side of narrow continent
- if( iPathTurns <= 1 + iMaxRange/std::max(1, baseMoves()) )
- {
- int iValue = std::min(20,pBombardCity->getDefenseModifier(false)/2);
- // Inclination to support attacks by others
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if( GET_PLAYER(pBombardCity->getOwnerINLINE()).AI_getPlotDanger(pBombardCity->plot(), 2, false) > 0 )
- if( GET_PLAYER(pBombardCity->getOwnerINLINE()).AI_getAnyPlotDanger(pBombardCity->plot(), 2, false) )
- {
- iValue += 60;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Inclination to bombard a different nearby city to extend the reach of blockade
- if( GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pBombardCity->plot(), MISSIONAI_BLOCKADE, getGroup(), 3) == 0 )
- {
- iValue += 35 + pBombardCity->getPopulation();
- }
- // Small inclination to bombard area target, not too large so as not to tip our hand
- if( pBombardCity == pBombardCity->area()->getTargetCity(getOwnerINLINE()) )
- {
- iValue += 10;
- }
-
- if (iValue > 0)
- {
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
-
- if (iPathTurns == 1)
- {
- //Prefer to have movement remaining to Bombard + Plunder
- iValue *= 1 + std::min(2, getPathLastNode()->m_iData1);
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestBombardPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
-
- if ((pBestPlot != NULL) && (pBestBombardPlot != NULL))
- {
- if (atPlot(pBestBombardPlot))
- {
- // if we are at the plot from which to bombard, and we have a unit that can bombard this turn, do it
- if (bBombardUnitCanBombardNow && pGroup->canBombard(pBestBombardPlot))
- {
- getGroup()->pushMission(MISSION_BOMBARD, -1, -1, 0, false, false, MISSIONAI_BLOCKADE, pBestBombardPlot);
- // if city bombarded enough, wake up any units that were waiting to bombard this city
- CvCity* pBombardCity = bombardTarget(pBestBombardPlot); // is NULL if city cannot be bombarded any more
- if (pBombardCity == NULL || pBombardCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE()*5)/6))
- {
- kPlayer.AI_wakePlotTargetMissionAIs(pBestBombardPlot, MISSIONAI_BLOCKADE, getGroup());
- }
- }
- // otherwise, skip until next turn, when we will surely bombard
- else if (canPlunder(pBestBombardPlot))
- {
- getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, false, false, MISSIONAI_BLOCKADE, pBestBombardPlot);
- }
- else
- {
- getGroup()->pushMission(MISSION_SKIP);
- }
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBombardPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_pillage(int iBonusValueThreshold)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestPillagePlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iI;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestPillagePlot = NULL;
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot) && !(pLoopPlot->isBarbarian()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if (potentialWarAction(pLoopPlot))
- if( pLoopPlot->isOwned() && isEnemy(pLoopPlot->getTeam(),pLoopPlot) )
- {
- CvCity * pWorkingCity = pLoopPlot->getWorkingCity();
- if (pWorkingCity != NULL)
- {
- if (!(pWorkingCity == area()->getTargetCity(getOwnerINLINE())) && canPillage(pLoopPlot))
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup(), 1) == 0)
- {
- iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);
- iValue *= 1000;
- // if not at war with this plot owner, then devalue plot if we already inside this owner's borders
- // (because declaring war will pop us some unknown distance away)
- if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
- {
- iValue /= 10;
- }
- if( iValue > iBestValue )
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestPillagePlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
- {
- if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
- {
- //getGroup()->groupDeclareWar(pBestPillagePlot, true);
- // rather than declare war, just find something else to do, since we may already be deep in enemy territory
- return false;
- }
- if (atPlot(pBestPillagePlot))
- {
- if (isEnemy(pBestPillagePlot->getTeam()))
- {
- getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
- return true;
- }
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
- return true;
- }
- }
- return false;
- }
- bool CvUnitAI::AI_canPillage(CvPlot& kPlot) const
- {
- if (isEnemy(kPlot.getTeam(), &kPlot))
- {
- return true;
- }
- if (!kPlot.isOwned())
- {
- bool bPillageUnowned = true;
- for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS && bPillageUnowned; ++iPlayer)
- {
- int iIndx;
- CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iPlayer);
- if (!isEnemy(kLoopPlayer.getTeam(), &kPlot))
- {
- for (CvCity* pCity = kLoopPlayer.firstCity(&iIndx); NULL != pCity; pCity = kLoopPlayer.nextCity(&iIndx))
- {
- if (kPlot.getPlotGroup((PlayerTypes)iPlayer) == pCity->plot()->getPlotGroup((PlayerTypes)iPlayer))
- {
- bPillageUnowned = false;
- break;
- }
- }
- }
- }
- if (bPillageUnowned)
- {
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_pillageRange(int iRange, int iBonusValueThreshold)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestPillagePlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- iSearchRange = AI_searchRange(iRange);
- iBestValue = 0;
- pBestPlot = NULL;
- pBestPillagePlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot) && !(pLoopPlot->isBarbarian()))
- {
- if (potentialWarAction(pLoopPlot))
- {
- CvCity * pWorkingCity = pLoopPlot->getWorkingCity();
- if (pWorkingCity != NULL)
- {
- if (!(pWorkingCity == area()->getTargetCity(getOwnerINLINE())) && getGroup()->canPillage(pLoopPlot))
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup()) == 0)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (getPathLastNode()->m_iData1 == 0)
- {
- iPathTurns++;
- }
- if (iPathTurns <= iRange)
- {
- iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- // if not at war with this plot owner, then devalue plot if we already inside this owner's borders
- // (because declaring war will pop us some unknown distance away)
- if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
- {
- iValue /= 10;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- //pBestPlot = getPathEndTurnPlot();
- pBestPlot = pLoopPlot;
- pBestPillagePlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
- {
- if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
- {
- //getGroup()->groupDeclareWar(pBestPillagePlot, true);
- // rather than declare war, just find something else to do, since we may already be deep in enemy territory
- return false;
- }
- if (atPlot(pBestPillagePlot))
- {
- if (isEnemy(pBestPillagePlot->getTeam()))
- {
- getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
- return true;
- }
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_found()
- {
- PROFILE_FUNC();
- //
- // CvPlot* pLoopPlot;
- // CvPlot* pBestPlot;
- // CvPlot* pBestFoundPlot;
- // int iPathTurns;
- // int iValue;
- // int iBestValue;
- // int iI;
- //
- // iBestValue = 0;
- // pBestPlot = NULL;
- // pBestFoundPlot = NULL;
- //
- // for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- // {
- // pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- //
- // if (AI_plotValid(pLoopPlot) && (pLoopPlot != plot() || GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopPlot, 1) <= pLoopPlot->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE())))
- // {
- // if (canFound(pLoopPlot))
- // {
- // iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
- //
- // if (iValue > 0)
- // {
- // if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- // {
- // if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_FOUND, getGroup(), 3) == 0)
- // {
- // if (generatePath(pLoopPlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
- // {
- // iValue *= 1000;
- //
- // iValue /= (iPathTurns + 1);
- //
- // if (iValue > iBestValue)
- // {
- // iBestValue = iValue;
- // pBestPlot = getPathEndTurnPlot();
- // pBestFoundPlot = pLoopPlot;
- // }
- // }
- // }
- // }
- // }
- // }
- // }
- // }
- int iPathTurns;
- int iValue;
- int iBestFoundValue = 0;
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestFoundPlot = NULL;
- for (int iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
- {
- CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 10/23/09 jdog5000 */
- /* */
- /* Settler AI */
- /************************************************************************************************/
- /* orginal BTS code
- if (pCitySitePlot->getArea() == getArea())
- */
- if (pCitySitePlot->getArea() == getArea() || canMoveAllTerrain())
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- if (canFound(pCitySitePlot))
- {
- if (!(pCitySitePlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_FOUND, getGroup()) == 0)
- {
- if (getGroup()->canDefend() || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_GUARD_CITY) > 0)
- {
- if (generatePath(pCitySitePlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
- {
- iValue = pCitySitePlot->getFoundValue(getOwnerINLINE());
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestFoundValue)
- {
- iBestFoundValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestFoundPlot = pCitySitePlot;
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
- {
- if (atPlot(pBestFoundPlot))
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Settler founding at best found plot %d, %d", pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE());
- }
- getGroup()->pushMission(MISSION_FOUND, -1, -1, 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
- return true;
- }
- else
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Settler heading for best found plot %d, %d", pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE());
- }
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_FOUND, pBestFoundPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_foundRange(int iRange, bool bFollow)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestFoundPlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- iSearchRange = AI_searchRange(iRange);
- iBestValue = 0;
- pBestPlot = NULL;
- pBestFoundPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot) && (pLoopPlot != plot() || GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopPlot, 1) <= pLoopPlot->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE())))
- {
- if (canFound(pLoopPlot))
- {
- iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
- if (iValue > iBestValue)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_FOUND, getGroup(), 3) == 0)
- {
- if (generatePath(pLoopPlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
- {
- if (iPathTurns <= iRange)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestFoundPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
- {
- if (atPlot(pBestFoundPlot))
- {
- getGroup()->pushMission(MISSION_FOUND, -1, -1, 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
- return true;
- }
- else if (!bFollow)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_FOUND, pBestFoundPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_assaultSeaTransport(bool bBarbarian)
- {
- PROFILE_FUNC();
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_assaultSeaTransport", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- bool bIsAttackCity = (getUnitAICargo(UNITAI_ATTACK_CITY) > 0);
- FAssert(getGroup()->hasCargo());
- //FAssert(bIsAttackCity || getGroup()->getUnitAICargo(UNITAI_ATTACK) > 0);
- if (!canCargoAllMove())
- {
- if( gUnitLogLevel >= 4 ) logBBAI(" ...CANT MOVE!");
- return false;
- }
- if (getGroup()->AI_getMissionAIType() == MISSIONAI_ASSAULT)
- {
- if (getPathLastNode() != NULL)
- {
- if( gUnitLogLevel >= 4 ) logBBAI(" ...continuing mission to plot %d, %d", getPathEndTurnPlot()->getX(), getPathEndTurnPlot()->getY());
- getGroup()->pushMission(MISSION_MOVE_TO, getPathEndTurnPlot()->getX(), getPathEndTurnPlot()->getY(), MOVE_AVOID_ENEMY_WEIGHT_3);
- }
- else
- {
- if( gUnitLogLevel >= 4 ) logBBAI(" ...continuing mission to assault plot %d, %d", getGroup()->AI_getMissionAIPlot()->getX(), getGroup()->AI_getMissionAIPlot()->getY());
- getGroup()->pushMission(MISSION_MOVE_TO, getGroup()->AI_getMissionAIPlot()->getX(), getGroup()->AI_getMissionAIPlot()->getY(), MOVE_AVOID_ENEMY_WEIGHT_3);
- }
- return true;
- }
- std::vector<CvUnit*> aGroupCargo;
- CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = plot()->nextUnitNode(pUnitNode);
- CvUnit* pTransport = pLoopUnit->getTransportUnit();
- if (pTransport != NULL && pTransport->getGroup() == getGroup())
- {
- aGroupCargo.push_back(pLoopUnit);
- }
- }
- int iCargo = getGroup()->getCargo();
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestAssaultPlot = NULL;
- for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (pLoopPlot->isRevealed(getTeam(), false) && pLoopPlot->isCoastalLand()) // K-Mod
- {
- if (pLoopPlot->isOwned())
- {
- //if (((bBarbarian || !pLoopPlot->isBarbarian())) || GET_PLAYER(getOwnerINLINE()).isMinorCiv())
- //if (!(bBarbarian && pLoopPlot->isBarbarian()))
- {
- if (isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
- {
- int iTargetCities = pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE());
- if (iTargetCities > 0)
- {
- bool bCanCargoAllUnload = true;
- int iVisibleEnemyDefenders = pLoopPlot->getNumVisibleEnemyDefenders(this);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 11/30/08 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- if (iVisibleEnemyDefenders > 0 || pLoopPlot->isCity())
- {
- for (uint i = 0; i < aGroupCargo.size(); ++i)
- {
- CvUnit* pAttacker = aGroupCargo[i];
- if( iVisibleEnemyDefenders > 0 )
- {
- CvUnit* pDefender = pLoopPlot->getBestDefender(NO_PLAYER, pAttacker->getOwnerINLINE(), pAttacker, true);
- if (pDefender == NULL || !pAttacker->canAttack(*pDefender) || !pAttacker->isAmphib())
- {
- bCanCargoAllUnload = false;
- break;
- }
- }
- else if( pLoopPlot->isCity() && !(pLoopPlot->isVisible(getTeam(),false)) )
- {
- // Assume city is defended, artillery can't naval invade
- if(( pAttacker->combatLimit() < 100 ) || !pAttacker->isAmphib())
- {
- bCanCargoAllUnload = false;
- break;
- }
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (bCanCargoAllUnload)
- {
- int iPathTurns;
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/17/09 jdog5000 */
- /* */
- /* War tactics AI */
- /************************************************************************************************/
- /* original bts code
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- */
- if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- int iValue = 1;
- if (!bIsAttackCity)
- {
- iValue += (AI_pillageValue(pLoopPlot, 15) * 10);
- }
- int iAssaultsHere = GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ASSAULT, getGroup());
- iValue += (iAssaultsHere * 100);
- CvCity* pCity = pLoopPlot->getPlotCity();
- if (pCity == NULL)
- {
- for (int iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
- {
- CvPlot* pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iJ));
- if (pAdjacentPlot != NULL)
- {
- pCity = pAdjacentPlot->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == pLoopPlot->getOwnerINLINE())
- {
- break;
- }
- else
- {
- pCity = NULL;
- }
- }
- }
- }
- }
- if (pCity != NULL)
- {
- FAssert(isPotentialEnemy(pCity->getTeam(), pLoopPlot));
- if (!(pLoopPlot->isRiverCrossing(directionXY(pLoopPlot, pCity->plot()))))
- {
- iValue += (50 * -(GC.getRIVER_ATTACK_MODIFIER()));
- }
- iValue += 15 * (pLoopPlot->defenseModifier(getTeam(), false));
- iValue += 1000;
- iValue += (GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pCity->plot()) * 200);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/26/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- // Continue attacking in area we have already captured cities
- if( pCity->area()->getCitiesPerPlayer(getOwnerINLINE()) > 0 )
- {
- if( pCity->AI_playerCloseness(getOwnerINLINE()) > 5 )
- {
- iValue *= 3;
- iValue /= 2;
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (iPathTurns == 1)
- {
- iValue += GC.getGameINLINE().getSorenRandNum(50, "AI Assault");
- }
- }
- FAssert(iPathTurns > 0);
- if (iPathTurns == 1)
- {
- if (pCity != NULL)
- {
- if (pCity->area()->getNumCities() > 1)
- {
- iValue *= 2;
- }
- }
- }
- iValue *= 1000;
- if (iTargetCities <= iAssaultsHere)
- {
- iValue /= 2;
- }
- if (iTargetCities == 1)
- {
- if (iCargo > 7)
- {
- iValue *= 3;
- iValue /= iCargo - 4;
- }
- }
- if (pLoopPlot->isCity())
- {
- if (iVisibleEnemyDefenders * 3 > iCargo)
- {
- iValue /= 10;
- }
- else
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 11/30/08 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- /*
- // original bts code
- iValue *= iCargo;
- iValue /= std::max(1, (iVisibleEnemyDefenders * 3));
- */
- // Assume non-visible city is properly defended
- iValue *= (iCargo / 2);
- iValue /= std::max(pLoopPlot->getPlotCity()->AI_neededDefenders(), (iVisibleEnemyDefenders * 3));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- }
- else
- {
- if (0 == iVisibleEnemyDefenders)
- {
- iValue *= 4;
- iValue /= 3;
- }
- else
- {
- iValue /= iVisibleEnemyDefenders;
- }
- }
- // if more than 3 turns to get there, then put some randomness into our preference of distance
- // +/- 33%
- if (iPathTurns > 3)
- {
- int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");
- iPathTurns *= 66 + iPathAdjustment;
- iPathTurns /= 100;
- }
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestAssaultPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestAssaultPlot != NULL))
- {
- FAssert(!(pBestPlot->isImpassable()));
- // BETTER_BTS_AI_MOD - War tactics AI
- // Cancel missions of all those coming to join departing transport
- CvSelectionGroup* pLoopGroup = NULL;
- int iLoop = 0;
- CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
- for(pLoopGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = kPlayer.nextSelectionGroup(&iLoop))
- {
- if( pLoopGroup != getGroup() )
- {
- if( pLoopGroup->AI_getMissionAIType() == MISSIONAI_GROUP && pLoopGroup->getHeadUnitAI() == AI_getUnitAIType() )
- {
- CvUnit* pMissionUnit = pLoopGroup->AI_getMissionAIUnit();
- if( pMissionUnit != NULL && pMissionUnit->getGroup() == getGroup() )
- {
- pLoopGroup->clearMissionQueue();
- }
- }
- }
- }
- // BETTER_BTS_AI_MOD END
- //if ((pBestPlot == pBestAssaultPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE()) == 1))
- if (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE()) == 1)
- {
- if (atPlot(pBestAssaultPlot))
- {
- logBBAI(" ...unloading at %d, %d", pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE());
- getGroup()->unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
- return true;
- }
- else
- {
- // BETTER_BTS_AI_MOD - War tactics AI
- /* original bts code
- getGroup()->pushMission(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), 0, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
- */
- if( gUnitLogLevel >= 4 ) logBBAI(" ...moving to assault %d, %d", pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE());
- getGroup()->pushMission(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
- // BETTER_BTS_AI_MOD END
- return true;
- }
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- // BETTER_BTS_AI_MOD - War tactics AI
- /* original bts code
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
- */
- //getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
- getGroup()->pushMission(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
- // BETTER_BTS_AI_MOD END
- return true;
- }
- }
- if( gUnitLogLevel >= 4 ) logBBAI(" ...failing assault sea transport check");
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/07/10 jdog5000 */
- /* */
- /* Naval AI, Efficiency */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_assaultSeaReinforce(bool bBarbarian)
- {
- PROFILE_FUNC();
- bool bIsAttackCity = (getUnitAICargo(UNITAI_ATTACK_CITY) > 0);
-
- FAssert(getGroup()->hasCargo());
- if (!canCargoAllMove())
- {
- return false;
- }
- if( !(getGroup()->canAllMove()) )
- {
- return false;
- }
- std::vector<CvUnit*> aGroupCargo;
- CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = plot()->nextUnitNode(pUnitNode);
- CvUnit* pTransport = pLoopUnit->getTransportUnit();
- if (pTransport != NULL && pTransport->getGroup() == getGroup())
- {
- aGroupCargo.push_back(pLoopUnit);
- }
- }
- int iCargo = getGroup()->getCargo();
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestAssaultPlot = NULL;
- CvArea* pWaterArea = plot()->waterArea();
- bool bCity = plot()->isCity(true,getTeam());
- bool bCanMoveAllTerrain = getGroup()->canMoveAllTerrain();
- int iTargetCities;
- int iOurFightersHere;
- int iPathTurns;
- int iValue;
-
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_assaultSeaReinforce", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
-
- // Loop over nearby plots for groups in enemy territory to reinforce
- int iRange = 2*baseMoves();
- int iDX, iDY;
- for (iDX = -(iRange); iDX <= iRange; iDX++)
- {
- for (iDY = -(iRange); iDY <= iRange; iDY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if( pLoopPlot != NULL )
- {
- if (pLoopPlot->isOwned())
- {
- if (isEnemy(pLoopPlot->getTeam(), pLoopPlot))
- {
- if ( bCanMoveAllTerrain || (pWaterArea != NULL && pLoopPlot->isAdjacentToArea(pWaterArea)) )
- {
- iTargetCities = pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE());
-
- if (iTargetCities > 0)
- {
- iOurFightersHere = pLoopPlot->getNumDefenders(getOwnerINLINE());
- if( iOurFightersHere > 2 )
- {
- iPathTurns;
- if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
- {
- if( iPathTurns <= 2 )
- {
- CvPlot* pEndTurnPlot = getPathEndTurnPlot();
- iValue = 10*iTargetCities;
- iValue += 8*iOurFightersHere;
- iValue += 3*GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);
- iValue *= 100;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pEndTurnPlot;
- pBestAssaultPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- // Loop over other transport groups, looking for synchronized landing
- if ((pBestPlot == NULL) && (pBestAssaultPlot == NULL))
- {
- int iLoop;
- for(CvSelectionGroup* pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).firstSelectionGroup(&iLoop); pLoopSelectionGroup; pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).nextSelectionGroup(&iLoop))
- {
- if (pLoopSelectionGroup != getGroup())
- {
- if (pLoopSelectionGroup->AI_getMissionAIType() == MISSIONAI_ASSAULT)
- {
- CvPlot* pLoopPlot = pLoopSelectionGroup->AI_getMissionAIPlot();
- if( pLoopPlot != NULL )
- {
- if (pLoopPlot->isOwned())
- {
- if (isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
- {
- if ( bCanMoveAllTerrain || (pWaterArea != NULL && pLoopPlot->isAdjacentToArea(pWaterArea)) )
- {
- iTargetCities = pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE());
- if (iTargetCities > 0)
- {
- int iAssaultsHere = pLoopSelectionGroup->getCargo();
-
- if( iAssaultsHere > 2 )
- {
- iPathTurns;
- if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
- {
- CvPlot* pEndTurnPlot = getPathEndTurnPlot();
-
- int iOtherPathTurns = MAX_INT;
- if (pLoopSelectionGroup->generatePath(pLoopSelectionGroup->plot(), pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iOtherPathTurns))
- {
- // We need to get there the turn after they do, +1 required whether
- // they move first or we do
- iOtherPathTurns += 1;
- }
- else
- {
- // Should never happen ...
- continue;
- }
- if( (iPathTurns >= iOtherPathTurns) && (iPathTurns < iOtherPathTurns + 5) )
- {
- bool bCanCargoAllUnload = true;
- int iVisibleEnemyDefenders = pLoopPlot->getNumVisibleEnemyDefenders(this);
- if (iVisibleEnemyDefenders > 0 || pLoopPlot->isCity())
- {
- for (uint i = 0; i < aGroupCargo.size(); ++i)
- {
- CvUnit* pAttacker = aGroupCargo[i];
- CvUnit* pDefender = pLoopPlot->getBestDefender(NO_PLAYER, pAttacker->getOwnerINLINE(), pAttacker, true);
- if (pDefender == NULL || !pAttacker->canAttack(*pDefender))
- {
- bCanCargoAllUnload = false;
- break;
- }
- else if( pLoopPlot->isCity() && !(pLoopPlot->isVisible(getTeam(),false)) )
- {
- // Artillery can't naval invade, so don't try
- if( pAttacker->combatLimit() < 100 )
- {
- bCanCargoAllUnload = false;
- break;
- }
- }
- }
- }
- iValue = (iAssaultsHere * 5);
- iValue += iTargetCities*10;
- iValue *= 100;
- // if more than 3 turns to get there, then put some randomness into our preference of distance
- // +/- 33%
- if (iPathTurns > 3)
- {
- int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");
- iPathTurns *= 66 + iPathAdjustment;
- iPathTurns /= 100;
- }
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pEndTurnPlot;
- pBestAssaultPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- // Reinforce our cities in need
- if ((pBestPlot == NULL) && (pBestAssaultPlot == NULL))
- {
- int iLoop;
- CvCity* pLoopCity;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if( bCanMoveAllTerrain || (pWaterArea != NULL && (pLoopCity->waterArea(true) == pWaterArea || pLoopCity->secondWaterArea() == pWaterArea)) )
- {
- iValue = 0;
- if(pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE)
- {
- iValue = 3;
- }
- else if(pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
- {
- iValue = 2;
- }
- else if(pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_MASSING)
- {
- iValue = 1;
- }
- else if( bBarbarian && (pLoopCity->area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0) )
- {
- iValue = 1;
- }
- if( iValue > 0 )
- {
- bool bCityDanger = pLoopCity->AI_isDanger();
- if( (bCity && pLoopCity->area() != area()) || bCityDanger || ((GC.getGameINLINE().getGameTurn() - pLoopCity->getGameTurnAcquired()) < 10 && pLoopCity->getPreviousOwner() != NO_PLAYER) )
- {
- int iOurPower = std::max(1, pLoopCity->area()->getPower(getOwnerINLINE()));
- // Enemy power includes barb power
- int iEnemyPower = GET_TEAM(getTeam()).countEnemyPowerByArea(pLoopCity->area());
- // Don't send troops to areas we are dominating already
- // Don't require presence of enemy cities, just a dangerous force
- if( iOurPower < (3*iEnemyPower) )
- {
- iPathTurns;
- if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
- {
- iValue *= 10*pLoopCity->AI_cityThreat();
-
- iValue += 20 * GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ASSAULT, getGroup());
-
- iValue *= std::min(iEnemyPower, 3*iOurPower);
- iValue /= iOurPower;
- iValue *= 100;
- // if more than 3 turns to get there, then put some randomness into our preference of distance
- // +/- 33%
- if (iPathTurns > 3)
- {
- int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");
- iPathTurns *= 66 + iPathAdjustment;
- iPathTurns /= 100;
- }
- iValue /= (iPathTurns + 6);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = (bCityDanger ? getPathEndTurnPlot() : pLoopCity->plot());
- pBestAssaultPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot == NULL) && (pBestAssaultPlot == NULL))
- {
- if( bCity )
- {
- if( GET_TEAM(getTeam()).isAVassal() )
- {
- TeamTypes eMasterTeam = NO_TEAM;
- for( int iI = 0; iI < MAX_CIV_TEAMS; iI++ )
- {
- if( GET_TEAM(getTeam()).isVassal((TeamTypes)iI) )
- {
- eMasterTeam = (TeamTypes)iI;
- }
- }
- if( (eMasterTeam != NO_TEAM) && GET_TEAM(getTeam()).isOpenBorders(eMasterTeam) )
- {
- for( int iI = 0; iI < MAX_CIV_PLAYERS; iI++ )
- {
- if( GET_PLAYER((PlayerTypes)iI).getTeam() == eMasterTeam )
- {
- int iLoop;
- CvCity* pLoopCity;
- for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
- {
- if( pLoopCity->area() != area() )
- {
- iValue = 0;
- if(pLoopCity->area()->getAreaAIType(eMasterTeam) == AREAAI_OFFENSIVE)
- {
- iValue = 2;
- }
- else if(pLoopCity->area()->getAreaAIType(eMasterTeam) == AREAAI_MASSING)
- {
- iValue = 1;
- }
- if( iValue > 0 )
- {
- if( bCanMoveAllTerrain || (pWaterArea != NULL && (pLoopCity->waterArea(true) == pWaterArea || pLoopCity->secondWaterArea() == pWaterArea)) )
- {
- int iOurPower = std::max(1, pLoopCity->area()->getPower(getOwnerINLINE()));
- iOurPower += GET_TEAM(eMasterTeam).countPowerByArea(pLoopCity->area());
- // Enemy power includes barb power
- int iEnemyPower = GET_TEAM(eMasterTeam).countEnemyPowerByArea(pLoopCity->area());
- // Don't send troops to areas we are dominating already
- // Don't require presence of enemy cities, just a dangerous force
- if( iOurPower < (2*iEnemyPower) )
- {
- int iPathTurns;
- if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
- {
- iValue *= pLoopCity->AI_cityThreat();
-
- iValue += 10 * GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ASSAULT, getGroup());
-
- iValue *= std::min(iEnemyPower, 3*iOurPower);
- iValue /= iOurPower;
- iValue *= 100;
- // if more than 3 turns to get there, then put some randomness into our preference of distance
- // +/- 33%
- if (iPathTurns > 3)
- {
- int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");
- iPathTurns *= 66 + iPathAdjustment;
- iPathTurns /= 100;
- }
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestAssaultPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestAssaultPlot != NULL))
- {
- FAssert(!(pBestPlot->isImpassable()));
- // Cancel missions of all those coming to join departing transport
- CvSelectionGroup* pLoopGroup = NULL;
- int iLoop = 0;
- CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
- for(pLoopGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = kPlayer.nextSelectionGroup(&iLoop))
- {
- if( pLoopGroup != getGroup() )
- {
- if( pLoopGroup->AI_getMissionAIType() == MISSIONAI_GROUP && pLoopGroup->getHeadUnitAI() == AI_getUnitAIType() )
- {
- CvUnit* pMissionUnit = pLoopGroup->AI_getMissionAIUnit();
- if( pMissionUnit != NULL && pMissionUnit->getGroup() == getGroup() )
- {
- pLoopGroup->clearMissionQueue();
- }
- }
- }
- }
- if ((pBestPlot == pBestAssaultPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE()) == 1))
- {
- if (atPlot(pBestAssaultPlot))
- {
- getGroup()->unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
- return true;
- }
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
- return true;
- }
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_settlerSeaTransport()
- {
- PROFILE_FUNC();
- CLLNode<IDInfo>* pUnitNode;
- CvUnit* pLoopUnit;
- CvPlot* pLoopPlot;
- CvPlot* pPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestFoundPlot;
- CvArea* pWaterArea;
- bool bValid;
- int iValue;
- int iBestValue;
- int iI;
- FAssert(getCargo() > 0);
- FAssert(getUnitAICargo(UNITAI_SETTLE) > 0);
- if (!canCargoAllMove())
- {
- return false;
- }
-
- if (gUnitLogLevel >= 2)
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting AI_settlerSeaTransport", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- //New logic should allow some new tricks like
- //unloading settlers when a better site opens up locally
- //and delivering settlers
- //to inland sites
- pWaterArea = plot()->waterArea();
- FAssertMsg(pWaterArea != NULL, "Ship out of water?");
- CvUnit* pSettlerUnit = NULL;
- pPlot = plot();
- pUnitNode = pPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pPlot->nextUnitNode(pUnitNode);
- if (pLoopUnit->getTransportUnit() == this)
- {
- if (pLoopUnit->AI_getUnitAIType() == UNITAI_SETTLE)
- {
- pSettlerUnit = pLoopUnit;
- break;
- }
- }
- }
- FAssert(pSettlerUnit != NULL);
- int iAreaBestFoundValue = 0;
- CvPlot* pAreaBestPlot = NULL;
- int iOtherAreaBestFoundValue = 0;
- CvPlot* pOtherAreaBestPlot = NULL;
- for (iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
- {
- CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
- int iPathTurns;
- if (generatePath(pCitySitePlot, 0, true, &iPathTurns))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_FOUND, getGroup()) == 0)
- {
- iValue = pCitySitePlot->getFoundValue(getOwnerINLINE());
- if( gUnitLogLevel >= 4 ) logBBAI("...city plot %d, %d valued at %d", pCitySitePlot->getX(), pCitySitePlot->getY(), iValue);
- /*************************************************************************************************/
- /** BETTER_BTS_AI_MOD merged Sephi 0.41k 01/13/09 jdog5000 */
- /** */
- /** Settler AI */
- /*************************************************************************************************/
- // if (pCitySitePlot->getArea() == getArea())
- // {
- // if (iValue > iAreaBestFoundValue)
- // {
- // Only count city sites we can get to
- if (pCitySitePlot->getArea() == getArea() && pSettlerUnit->generatePath(pCitySitePlot, MOVE_SAFE_TERRITORY, true))
- {
- if (iValue > iAreaBestFoundValue)
- {
- /*************************************************************************************************/
- /** BETTER_BTS_AI_MOD END */
- /*************************************************************************************************/
- iAreaBestFoundValue = iValue;
- pAreaBestPlot = pCitySitePlot;
- }
- }
- else
- {
- if (iValue > iOtherAreaBestFoundValue)
- {
- iOtherAreaBestFoundValue = iValue;
- pOtherAreaBestPlot = pCitySitePlot;
- }
- }
- }
- }
- }
- if ((0 == iAreaBestFoundValue) && (0 == iOtherAreaBestFoundValue))
- {
- return false;
- }
-
- if (iAreaBestFoundValue > iOtherAreaBestFoundValue)
- {
- //let the settler walk.
- getGroup()->unloadAll();
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- if (iOtherAreaBestFoundValue > 0)
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pOtherAreaBestPlot->getX_INLINE(), pOtherAreaBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pOtherAreaBestPlot);
- return true;
- }
- iBestValue = 0;
- pBestPlot = NULL;
- pBestFoundPlot = NULL;
- for (iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
- {
- CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
- if (!(pCitySitePlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_FOUND, getGroup(), 4) == 0)
- {
- int iPathTurns;
- if (generatePath(pCitySitePlot, 0, true, &iPathTurns))
- {
- iValue = pCitySitePlot->getFoundValue(getOwnerINLINE());
- if (iValue >= GET_PLAYER(getOwnerINLINE()).AI_getMinFoundValue())
- {
- iValue *= 1000;
- iValue /= (2 + iPathTurns);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestFoundPlot = pCitySitePlot;
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
- {
- FAssert(!(pBestPlot->isImpassable()));
- if ((pBestPlot == pBestFoundPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE()) == 1))
- {
- if (atPlot(pBestFoundPlot))
- {
- unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
- return true;
- }
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
- return true;
- }
- }
- //Try original logic
- //(sometimes new logic breaks)
- pPlot = plot();
- iBestValue = 0;
- pBestPlot = NULL;
- pBestFoundPlot = NULL;
- int iMinFoundValue = GET_PLAYER(getOwnerINLINE()).AI_getMinFoundValue();
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (pLoopPlot->isCoastalLand())
- {
- iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
- if ((iValue > iBestValue) && (iValue >= iMinFoundValue))
- {
- bValid = false;
- pUnitNode = pPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pPlot->nextUnitNode(pUnitNode);
- if (pLoopUnit->getTransportUnit() == this)
- {
- if (pLoopUnit->canFound(pLoopPlot))
- {
- bValid = true;
- break;
- }
- }
- }
- if (bValid)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_FOUND, getGroup(), 4) == 0)
- {
- if (generatePath(pLoopPlot, 0, true))
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestFoundPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
- {
- FAssert(!(pBestPlot->isImpassable()));
- if ((pBestPlot == pBestFoundPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE()) == 1))
- {
- if (atPlot(pBestFoundPlot))
- {
- unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
- return true;
- }
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_settlerSeaFerry()
- {
- PROFILE_FUNC();
- FAssert(getCargo() > 0);
- FAssert(getUnitAICargo(UNITAI_WORKER) > 0);
- if (!canCargoAllMove())
- {
- return false;
- }
- CvArea* pWaterArea = plot()->waterArea();
- FAssertMsg(pWaterArea != NULL, "Ship out of water?");
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- CvCity* pLoopCity;
- int iLoop;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- int iValue = pLoopCity->AI_getWorkersNeeded();
- if (iValue > 0)
- {
- iValue -= GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_FOUND, getGroup());
- if (iValue > 0)
- {
- int iPathTurns;
- if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- iValue += std::max(0, (GET_PLAYER(getOwnerINLINE()).AI_neededWorkers(pLoopCity->area()) - GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), UNITAI_WORKER)));
- iValue *= 1000;
- iValue /= 4 + iPathTurns;
- if (atPlot(pLoopCity->plot()))
- {
- iValue += 100;
- }
- else
- {
- iValue += GC.getGame().getSorenRandNum(100, "AI settler sea ferry");
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_specialSeaTransportMissionary()
- {
- //PROFILE_FUNC();
- CLLNode<IDInfo>* pUnitNode;
- CvCity* pCity;
- CvUnit* pMissionaryUnit;
- CvUnit* pLoopUnit;
- CvPlot* pLoopPlot;
- CvPlot* pPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestSpreadPlot;
- int iPathTurns;
- int iValue;
- int iCorpValue;
- int iBestValue;
- int iI, iJ;
- bool bExecutive = false;
- FAssert(getCargo() > 0);
- FAssert(getUnitAICargo(UNITAI_MISSIONARY) > 0);
- if (!canCargoAllMove())
- {
- return false;
- }
- pPlot = plot();
- pMissionaryUnit = NULL;
- pUnitNode = pPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pPlot->nextUnitNode(pUnitNode);
- if (pLoopUnit->getTransportUnit() == this)
- {
- if (pLoopUnit->AI_getUnitAIType() == UNITAI_MISSIONARY)
- {
- pMissionaryUnit = pLoopUnit;
- break;
- }
- }
- }
- if (pMissionaryUnit == NULL)
- {
- return false;
- }
- iBestValue = 0;
- pBestPlot = NULL;
- pBestSpreadPlot = NULL;
- // XXX what about non-coastal cities?
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (pLoopPlot->isCoastalLand())
- {
- pCity = pLoopPlot->getPlotCity();
- if (pCity != NULL)
- {
- iValue = 0;
- iCorpValue = 0;
- for (iJ = 0; iJ < GC.getNumReligionInfos(); iJ++)
- {
- if (pMissionaryUnit->canSpread(pLoopPlot, ((ReligionTypes)iJ)))
- {
- if (GET_PLAYER(getOwnerINLINE()).getStateReligion() == ((ReligionTypes)iJ))
- {
- iValue += 3;
- }
- if (GET_PLAYER(getOwnerINLINE()).hasHolyCity((ReligionTypes)iJ))
- {
- iValue++;
- }
- }
- }
- for (iJ = 0; iJ < GC.getNumCorporationInfos(); iJ++)
- {
- if (pMissionaryUnit->canSpreadCorporation(pLoopPlot, ((CorporationTypes)iJ)))
- {
- if (GET_PLAYER(getOwnerINLINE()).hasHeadquarters((CorporationTypes)iJ))
- {
- iCorpValue += 3;
- }
- }
- }
- if (iValue > 0)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_SPREAD, getGroup()) == 0)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue *= pCity->getPopulation();
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- iValue *= 4;
- }
- else if (pCity->getTeam() == getTeam())
- {
- iValue *= 3;
- }
- if (pCity->getReligionCount() == 0)
- {
- iValue *= 2;
- }
- iValue /= (pCity->getReligionCount() + 1);
- FAssert(iPathTurns > 0);
- if (iPathTurns == 1)
- {
- iValue *= 2;
- }
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestSpreadPlot = pLoopPlot;
- bExecutive = false;
- }
- }
- }
- }
- }
- if (iCorpValue > 0)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_SPREAD_CORPORATION, getGroup()) == 0)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iCorpValue *= pCity->getPopulation();
- FAssert(iPathTurns > 0);
- if (iPathTurns == 1)
- {
- /************************************************************************************************/
- /* UNOFFICIAL_PATCH 02/22/10 jdog5000 */
- /* */
- /* Bugfix */
- /************************************************************************************************/
- /* original bts code
- iValue *= 2;
- */
- iCorpValue *= 2;
- /************************************************************************************************/
- /* UNOFFICIAL_PATCH END */
- /************************************************************************************************/
- }
- iCorpValue *= 1000;
- iCorpValue /= (iPathTurns + 1);
- if (iCorpValue > iBestValue)
- {
- iBestValue = iCorpValue;
- pBestPlot = getPathEndTurnPlot();
- pBestSpreadPlot = pLoopPlot;
- bExecutive = true;
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestSpreadPlot != NULL))
- {
- FAssert(!(pBestPlot->isImpassable()) || canMoveImpassable());
- if ((pBestPlot == pBestSpreadPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestSpreadPlot->getX_INLINE(), pBestSpreadPlot->getY_INLINE()) == 1))
- {
- if (atPlot(pBestSpreadPlot))
- {
- unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestSpreadPlot->getX_INLINE(), pBestSpreadPlot->getY_INLINE(), 0, false, false, bExecutive ? MISSIONAI_SPREAD_CORPORATION : MISSIONAI_SPREAD, pBestSpreadPlot);
- return true;
- }
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, bExecutive ? MISSIONAI_SPREAD_CORPORATION : MISSIONAI_SPREAD, pBestSpreadPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_specialSeaTransportSpy()
- {
- //PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- CvPlot* pBestSpyPlot;
- PlayerTypes eBestPlayer;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iI;
- FAssert(getCargo() > 0);
- FAssert(getUnitAICargo(UNITAI_SPY) > 0);
- if (!canCargoAllMove())
- {
- return false;
- }
- iBestValue = 0;
- eBestPlayer = NO_PLAYER;
- for (iI = 0; iI < MAX_CIV_PLAYERS; iI++)
- {
- if (GET_PLAYER((PlayerTypes)iI).isAlive())
- {
- if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_ANNOYED)
- {
- iValue = GET_PLAYER((PlayerTypes)iI).getTotalPopulation();
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestPlayer = ((PlayerTypes)iI);
- }
- }
- }
- }
- }
- if (eBestPlayer == NO_PLAYER)
- {
- return false;
- }
- pBestPlot = NULL;
- pBestSpyPlot = NULL;
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (pLoopPlot->isCoastalLand())
- {
- if (pLoopPlot->getOwnerINLINE() == eBestPlayer)
- {
- iValue = pLoopPlot->area()->getCitiesPerPlayer(eBestPlayer);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/23/10 jdog5000 */
- /* */
- /* Efficiency */
- /************************************************************************************************/
- iValue *= 1000;
- if (iValue > iBestValue)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ATTACK_SPY, getGroup(), 4) == 0)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestSpyPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestSpyPlot != NULL))
- {
- FAssert(!(pBestPlot->isImpassable()));
- if ((pBestPlot == pBestSpyPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestSpyPlot->getX_INLINE(), pBestSpyPlot->getY_INLINE()) == 1))
- {
- if (atPlot(pBestSpyPlot))
- {
- unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestSpyPlot->getX_INLINE(), pBestSpyPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestSpyPlot);
- return true;
- }
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestSpyPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_carrierSeaTransport()
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pLoopPlotAir;
- CvPlot* pBestPlot;
- CvPlot* pBestCarrierPlot;
- int iMaxAirRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- int iI;
- iMaxAirRange = 0;
- std::vector<CvUnit*> aCargoUnits;
- getCargoUnits(aCargoUnits);
- for (uint i = 0; i < aCargoUnits.size(); ++i)
- {
- iMaxAirRange = std::max(iMaxAirRange, aCargoUnits[i]->airRange());
- }
- if (iMaxAirRange == 0)
- {
- return false;
- }
- iBestValue = 0;
- pBestPlot = NULL;
- pBestCarrierPlot = NULL;
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
- /* */
- /* Naval AI, War tactics, Efficiency */
- /************************************************************************************************/
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->isAdjacentToLand())
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- iValue = 0;
- for (iDX = -(iMaxAirRange); iDX <= iMaxAirRange; iDX++)
- {
- for (iDY = -(iMaxAirRange); iDY <= iMaxAirRange; iDY++)
- {
- pLoopPlotAir = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iDX, iDY);
- if (pLoopPlotAir != NULL)
- {
- if (plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pLoopPlotAir->getX_INLINE(), pLoopPlotAir->getY_INLINE()) <= iMaxAirRange)
- {
- if (!(pLoopPlotAir->isBarbarian()))
- {
- if (potentialWarAction(pLoopPlotAir))
- {
- if (pLoopPlotAir->isCity())
- {
- iValue += 3;
- // BBAI: Support invasions
- iValue += (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlotAir, MISSIONAI_ASSAULT, getGroup(), 2) * 6);
- }
- if (pLoopPlotAir->getImprovementType() != NO_IMPROVEMENT)
- {
- iValue += 2;
- }
- if (plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pLoopPlotAir->getX_INLINE(), pLoopPlotAir->getY_INLINE()) <= iMaxAirRange/2)
- {
- // BBAI: Support/air defense for land troops
- iValue += pLoopPlotAir->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE());
- }
- }
- }
- }
- }
- }
- }
- if( iValue > 0 )
- {
- iValue *= 1000;
- for (int iDirection = 0; iDirection < NUM_DIRECTION_TYPES; iDirection++)
- {
- CvPlot* pDirectionPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), (DirectionTypes)iDirection);
- if (pDirectionPlot != NULL)
- {
- if (pDirectionPlot->isCity() && isEnemy(pDirectionPlot->getTeam(), pLoopPlot))
- {
- iValue /= 2;
- break;
- }
- }
- }
- if (iValue > iBestValue)
- {
- bool bStealth = (getInvisibleType() != NO_INVISIBLE);
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_CARRIER, getGroup(), bStealth ? 5 : 3) <= (bStealth ? 0 : 3))
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestCarrierPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if ((pBestPlot != NULL) && (pBestCarrierPlot != NULL))
- {
- if (atPlot(pBestCarrierPlot))
- {
- if (getGroup()->hasCargo())
- {
- CvPlot* pPlot = plot();
- int iNumUnits = pPlot->getNumUnits();
- for (int i = 0; i < iNumUnits; ++i)
- {
- bool bDone = true;
- CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pCargoUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pPlot->nextUnitNode(pUnitNode);
- if (pCargoUnit->isCargo())
- {
- FAssert(pCargoUnit->getTransportUnit() != NULL);
- if (pCargoUnit->getOwnerINLINE() == getOwnerINLINE() && (pCargoUnit->getTransportUnit()->getGroup() == getGroup()) && (pCargoUnit->getDomainType() == DOMAIN_AIR))
- {
- if (pCargoUnit->canMove() && pCargoUnit->isGroupHead())
- {
- // careful, this might kill the cargo group
- if (pCargoUnit->getGroup()->AI_update())
- {
- bDone = false;
- break;
- }
- }
- }
- }
- }
- if (bDone)
- {
- break;
- }
- }
- }
- if (canPlunder(pBestCarrierPlot))
- {
- getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, false, false, MISSIONAI_CARRIER, pBestCarrierPlot);
- }
- else
- {
- getGroup()->pushMission(MISSION_SKIP);
- }
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_CARRIER, pBestCarrierPlot);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_connectPlot(CvPlot* pPlot, int iRange)
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- int iLoop;
- FAssert(canBuildRoute());
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check area for land units before generating paths
- if( (getDomainType() == DOMAIN_LAND) && (pPlot->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
- {
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (!(pPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pPlot, MISSIONAI_BUILD, getGroup(), iRange) == 0)
- {
- if (generatePath(pPlot, MOVE_SAFE_TERRITORY, true))
- {
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (!(pPlot->isConnectedTo(pLoopCity)))
- {
- FAssertMsg(pPlot->getPlotCity() != pLoopCity, "pPlot->getPlotCity() is not expected to be equal with pLoopCity");
- if (plot()->getPlotGroup(getOwnerINLINE()) == pLoopCity->plot()->getPlotGroup(getOwnerINLINE()))
- {
- getGroup()->pushMission(MISSION_ROUTE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pPlot);
- return true;
- }
- }
- }
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check same area
- if( (pLoopCity->area() != pPlot->area()) )
- {
- continue;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (!(pPlot->isConnectedTo(pLoopCity)))
- {
- FAssertMsg(pPlot->getPlotCity() != pLoopCity, "pPlot->getPlotCity() is not expected to be equal with pLoopCity");
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true))
- {
- if (atPlot(pPlot)) // need to test before moving...
- {
- getGroup()->pushMission(MISSION_ROUTE_TO, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pPlot);
- }
- else
- {
- getGroup()->pushMission(MISSION_ROUTE_TO, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pPlot);
- getGroup()->pushMission(MISSION_ROUTE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pPlot);
- }
- return true;
- }
- }
- }
- }
- }
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_improveCity(CvCity* pCity)
- {
- PROFILE_FUNC();
- CvPlot* pBestPlot;
- BuildTypes eBestBuild;
- MissionTypes eMission;
- if (AI_bestCityBuild(pCity, &pBestPlot, &eBestBuild, NULL, this))
- {
- FAssertMsg(pBestPlot != NULL, "BestPlot is not assigned a valid value");
- FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
- FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
- if ((plot()->getWorkingCity() != pCity) || (GC.getBuildInfo(eBestBuild).getRoute() != NO_ROUTE))
- {
- eMission = MISSION_ROUTE_TO;
- }
- else
- {
- eMission = MISSION_MOVE_TO;
- if (NULL != pBestPlot && generatePath(pBestPlot) && (getPathLastNode()->m_iData2 == 1) && (getPathLastNode()->m_iData1 == 0))
- {
- if (pBestPlot->getRouteType() != NO_ROUTE)
- {
- eMission = MISSION_ROUTE_TO;
- }
- }
- else if (plot()->getRouteType() == NO_ROUTE)
- {
- int iPlotMoveCost = 0;
- iPlotMoveCost = ((plot()->getFeatureType() == NO_FEATURE) ? GC.getTerrainInfo(plot()->getTerrainType()).getMovementCost() : GC.getFeatureInfo(plot()->getFeatureType()).getMovementCost());
- if (plot()->isHills())
- {
- iPlotMoveCost += GC.getHILLS_EXTRA_MOVEMENT();
- }
- if (iPlotMoveCost > 1)
- {
- eMission = MISSION_ROUTE_TO;
- }
- }
- }
- eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);
- getGroup()->pushMission(eMission, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
- getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_improveLocalPlot(int iRange, CvCity* pIgnoreCity)
- {
- int iX, iY;
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- BuildTypes eBestBuild = NO_BUILD;
- for (iX = -iRange; iX <= iRange; iX++)
- {
- for (iY = -iRange; iY <= iRange; iY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
- if ((pLoopPlot != NULL) && (pLoopPlot->isCityRadius()))
- {
- CvCity* pCity = pLoopPlot->getWorkingCity();
- if ((NULL != pCity) && (pCity->getOwnerINLINE() == getOwnerINLINE()))
- {
- if ((NULL == pIgnoreCity) || (pCity != pIgnoreCity))
- {
- if (AI_plotValid(pLoopPlot))
- {
- int iIndex = pCity->getCityPlotIndex(pLoopPlot);
- if (iIndex != CITY_HOME_PLOT)
- {
- if (((NULL == pIgnoreCity) || ((pCity->AI_getWorkersNeeded() > 0) && (pCity->AI_getWorkersHave() < (1 + pCity->AI_getWorkersNeeded() * 2 / 3)))) && (pCity->AI_getBestBuild(iIndex) != NO_BUILD))
- {
- if (canBuild(pLoopPlot, pCity->AI_getBestBuild(iIndex)))
- {
- bool bAllowed = true;
- if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION))
- {
- if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT && pLoopPlot->getImprovementType() != GC.getDefineINT("RUINS_IMPROVEMENT"))
- {
- bAllowed = false;
- }
- }
- if (bAllowed)
- {
- if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT && GC.getBuildInfo(pCity->AI_getBestBuild(iIndex)).getImprovement() != NO_IMPROVEMENT)
- {
- bAllowed = false;
- }
- }
- if (bAllowed)
- {
- int iValue = pCity->AI_getBestBuildValue(iIndex);
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- int iMaxWorkers = 1;
- if (plot() == pLoopPlot)
- {
- iValue *= 3;
- iValue /= 2;
- }
- else if (getPathLastNode()->m_iData1 == 0)
- {
- iPathTurns++;
- }
- else if (iPathTurns <= 1)
- {
- iMaxWorkers = AI_calculatePlotWorkersNeeded(pLoopPlot, pCity->AI_getBestBuild(iIndex));
- }
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup()) < iMaxWorkers)
- {
- iValue *= 1000;
- iValue /= 1 + iPathTurns;
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- eBestBuild = pCity->AI_getBestBuild(iIndex);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
- FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
- FAssert(pBestPlot->getWorkingCity() != NULL);
- if (NULL != pBestPlot->getWorkingCity())
- {
- pBestPlot->getWorkingCity()->AI_changeWorkersHave(+1);
- if (plot()->getWorkingCity() != NULL)
- {
- plot()->getWorkingCity()->AI_changeWorkersHave(-1);
- }
- }
- MissionTypes eMission = MISSION_MOVE_TO;
- int iPathTurns;
- if (generatePath(pBestPlot, 0, true, &iPathTurns) && (getPathLastNode()->m_iData2 == 1) && (getPathLastNode()->m_iData1 == 0))
- {
- if (pBestPlot->getRouteType() != NO_ROUTE)
- {
- eMission = MISSION_ROUTE_TO;
- }
- }
- else if (plot()->getRouteType() == NO_ROUTE)
- {
- int iPlotMoveCost = 0;
- iPlotMoveCost = ((plot()->getFeatureType() == NO_FEATURE) ? GC.getTerrainInfo(plot()->getTerrainType()).getMovementCost() : GC.getFeatureInfo(plot()->getFeatureType()).getMovementCost());
- if (plot()->isHills())
- {
- iPlotMoveCost += GC.getHILLS_EXTRA_MOVEMENT();
- }
- if (iPlotMoveCost > 1)
- {
- eMission = MISSION_ROUTE_TO;
- }
- }
- eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);
- getGroup()->pushMission(eMission, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
- getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_nextCityToImprove(CvCity* pCity)
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvPlot* pPlot;
- CvPlot* pBestPlot;
- BuildTypes eBuild;
- BuildTypes eBestBuild;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- iBestValue = 0;
- eBestBuild = NO_BUILD;
- pBestPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (pLoopCity != pCity)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
- /* */
- /* Worker AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check area for land units before path generation
- if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
- {
- continue;
- }
- //iValue = pLoopCity->AI_totalBestBuildValue(area());
- int iWorkersNeeded = pLoopCity->AI_getWorkersNeeded();
- int iWorkersHave = pLoopCity->AI_getWorkersHave();
- iValue = std::max(0, iWorkersNeeded - iWorkersHave) * 100;
- iValue += iWorkersNeeded * 10;
- iValue *= (iWorkersNeeded + 1);
- iValue /= (iWorkersHave + 1);
- if (iValue > 0)
- {
- if (AI_bestCityBuild(pLoopCity, &pPlot, &eBuild, NULL, this))
- {
- FAssert(pPlot != NULL);
- FAssert(eBuild != NO_BUILD);
- if( AI_plotValid(pPlot) )
- {
- iValue *= 1000;
- if (pLoopCity->isCapital())
- {
- iValue *= 2;
- }
- if( iValue > iBestValue )
- {
- if( generatePath(pPlot, 0, true, &iPathTurns) )
- {
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestBuild = eBuild;
- pBestPlot = pPlot;
- FAssert(!atPlot(pBestPlot) || NULL == pCity || pCity->AI_getWorkersNeeded() == 0 || pCity->AI_getWorkersHave() > pCity->AI_getWorkersNeeded() + 1);
- }
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
- FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
- if (plot()->getWorkingCity() != NULL)
- {
- plot()->getWorkingCity()->AI_changeWorkersHave(-1);
- }
- FAssert(pBestPlot->getWorkingCity() != NULL || GC.getBuildInfo(eBestBuild).getImprovement() == NO_IMPROVEMENT);
- if (NULL != pBestPlot->getWorkingCity())
- {
- pBestPlot->getWorkingCity()->AI_changeWorkersHave(+1);
- }
- eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);
- getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
- getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_nextCityToImproveAirlift()
- {
- PROFILE_FUNC();
- CvCity* pCity;
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- int iValue;
- int iBestValue;
- int iLoop;
- if (getGroup()->getNumUnits() > 1)
- {
- return false;
- }
- pCity = plot()->getPlotCity();
- if (pCity == NULL)
- {
- return false;
- }
- if (pCity->getMaxAirlift() == 0)
- {
- return false;
- }
- iBestValue = 0;
- pBestPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (pLoopCity != pCity)
- {
- if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
- {
- iValue = pLoopCity->AI_totalBestBuildValue(pLoopCity->area());
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- FAssert(pLoopCity != pCity);
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_irrigateTerritory()
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- ImprovementTypes eImprovement;
- BuildTypes eBuild;
- BuildTypes eBestBuild;
- BuildTypes eBestTempBuild;
- BonusTypes eNonObsoleteBonus;
- bool bValid;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iBestTempBuildValue;
- int iI, iJ;
- iBestValue = 0;
- eBestBuild = NO_BUILD;
- pBestPlot = NULL;
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
- {
- if (pLoopPlot->getWorkingCity() == NULL)
- {
- eImprovement = pLoopPlot->getImprovementType();
- if ((eImprovement == NO_IMPROVEMENT) || !(GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION) && !(eImprovement == (GC.getDefineINT("RUINS_IMPROVEMENT")))))
- {
- if ((eImprovement == NO_IMPROVEMENT) || !(GC.getImprovementInfo(eImprovement).isCarriesIrrigation()))
- {
- eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());
- //if ((eImprovement == NO_IMPROVEMENT) || (eNonObsoleteBonus == NO_BONUS) || !(GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus)))
- if (eImprovement == NO_IMPROVEMENT || eNonObsoleteBonus == NO_BONUS || !GET_PLAYER(getOwnerINLINE()).doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus))
- {
- if (pLoopPlot->isIrrigationAvailable(true))
- {
- iBestTempBuildValue = MAX_INT;
- eBestTempBuild = NO_BUILD;
- for (iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
- {
- eBuild = ((BuildTypes)iJ);
- FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");
- if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
- {
- if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).isCarriesIrrigation())
- {
- if (canBuild(pLoopPlot, eBuild))
- {
- iValue = 10000;
- iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);
- // XXX feature production???
- if (iValue < iBestTempBuildValue)
- {
- iBestTempBuildValue = iValue;
- eBestTempBuild = eBuild;
- }
- }
- }
- }
- }
- if (eBestTempBuild != NO_BUILD)
- {
- bValid = true;
- if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_LEAVE_FORESTS))
- {
- if (pLoopPlot->getFeatureType() != NO_FEATURE)
- {
- if (GC.getBuildInfo(eBestTempBuild).isFeatureRemove(pLoopPlot->getFeatureType())
- //FfH: Added by Kael 04/24/2008
- && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pLoopPlot->getFeatureType())
- //FfH: End Add
- )
- {
- if (GC.getFeatureInfo(pLoopPlot->getFeatureType()).getYieldChange(YIELD_PRODUCTION) > 0)
- {
- bValid = false;
- }
- }
- }
- }
- if (bValid)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 1) == 0)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns)) // XXX should this actually be at the top of the loop? (with saved paths and all...)
- {
- iValue = 10000;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestBuild = eBestTempBuild;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
- FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
- getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
- getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
- return true;
- }
- return false;
- }
- // Tries to build a fort. Only in own territory if SuperForts/AdvancedTactics isn't enabled.
- // Returns true if a mission was pushed.
- bool CvUnitAI::AI_fortTerritory(bool bCanal, bool bAirbase)
- {
- PROFILE_FUNC();
-
- // lfgr 07/2019: Barbarians don't build forts
- if( GET_PLAYER(getOwnerINLINE()).isBarbarian() ) {
- return false;
- }
- // lfgr end
- int iBestValue = 0;
- BuildTypes eBestBuild = NO_BUILD;
- CvPlot* pBestPlot = NULL;
- CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
- for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()
- // Super Forts *canal* *choke* begin
- || (GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS) && pLoopPlot->getOwnerINLINE() == NO_PLAYER && pLoopPlot->isRevealed(getTeam(), false)))
- // Super Forts end
- {
- if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT
- // Super Forts *canal* *choke* begin
- || !pLoopPlot->isCityRadius())
- // Super Forts end
- {
- int iValue = 0;
- iValue += bCanal ? kOwner.AI_getPlotCanalValue(pLoopPlot) : 0;
- iValue += bAirbase ? kOwner.AI_getPlotAirbaseValue(pLoopPlot) : 0;
- // Super Forts *choke* begin
- iValue += kOwner.AI_getPlotChokeValue(pLoopPlot);
- /* The commented lines below weren't in the original BTS code, and shouldn't be necessary because
- the canal, airbase, and choke functions all consider defense bonus in their values
- if (pLoopPlot->isHills())
- iValue += 10;
- */
- if (GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS))
- {
- CvPlot* pAdjacentPlot;
- for (int iI = 0; iI < NUM_DIRECTION_TYPES; ++iI)
- {
- pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot != NULL)
- {
- if(pAdjacentPlot->getOwnerINLINE() == NO_PLAYER)
- {
- BonusTypes eNonObsoleteBonus = pAdjacentPlot->getNonObsoleteBonusType(getTeam());
- if (eNonObsoleteBonus != NO_BONUS)
- {
- if (!GET_PLAYER(getOwnerINLINE()).hasBonus(eNonObsoleteBonus) || GC.getBonusInfo(eNonObsoleteBonus).isMana())
- {
- iValue += 250;
- }
- else
- {
- iValue += 50;
- }
- }
- }
- }
- }
- }
- int iMinAcceptableValue = 0;
- if(pLoopPlot->getOwnerINLINE() == NO_PLAYER || pLoopPlot->isBeingWorked())
- { // Don't go outside borders for low values
- iMinAcceptableValue += 150;
- }
- if (iValue > iMinAcceptableValue)
- {
- int iBestTempBuildValue = MAX_INT;
- BuildTypes eBestTempBuild = NO_BUILD;
-
- int iPlotValue = iValue;
- iPlotValue += bCanal ? 0 : kOwner.AI_getPlotCanalValue(pLoopPlot) / 4;
- iPlotValue += bAirbase ? 0 : kOwner.AI_getPlotAirbaseValue(pLoopPlot) / 4;
- // Super Forts end
- for (int iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
- {
- BuildTypes eBuild = ((BuildTypes)iJ);
- FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");
- if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
- {
- if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).isActsAsCity())
- {
- if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).getDefenseModifier() > 0)
- {
- if (canBuild(pLoopPlot, eBuild))
- {
- iValue = 10000;
- iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);
- if (iValue < iBestTempBuildValue)
- {
- iBestTempBuildValue = iValue;
- eBestTempBuild = eBuild;
- }
- }
- }
- }
- }
- }
- if (eBestTempBuild != NO_BUILD)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- bool bValid = true;
- if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_LEAVE_FORESTS))
- {
- if (pLoopPlot->getFeatureType() != NO_FEATURE)
- {
- if (GC.getBuildInfo(eBestTempBuild).isFeatureRemove(pLoopPlot->getFeatureType())
- //FfH: Added by Kael 04/24/2008
- && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pLoopPlot->getFeatureType())
- //FfH: End Add
- )
- {
- if (GC.getFeatureInfo(pLoopPlot->getFeatureType()).getYieldChange(YIELD_PRODUCTION) > 0)
- {
- bValid = false;
- }
- }
- }
- }
- if (bValid)
- {
- // Super Forts begin *canal* *choke*
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 1/*3*/) == 0)
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- //iValue *= 1000;
- iValue = iPlotValue * 100;
- iValue /= (iPathTurns + 1);
- if(pLoopPlot->getOwnerINLINE() == NO_PLAYER)
- {
- CvCity* pNearestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), getOwnerINLINE(), NO_TEAM, false);
- if((pNearestCity == NULL) ||
- (plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE()) > GC.getDefineINT("AI_WORKER_MAX_DISTANCE_FROM_CITY_OUT_BORDERS")) ||
- (iPathTurns > (GC.getDefineINT("AI_WORKER_MAX_DISTANCE_FROM_CITY_OUT_BORDERS") / 2)))
- {
- iValue = 0;
- }
- }
- // Super Forts end
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestBuild = eBestTempBuild;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
- FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
- getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
- getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_improveBonus(int iMinValue, CvPlot** ppBestPlot, BuildTypes* peBestBuild, int* piBestValue, bool bInsideBordersOrCurrentPlot)
- {
- // LFGR_TODO: Maybe do some caching, this is called multiple times in the same turn by the same worker.
- PROFILE_FUNC();
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- ImprovementTypes eImprovement;
- BuildTypes eBuild;
- BuildTypes eBestBuild;
- BuildTypes eBestTempBuild;
- BonusTypes eNonObsoleteBonus;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iBestTempBuildValue;
- int iBestResourceValue;
- int iI, iJ;
- bool bBestBuildIsRoute = false;
- bool bCanRoute;
- bool bIsConnected;
- iBestValue = 0;
- iBestResourceValue = 0;
- eBestBuild = NO_BUILD;
- pBestPlot = NULL;
- if( gUnitLogLevel >= 3 ){logBBAI(" Try to improve some bonus");}
- bCanRoute = canBuildRoute();
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- // Super Forts begin *AI_worker*: Allow building outside borders if super forts is enabled
- if ((pLoopPlot->getOwnerINLINE() == getOwnerINLINE() ||
- ( ( !bInsideBordersOrCurrentPlot || pLoopPlot == plot() ) && GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)
- && pLoopPlot->getOwnerINLINE() == NO_PLAYER && pLoopPlot->isRevealed(getTeam(), false) )
- ) && AI_plotValid(pLoopPlot))
- //if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE() && AI_plotValid(pLoopPlot)) - Original Code
- // Super Forts end
- {
- bool bCanImprove = (pLoopPlot->area() == area());
- if (!bCanImprove)
- {
- if (DOMAIN_SEA == getDomainType() && pLoopPlot->isWater() && plot()->isAdjacentToArea(pLoopPlot->area()))
- {
- bCanImprove = true;
- }
- }
- //FfH: Added by Kael 12/20/2008
- if (pLoopPlot->isVisibleEnemyUnit(this))
- {
- bCanImprove = false;
- }
- if (!atPlot(pLoopPlot))
- {
- if (!canMoveInto(pLoopPlot))
- {
- bCanImprove = false;
- }
- }
- //FfH: End Add
- if (bCanImprove)
- {
- eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());
- if (eNonObsoleteBonus != NO_BONUS)
- {
- bIsConnected = pLoopPlot->isConnectedToCapital(getOwnerINLINE());
- // Super Forts begin *AI_worker* - This section makes sure the plot is "close enough" to a city to be worth building on
- bool bCloseEnough = false;
-
- if(pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
- {
- bCloseEnough = true;
- }
- // Automated human workers will not look outside borders to build forts on bonuses the player already has
- else if(!isHuman() || !GET_PLAYER(getOwnerINLINE()).hasBonus(eNonObsoleteBonus))
- {
- CvCity* pNearestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), getOwnerINLINE(), NO_TEAM, false);
- int iPathTurns;
- if ((pNearestCity != NULL) && generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- int iDistanceModifier = 1;
- if(GET_PLAYER(getOwnerINLINE()).hasBonus(eNonObsoleteBonus))
- {
- iDistanceModifier = 2; // AI will not travel as far for bonuses they already have
- }
- 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"))
- {
- bCloseEnough = true;
- }
- if (iPathTurns > (GC.getDefineINT("AI_WORKER_MAX_DISTANCE_FROM_CITY_OUT_BORDERS") / 2))
- {
- bCloseEnough = false;
- }
- }
- }
- if (((pLoopPlot->getWorkingCity() != NULL) || (bIsConnected || bCanRoute)) && bCloseEnough)
- //if ((pLoopPlot->getWorkingCity() != NULL) || (bIsConnected || bCanRoute)) // Original Code
- // Super Forts end
- {
- if( gUnitLogLevel >= 3 ){
- logBBAI(" Found bonus %s on %d|%d (%s), check whether we want to improve that...",
- GC.getBonusInfo( eNonObsoleteBonus ).getType(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(),
- ( pLoopPlot->getOwnerINLINE() == getOwnerINLINE() ? "owned" : "unowned" ) );
- }
- eImprovement = pLoopPlot->getImprovementType();
- bool bDoImprove = false;
- if (eImprovement == NO_IMPROVEMENT)
- {
- bDoImprove = true;
- }
- else if (GC.getImprovementInfo(eImprovement).isActsAsCity() || GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
- {
- bDoImprove = false;
- }
- // Super Forts begin *AI_worker* (No need to loop through builds if the improvement is permanent)
- else if (GC.getImprovementInfo(eImprovement).isPermanent())
- {
- bDoImprove = false;
- }
- // Super Forts end
- else if (eImprovement == (ImprovementTypes)(GC.getDefineINT("RUINS_IMPROVEMENT")))
- {
- bDoImprove = true;
- }
- else if (!GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION))
- {
- bDoImprove = true;
- }
- iBestTempBuildValue = MAX_INT;
- eBestTempBuild = NO_BUILD;
- if (bDoImprove)
- {
- if( gUnitLogLevel >= 3 ){
- logBBAI(" We want to improve this, checking for builds..." );
- }
- for (iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
- {
- eBuild = ((BuildTypes)iJ);
- if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
- {
- // Super Forts *AI_worker* (added if statement)
- ImprovementTypes eImprovement = (ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement();
- CvImprovementInfo& kImprovement = GC.getImprovementInfo( eImprovement );
- if(pLoopPlot->getOwnerINLINE() == getOwnerINLINE() || kImprovement.isActsAsCity() && kImprovement.isOutsideBorders())
- {
- //if (GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).isImprovementBonusTrade(eNonObsoleteBonus) || (!pLoopPlot->isCityRadius() && GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).isActsAsCity()))
- if (kOwner.doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus)) // K-Mod
- {
- if (canBuild(pLoopPlot, eBuild))
- {
- if ((pLoopPlot->getFeatureType() == NO_FEATURE) || !GC.getBuildInfo(eBuild).isFeatureRemove(pLoopPlot->getFeatureType()) || !GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_LEAVE_FORESTS)
- //FfH: Added by Kael 04/24/2008
- || GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pLoopPlot->getFeatureType())
- //FfH: End Add
- )
- {
- iValue = 10000;
- iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);
- /*FfH: Added by Chalid AiManaAndBonus 06/10/2006*/
- if (!isHuman())
- {
- iValue /= 100;
- iValue *= std::max(0, (100-GC.getLeaderHeadInfo(GET_PLAYER(getOwnerINLINE()).getPersonalityType()).getImprovementWeightModifier((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement())));
- }
- //iValue -= GC.getGameINLINE().getSorenRandNum(4000, "AIBonus");
- //FfH: End Add
- // XXX feature production???
- if (iValue < iBestTempBuildValue)
- {
- iBestTempBuildValue = iValue;
- eBestTempBuild = eBuild;
- }
- }
- }
- }
- } // Super Forts (closing bracket of if statement added above)
- }
- }
- if( gUnitLogLevel >= 3 ) {
- if( eBestTempBuild == NO_BUILD ) {logBBAI(" No build found!" );}
- else {logBBAI(" Best build %s", GC.getBuildInfo( eBestTempBuild ).getType() );}
- }
- }
- if (eBestTempBuild == NO_BUILD)
- {
- bDoImprove = false;
- }
- // 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)
- if(!bDoImprove && pLoopPlot->getOwnerINLINE() != getOwnerINLINE())
- {
- continue;
- }
- // Super Forts end
- if ((eBestTempBuild != NO_BUILD) || (bCanRoute && !bIsConnected))
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue = kOwner.AI_bonusVal(eNonObsoleteBonus);
- if( gUnitLogLevel >= 3 ){ logBBAI(" Reachable. Base value: %d", iValue ); }
- if (bDoImprove)
- {
- eImprovement = (ImprovementTypes)GC.getBuildInfo(eBestTempBuild).getImprovement();
- FAssert(eImprovement != NO_IMPROVEMENT);
- //iValue += (GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBestTempBuild).getImprovement()))
- iValue += 5 * pLoopPlot->calculateImprovementYieldChange(eImprovement, YIELD_FOOD, getOwnerINLINE(), false);
- //>>>>Unofficial Bug Fix: Modified by Denev 2010/02/21
- //*** Elvish civilization can see the amount of production from forest chopping.
- /*
- iValue += 5 * pLoopPlot->calculateNatureYield(YIELD_FOOD, getTeam(), (pLoopPlot->getFeatureType() == NO_FEATURE) ? true : (GC.getBuildInfo(eBestTempBuild).isFeatureRemove(pLoopPlot->getFeatureType())
- //FfH: Added by Kael 04/24/2008
- && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pLoopPlot->getFeatureType()))
- //FfH: End Add
- );
- */
- iValue += 5 * pLoopPlot->calculateNatureYield(YIELD_FOOD, getOwnerINLINE(), pLoopPlot->isFeatureRemove(eBestTempBuild));
- //<<<<Unofficial Bug Fix: End Modify
- if( gUnitLogLevel >= 3 ){ logBBAI(" Value after considering improvement: %d", iValue ); }
- }
- iValue += std::max(0, 100 * GC.getBonusInfo(eNonObsoleteBonus).getAIObjective());
- if (kOwner.getNumTradeableBonuses(eNonObsoleteBonus) == 0)
- {
- iValue *= 2;
- }
- if( gUnitLogLevel >= 3 ){ logBBAI(" Value after considering objective, trade: %d", iValue ); }
- int iMaxWorkers = 1;
- // Super Forts begin *AI_worker*
- if ((eBestTempBuild != NO_BUILD) && (GC.getBuildInfo(eBestTempBuild).getTime() > 0))
- //if ((eBestTempBuild != NO_BUILD) && (!GC.getBuildInfo(eBestTempBuild).isKill())) - Original Code
- // Super Forts end
- {
- //allow teaming.
- iMaxWorkers = AI_calculatePlotWorkersNeeded(pLoopPlot, eBestTempBuild);
- if (getPathLastNode()->m_iData1 == 0)
- {
- iMaxWorkers = std::min((iMaxWorkers + 1) / 2, 1 + kOwner.AI_baseBonusVal(eNonObsoleteBonus) / 20);
- }
- }
- if( gUnitLogLevel >= 3 ){ logBBAI(" Using at most %d workers", iMaxWorkers ); }
- if ((kOwner.AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup()) < iMaxWorkers)
- && (!bDoImprove || (pLoopPlot->getBuildTurnsLeft(eBestTempBuild, 0, 0) > (iPathTurns * 2 - 1))))
- {
- if( gUnitLogLevel >= 3 ){ logBBAI(" Workers are still required!" ); }
- if (bDoImprove)
- {
- iValue *= 1000;
- if (atPlot(pLoopPlot))
- {
- iValue *= 3;
- if( gUnitLogLevel >= 3 ){ logBBAI(" We're at the plot already: triple value" ); }
- }
- iValue /= (iPathTurns + 1);
- if( gUnitLogLevel >= 3 ){ logBBAI(" Divide by path turns: %d", iPathTurns ); }
- if (pLoopPlot->isCityRadius())
- {
- iValue *= 2;
- if( gUnitLogLevel >= 3 ){ logBBAI(" In city radius: double value" ); }
- }
- if( gUnitLogLevel >= 3 ){ logBBAI(" Final improvement build value: %d", iValue ); }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestBuild = eBestTempBuild;
- pBestPlot = pLoopPlot;
- bBestBuildIsRoute = false;
- iBestResourceValue = iValue;
- }
- }
- else
- {
- FAssert(bCanRoute && !bIsConnected);
- eImprovement = pLoopPlot->getImprovementType();
- //if ((eImprovement != NO_IMPROVEMENT) && (GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus)))
- if (kOwner.doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus))
- {
- iValue *= 1000;
- iValue /= (iPathTurns + 1);
- if( gUnitLogLevel >= 3 ){ logBBAI(" Final road build value: %d", iValue ); }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestBuild = NO_BUILD;
- pBestPlot = pLoopPlot;
- bBestBuildIsRoute = true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if( gUnitLogLevel >= 3 && eBestBuild != NO_BUILD ){
- logBBAI(" Best plot: %d|%d, best build: %s with value %d",
- pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), GC.getBuildInfo( eBestBuild ).getType(), iBestValue );
- }
- if ((iBestValue < iMinValue) && (NULL != ppBestPlot))
- {
- FAssert(NULL != peBestBuild);
- FAssert(NULL != piBestValue);
- *ppBestPlot = pBestPlot;
- *peBestBuild = eBestBuild;
- *piBestValue = iBestResourceValue;
- }
- if (pBestPlot != NULL)
- {
- if (eBestBuild != NO_BUILD)
- {
- FAssertMsg(!bBestBuildIsRoute, "BestBuild should not be a route");
- FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
- MissionTypes eBestMission = MISSION_MOVE_TO;
- if ((pBestPlot->getWorkingCity() == NULL) || !pBestPlot->getWorkingCity()->isConnectedToCapital())
- {
- eBestMission = MISSION_ROUTE_TO;
- }
- else
- {
- int iDistance = stepDistance(getX_INLINE(), getY_INLINE(), pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- int iPathTurns;
- if (generatePath(pBestPlot, 0, false, &iPathTurns))
- {
- if (iPathTurns >= iDistance)
- {
- eBestMission = MISSION_ROUTE_TO;
- }
- }
- }
- eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);
- getGroup()->pushMission(eBestMission, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
- getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
- if( gUnitLogLevel >= 3 ){logBBAI(" ... improving bonus at %d, %d with %S (value: %d)", pBestPlot->getX(), pBestPlot->getY(), GC.getBuildInfo((BuildTypes)eBestBuild).getTextKeyWide(), iBestValue);}
-
- return true;
- }
- else if (bBestBuildIsRoute)
- {
- if (AI_connectPlot(pBestPlot))
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ... building road to %d, %d (value: %d)", pBestPlot->getX(), iBestValue);}
- return true;
- }
- /*else
- {
- // 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)
- FAssertMsg(false, "Expected that a route could be built to eBestPlot");
- }*/
- }
- else
- {
- FAssert(false);
- }
- }
- return false;
- }
- //returns true if a mission is pushed
- //if eBuild is NO_BUILD, assumes a route is desired.
- bool CvUnitAI::AI_improvePlot(CvPlot* pPlot, BuildTypes eBuild)
- {
- FAssert(pPlot != NULL);
- if (eBuild != NO_BUILD)
- {
- FAssertMsg(eBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
- eBuild = AI_betterPlotBuild(pPlot, eBuild);
- if (!atPlot(pPlot))
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pPlot);
- }
- getGroup()->pushMission(MISSION_BUILD, eBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pPlot);
- return true;
- }
- else if (canBuildRoute())
- {
- if (AI_connectPlot(pPlot))
- {
- return true;
- }
- }
- return false;
- }
- BuildTypes CvUnitAI::AI_betterPlotBuild(CvPlot* pPlot, BuildTypes eBuild)
- {
- FAssert(pPlot != NULL);
- FAssert(eBuild != NO_BUILD);
- bool bBuildRoute = false;
- bool bClearFeature = false;
- FeatureTypes eFeature = pPlot->getFeatureType();
- CvBuildInfo& kOriginalBuildInfo = GC.getBuildInfo(eBuild);
- if (kOriginalBuildInfo.getRoute() != NO_ROUTE)
- {
- return eBuild;
- }
- int iWorkersNeeded = AI_calculatePlotWorkersNeeded(pPlot, eBuild);
-
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 7/31/08 jdog5000 */
- /* */
- /* Bugfix */
- /********************************************************************************/
- //if ((pPlot->getBonusType() == NO_BONUS) && (pPlot->getWorkingCity() != NULL))
- if ((pPlot->getNonObsoleteBonusType(getTeam()) == NO_BONUS) && (pPlot->getWorkingCity() != NULL))
- {
- iWorkersNeeded = std::max(1, std::min(iWorkersNeeded, pPlot->getWorkingCity()->AI_getWorkersHave()));
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- if (eFeature != NO_FEATURE)
- {
- CvFeatureInfo& kFeatureInfo = GC.getFeatureInfo(eFeature);
- if (kOriginalBuildInfo.isFeatureRemove(eFeature)
- //FfH: Added by Kael 04/24/2008
- && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pPlot->getFeatureType())
- //FfH: End Add
- )
- {
- if ((kOriginalBuildInfo.getImprovement() == NO_IMPROVEMENT) || (!pPlot->isBeingWorked() || (kFeatureInfo.getYieldChange(YIELD_FOOD) + kFeatureInfo.getYieldChange(YIELD_PRODUCTION)) <= 0))
- {
- bClearFeature = true;
- }
- }
- if ((kFeatureInfo.getMovementCost() > 1) && (iWorkersNeeded > 1))
- {
- bBuildRoute = true;
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 7/31/08 jdog5000 */
- /* */
- /* Bugfix */
- /********************************************************************************/
- //if (pPlot->getBonusType() != NO_BONUS)
- if (pPlot->getNonObsoleteBonusType(getTeam()) != NO_BONUS)
- {
- bBuildRoute = true;
- }
- else if (pPlot->isHills())
- {
- if ((GC.getHILLS_EXTRA_MOVEMENT() > 0) && (iWorkersNeeded > 1))
- {
- bBuildRoute = true;
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
-
- if (pPlot->getRouteType() != NO_ROUTE)
- {
- bBuildRoute = false;
- }
- BuildTypes eBestBuild = NO_BUILD;
- int iBestValue = 0;
- for (int iBuild = 0; iBuild < GC.getNumBuildInfos(); iBuild++)
- {
- BuildTypes eBuild = ((BuildTypes)iBuild);
- CvBuildInfo& kBuildInfo = GC.getBuildInfo(eBuild);
- RouteTypes eRoute = (RouteTypes)kBuildInfo.getRoute();
- if ((bBuildRoute && (eRoute != NO_ROUTE)) || (bClearFeature && kBuildInfo.isFeatureRemove(eFeature)
- //FfH: Added by Kael 04/24/2008
- && !GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(pPlot->getFeatureType())
- //FfH: End Add
- ))
- {
- if (canBuild(pPlot, eBuild))
- {
- int iValue = 10000;
- if (bBuildRoute && (eRoute != NO_ROUTE))
- {
- iValue *= (1 + GC.getRouteInfo(eRoute).getValue());
- iValue /= 2;
-
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 7/31/08 jdog5000 */
- /* */
- /* Bugfix */
- /********************************************************************************/
- //if if (pPlot->getBonusType() != NO_BONUS)
- if (pPlot->getNonObsoleteBonusType(getTeam()) != NO_BONUS)
- {
- iValue *= 2;
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
-
- if (pPlot->getWorkingCity() != NULL)
- {
- iValue *= 2 + iWorkersNeeded + ((pPlot->isHills() && (iWorkersNeeded > 1)) ? 2 * GC.getHILLS_EXTRA_MOVEMENT() : 0);
- iValue /= 3;
- }
- ImprovementTypes eImprovement = (ImprovementTypes)kOriginalBuildInfo.getImprovement();
- if (eImprovement != NO_IMPROVEMENT)
- {
- int iRouteMultiplier = ((GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eRoute, YIELD_FOOD)) * 100);
- iRouteMultiplier += ((GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eRoute, YIELD_PRODUCTION)) * 100);
- iRouteMultiplier += ((GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eRoute, YIELD_COMMERCE)) * 60);
- iValue *= 100 + iRouteMultiplier;
- iValue /= 100;
- }
- int iPlotGroupId = -1;
- for (int iDirection = 0; iDirection < NUM_DIRECTION_TYPES; iDirection++)
- {
- CvPlot* pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), (DirectionTypes)iDirection);
- if (pLoopPlot != NULL)
- {
- if (pPlot->isRiver() || (pLoopPlot->getRouteType() != NO_ROUTE))
- {
- CvPlotGroup* pLoopGroup = pLoopPlot->getPlotGroup(getOwnerINLINE());
- if (pLoopGroup != NULL)
- {
- if (pLoopGroup->getID() != -1)
- {
- if (pLoopGroup->getID() != iPlotGroupId)
- {
- //This plot bridges plot groups, so route it.
- iValue *= 4;
- break;
- }
- else
- {
- iPlotGroupId = pLoopGroup->getID();
- }
- }
- }
- }
- }
- }
- }
- iValue /= (kBuildInfo.getTime() + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestBuild = eBuild;
- }
- }
- }
- }
- if (eBestBuild == NO_BUILD)
- {
- return eBuild;
- }
- return eBestBuild;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_connectBonus(bool bTestTrade)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- BonusTypes eNonObsoleteBonus;
- int iI;
- // XXX how do we make sure that we can build roads???
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
- {
- eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());
- if (eNonObsoleteBonus != NO_BONUS)
- {
- if (!(pLoopPlot->isConnectedToCapital()))
- {
- //if (!bTestTrade || ((pLoopPlot->getImprovementType() != NO_IMPROVEMENT) && (GC.getImprovementInfo(pLoopPlot->getImprovementType()).isImprovementBonusTrade(eNonObsoleteBonus))))
- if (!bTestTrade || GET_PLAYER(getOwnerINLINE()).doesImprovementConnectBonus(pLoopPlot->getImprovementType(), eNonObsoleteBonus))
- {
- if (AI_connectPlot(pLoopPlot))
- {
- return true;
- }
- }
- }
- }
- }
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_connectCity()
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- int iLoop;
- // XXX how do we make sure that we can build roads???
- pLoopCity = plot()->getWorkingCity();
- if (pLoopCity != NULL)
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- if (!(pLoopCity->isConnectedToCapital()))
- {
- if (AI_connectPlot(pLoopCity->plot(), 1))
- {
- return true;
- }
- }
- }
- }
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- if (!(pLoopCity->isConnectedToCapital()))
- {
- if (AI_connectPlot(pLoopCity->plot(), 1))
- {
- return true;
- }
- }
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_routeCity()
- {
- PROFILE_FUNC();
- CvCity* pRouteToCity;
- CvCity* pLoopCity;
- int iLoop;
- FAssert(canBuildRoute());
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check area for land units before generating path
- if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
- {
- continue;
- }
- pRouteToCity = pLoopCity->AI_getRouteToCity();
- if (pRouteToCity != NULL)
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (!(pRouteToCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pRouteToCity->plot(), MISSIONAI_BUILD, getGroup()) == 0)
- {
- if (generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (generatePath(pRouteToCity->plot(), MOVE_SAFE_TERRITORY, true))
- {
- getGroup()->pushMission(MISSION_ROUTE_TO, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pRouteToCity->plot());
- getGroup()->pushMission(MISSION_ROUTE_TO, pRouteToCity->getX_INLINE(), pRouteToCity->getY_INLINE(), MOVE_SAFE_TERRITORY, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pRouteToCity->plot());
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_routeTerritory(bool bImprovementOnly)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- ImprovementTypes eImprovement;
- RouteTypes eBestRoute;
- bool bValid;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iI, iJ;
- // XXX how do we make sure that we can build roads???
- FAssert(canBuildRoute());
- iBestValue = 0;
- pBestPlot = NULL;
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
- {
- eBestRoute = GET_PLAYER(getOwnerINLINE()).getBestRoute(pLoopPlot);
- if (eBestRoute != NO_ROUTE)
- {
- if (eBestRoute != pLoopPlot->getRouteType())
- {
- if (bImprovementOnly)
- {
- bValid = false;
- eImprovement = pLoopPlot->getImprovementType();
- if (eImprovement != NO_IMPROVEMENT)
- {
- for (iJ = 0; iJ < NUM_YIELD_TYPES; iJ++)
- {
- if (GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eBestRoute, iJ) > 0)
- {
- bValid = true;
- break;
- }
- }
- }
- }
- else
- {
- bValid = true;
- }
- if (bValid)
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 1) == 0)
- {
- if (generatePath(pLoopPlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
- {
- iValue = 10000;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pBestPlot);
- return true;
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_travelToUpgradeCity()
- {
- PROFILE_FUNC();
- // is there a city which can upgrade us?
- CvCity* pUpgradeCity = getUpgradeCity(/*bSearch*/ true);
- if (pUpgradeCity != NULL)
- {
- // cache some stuff
- CvPlot* pPlot = plot();
- bool bSeaUnit = (getDomainType() == DOMAIN_SEA);
- bool bCanAirliftUnit = (getDomainType() == DOMAIN_LAND);
- bool bShouldSkipToUpgrade = (getDomainType() != DOMAIN_AIR);
- // if we at the upgrade city, stop, wait to get upgraded
- if (pUpgradeCity->plot() == pPlot || isUpgradeOutsideBorders())
- {
- if (!bShouldSkipToUpgrade)
- {
- return false;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- if (DOMAIN_AIR == getDomainType())
- {
- FAssert(!atPlot(pUpgradeCity->plot()));
- getGroup()->pushMission(MISSION_MOVE_TO, pUpgradeCity->getX_INLINE(), pUpgradeCity->getY_INLINE());
- return true;
- }
- // find the closest city
- CvCity* pClosestCity = pPlot->getPlotCity();
- bool bAtClosestCity = (pClosestCity != NULL);
- if (pClosestCity == NULL)
- {
- pClosestCity = pPlot->getWorkingCity();
- }
- if (pClosestCity == NULL)
- {
- pClosestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), NO_PLAYER, getTeam(), true, bSeaUnit);
- }
- // can we path to the upgrade city?
- int iUpgradeCityPathTurns;
- CvPlot* pThisTurnPlot = NULL;
- bool bCanPathToUpgradeCity = generatePath(pUpgradeCity->plot(), 0, true, &iUpgradeCityPathTurns);
- if (bCanPathToUpgradeCity)
- {
- pThisTurnPlot = getPathEndTurnPlot();
- }
- // if we close to upgrade city, head there
- if (NULL != pThisTurnPlot && NULL != pClosestCity && (pClosestCity == pUpgradeCity || iUpgradeCityPathTurns < 4))
- {
- FAssert(!atPlot(pThisTurnPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pThisTurnPlot->getX_INLINE(), pThisTurnPlot->getY_INLINE());
- if( gUnitLogLevel >= 3 )
- {
- 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());
- }
- return true;
- }
- // check for better airlift choice
- if (bCanAirliftUnit && NULL != pClosestCity && pClosestCity->getMaxAirlift() > 0)
- {
- // if we at the closest city, then do the airlift, or wait
- if (bAtClosestCity)
- {
- // can we do the airlift this turn?
- if (canAirliftAt(pClosestCity->plot(), pUpgradeCity->getX_INLINE(), pUpgradeCity->getY_INLINE()))
- {
- getGroup()->pushMission(MISSION_AIRLIFT, pUpgradeCity->getX_INLINE(), pUpgradeCity->getY_INLINE());
- return true;
- }
- // wait to do it next turn
- else
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- }
- int iClosestCityPathTurns;
- CvPlot* pThisTurnPlotForAirlift = NULL;
- bool bCanPathToClosestCity = generatePath(pClosestCity->plot(), 0, true, &iClosestCityPathTurns);
- if (bCanPathToClosestCity)
- {
- pThisTurnPlotForAirlift = getPathEndTurnPlot();
- }
- // is the closest city closer pathing? If so, move toward closest city
- if (NULL != pThisTurnPlotForAirlift && (!bCanPathToUpgradeCity || iClosestCityPathTurns < iUpgradeCityPathTurns))
- {
- FAssert(!atPlot(pThisTurnPlotForAirlift));
- getGroup()->pushMission(MISSION_MOVE_TO, pThisTurnPlotForAirlift->getX_INLINE(), pThisTurnPlotForAirlift->getY_INLINE());
- return true;
- }
- }
- // did not have better airlift choice, go ahead and path to the upgrade city
- if (NULL != pThisTurnPlot)
- {
- FAssert(!atPlot(pThisTurnPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pThisTurnPlot->getX_INLINE(), pThisTurnPlot->getY_INLINE());
- if( gUnitLogLevel >= 3 )
- {
- 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());
- }
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_retreatToCity(bool bPrimary, bool bAirlift, int iMaxPath)
- {
- PROFILE_FUNC();
- CvCity* pCity;
- CvCity* pLoopCity;
- CvPlot* pBestPlot = NULL;
- int iPathTurns;
- int iValue;
- int iBestValue = MAX_INT;
- int iPass;
- int iLoop;
- int iCurrentDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot());
- pCity = plot()->getPlotCity();
- if (0 == iCurrentDanger)
- {
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- if (!bPrimary || GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pCity->area()))
- {
- if (!bAirlift || (pCity->getMaxAirlift() > 0))
- {
- if (!(pCity->plot()->isVisibleEnemyUnit(this)))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- }
- }
- }
- }
- }
- for (iPass = 0; iPass < 4; iPass++)
- {
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- if (!bPrimary || GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopCity->area()))
- {
- if (!bAirlift || (pLoopCity->getMaxAirlift() > 0))
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check area for land units before generating path
- if( !bAirlift && (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
- {
- continue;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), ((iPass > 1) ? MOVE_IGNORE_DANGER : 0), true, &iPathTurns))
- {
- if (iPathTurns <= ((iPass == 2) ? 1 : iMaxPath))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- /* original bts code
- if ((iPass > 0) || (getGroup()->canFight() || GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopCity->plot()) < iCurrentDanger))
- */
- // Water units can't defend a city
- // Any unthreatened city acceptable on 0th pass, solves problem where sea units
- // would oscillate in and out of threatened city because they had iCurrentDanger = 0
- // on turns outside city
-
- bool bCheck = (iPass > 0) || (getGroup()->canDefend());
- if( !bCheck )
- {
- int iLoopDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopCity->plot());
- bCheck = (iLoopDanger == 0) || (iLoopDanger < iCurrentDanger);
- }
-
- if( bCheck )
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- iValue = iPathTurns;
- if (AI_getUnitAIType() == UNITAI_SETTLER_SEA)
- {
- iValue *= 1 + std::max(0, GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), UNITAI_SETTLE) - GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), UNITAI_SETTLER_SEA));
- }
- if (iValue < iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/27/08 jdog5000 */
- /* */
- /* Bugfix */
- /************************************************************************************************/
- // Not sure what can go wrong here, it seems somehow m_iData1 (moves) was set to 0
- // for first node in path so m_iData2 (turns) incremented
- if( atPlot(pBestPlot) )
- {
- //FAssert(false);
- pBestPlot = getGroup()->getPathFirstPlot();
- FAssert(!atPlot(pBestPlot));
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- break;
- }
- else if (iPass == 0)
- {
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- if (!bPrimary || GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pCity->area()))
- {
- if (!bAirlift || (pCity->getMaxAirlift() > 0))
- {
- if (!(pCity->plot()->isVisibleEnemyUnit(this)))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- }
- }
- }
- }
- }
- if (getGroup()->alwaysInvisible())
- {
- break;
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((iPass > 0) ? MOVE_IGNORE_DANGER : 0));
- return true;
- }
- if (pCity != NULL)
- {
- if (pCity->getTeam() == getTeam())
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/15/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- /* original bts code
- bool CvUnitAI::AI_pickup(UnitAITypes eUnitAI)
- */
- bool CvUnitAI::AI_pickup(UnitAITypes eUnitAI, bool bCountProduction, int iMaxPath)
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- PROFILE_FUNC();
- CvCity* pCity;
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- CvPlot* pBestPickupPlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- FAssert(cargoSpace() > 0);
- if (0 == cargoSpace())
- {
- return false;
- }
- pCity = plot()->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/23/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- /* original bts code
- if (pCity->plot()->plotCount(PUF_isUnitAIType, eUnitAI, -1, getOwnerINLINE()) > 0)
- {
- if ((AI_getUnitAIType() != UNITAI_ASSAULT_SEA) || pCity->AI_isDefended(-1))
- {
- */
- if( (GC.getGameINLINE().getGameTurn() - pCity->getGameTurnAcquired()) > 15 || (GET_TEAM(getTeam()).countEnemyPowerByArea(pCity->area()) == 0) )
- {
- bool bConsider = false;
- if(AI_getUnitAIType() == UNITAI_ASSAULT_SEA)
- {
- // Improve island hopping
- if( pCity->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE )
- {
- bConsider = false;
- }
- else if( eUnitAI == UNITAI_ATTACK_CITY && !(pCity->AI_isDanger()) )
- {
- bConsider = (pCity->plot()->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isDomainType, DOMAIN_LAND) > pCity->AI_neededDefenders());
- }
- else
- {
- bConsider = pCity->AI_isDefended(-1);
- }
- }
- else if(AI_getUnitAIType() == UNITAI_SETTLER_SEA)
- {
- if( eUnitAI == UNITAI_CITY_DEFENSE )
- {
- bConsider = (pCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isCityAIType) > 1);
- }
- else
- {
- bConsider = true;
- }
- }
- else
- {
- bConsider = true;
- }
-
- if ( bConsider )
- {
- // only count units which are available to load
- int iCount = pCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, eUnitAI, -1, getOwnerINLINE(), NO_TEAM, PUF_isFiniteRange);
-
- if (bCountProduction && (pCity->getProductionUnitAI() == eUnitAI))
- {
- if( pCity->getProductionTurnsLeft() < 4 )
- {
- CvUnitInfo& kUnitInfo = GC.getUnitInfo(pCity->getProductionUnit());
- if ((kUnitInfo.getDomainType() != DOMAIN_AIR) || kUnitInfo.getAirRange() > 0)
- {
- iCount++;
- }
- }
- }
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCity->plot(), MISSIONAI_PICKUP, getGroup()) < ((iCount + (cargoSpace() - 1)) / cargoSpace()))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_PICKUP, pCity->plot());
- return true;
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- }
- iBestValue = 0;
- pBestPlot = NULL;
- pBestPickupPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 01/23/09 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- if( (GC.getGameINLINE().getGameTurn() - pLoopCity->getGameTurnAcquired()) > 15 || (GET_TEAM(getTeam()).countEnemyPowerByArea(pLoopCity->area()) == 0) )
- {
- bool bConsider = false;
- if(AI_getUnitAIType() == UNITAI_ASSAULT_SEA)
- {
- if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE )
- {
- bConsider = false;
- }
- else if( eUnitAI == UNITAI_ATTACK_CITY && !(pLoopCity->AI_isDanger()) )
- {
- // Improve island hopping
- bConsider = (pLoopCity->plot()->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isDomainType, DOMAIN_LAND) > pLoopCity->AI_neededDefenders());
- }
- else
- {
- bConsider = pLoopCity->AI_isDefended(-1);
- }
- }
- else if(AI_getUnitAIType() == UNITAI_SETTLER_SEA)
- {
- if( eUnitAI == UNITAI_CITY_DEFENSE )
- {
- bConsider = (pLoopCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isCityAIType) > 1);
- }
- else
- {
- bConsider = true;
- }
- }
- else
- {
- bConsider = true;
- }
- if ( bConsider )
- {
- // only count units which are available to load, have had a chance to move since being built
- int iCount = pLoopCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, eUnitAI, -1, getOwnerINLINE(), NO_TEAM, (bCountProduction ? PUF_isFiniteRange : PUF_isFiniteRangeAndNotJustProduced));
- iValue = iCount * 10;
-
- if (bCountProduction && (pLoopCity->getProductionUnitAI() == eUnitAI))
- {
- CvUnitInfo& kUnitInfo = GC.getUnitInfo(pLoopCity->getProductionUnit());
- if ((kUnitInfo.getDomainType() != DOMAIN_AIR) || kUnitInfo.getAirRange() > 0)
- {
- iValue++;
- iCount++;
- }
- }
- if (iValue > 0)
- {
- iValue += pLoopCity->getPopulation();
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_PICKUP, getGroup()) < ((iCount + (cargoSpace() - 1)) / cargoSpace()))
- {
- if( !(pLoopCity->AI_isDanger()) )
- {
- if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- if( AI_getUnitAIType() == UNITAI_ASSAULT_SEA )
- {
- if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT )
- {
- iValue *= 4;
- }
- else if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT_ASSIST )
- {
- iValue *= 2;
- }
- }
- iValue *= 1000;
- iValue /= (iPathTurns + 3);
- if( (iValue > iBestValue) && (iPathTurns <= iMaxPath) )
- {
- iBestValue = iValue;
- // Do one turn along path, then reevaluate
- // Causes update of destination based on troop movement
- //pBestPlot = pLoopCity->plot();
- pBestPlot = getPathEndTurnPlot();
- pBestPickupPlot = pLoopCity->plot();
- if( pBestPlot == NULL || atPlot(pBestPlot) )
- {
- //FAssert(false);
- pBestPlot = pBestPickupPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if ((pBestPlot != NULL) && (pBestPickupPlot != NULL))
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_PICKUP, pBestPickupPlot);
- return true;
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
- /* */
- /* Naval AI */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_pickupStranded(UnitAITypes eUnitAI, int iMaxPath)
- {
- PROFILE_FUNC();
- CvUnit* pBestUnit;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- int iCount;
- FAssert(cargoSpace() > 0);
- if (0 == cargoSpace())
- {
- return false;
- }
- if( isBarbarian() )
- {
- return false;
- }
- iBestValue = 0;
- pBestUnit = NULL;
- int iI;
- CvSelectionGroup* pLoopGroup = NULL;
- CvUnit* pHeadUnit = NULL;
- CvPlot* pLoopPlot = NULL;
- CvPlot* pPickupPlot = NULL;
- CvPlot* pAdjacentPlot = NULL;
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- for(pLoopGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = kPlayer.nextSelectionGroup(&iLoop))
- {
- if( pLoopGroup->isStranded() )
- {
- pHeadUnit = pLoopGroup->getHeadUnit();
- if( pHeadUnit == NULL )
- {
- continue;
- }
- if( (eUnitAI != NO_UNITAI) && (pHeadUnit->AI_getUnitAIType() != eUnitAI) )
- {
- continue;
- }
- pLoopPlot = pHeadUnit->plot();
- if( pLoopPlot == NULL )
- {
- continue;
- }
- if( !(pLoopPlot->isCoastalLand()) && !canMoveAllTerrain() )
- {
- continue;
- }
- // Units are stranded, attempt rescue
- iCount = pLoopGroup->getNumUnits();
-
- if( 1000*iCount > iBestValue )
- {
- pPickupPlot = NULL;
- if( atPlot(pLoopPlot) )
- {
- pPickupPlot = pLoopPlot;
- iPathTurns = 0;
- }
- else if( AI_plotValid(pLoopPlot) && generatePath(pLoopPlot, 0, true, &iPathTurns) )
- {
- pPickupPlot = pLoopPlot;
- }
- else
- {
- for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot != NULL && atPlot(pLoopPlot))
- {
- pPickupPlot = pAdjacentPlot;
- iPathTurns = 0;
- break;
- }
- }
- if (pPickupPlot == NULL)
- {
- for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot != NULL && AI_plotValid(pAdjacentPlot))
- {
- if( generatePath(pAdjacentPlot, 0, true, &iPathTurns) )
- {
- pPickupPlot = pAdjacentPlot;
- break;
- }
- }
- }
- }
- }
- if( pPickupPlot != NULL && iPathTurns <= iMaxPath )
- {
- MissionAITypes eMissionAIType = MISSIONAI_PICKUP;
- iCount -= GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pHeadUnit, &eMissionAIType, 1, getGroup(), iPathTurns) * cargoSpace();
- iValue = 1000*iCount;
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pHeadUnit;
- }
- }
- }
- }
- }
- if ((pBestUnit != NULL))
- {
- if( atPlot(pBestUnit->plot()) )
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_PICKUP, pBestUnit->plot());
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestUnit->plot()));
- getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_PICKUP, NULL, pBestUnit);
- return true;
- }
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_airOffensiveCity()
- {
- //PROFILE_FUNC();
- CvPlot* pBestPlot;
- int iValue;
- int iBestValue;
- int iI;
- FAssert(canAirAttack() || nukeRange() >= 0);
- iBestValue = 0;
- pBestPlot = NULL;
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 04/25/08 jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- /* original BTS code
- */
- for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- // Limit to cities and forts, true for any city but only this team's forts
- if (pLoopPlot->isCity(true, getTeam()))
- {
- if (pLoopPlot->getTeam() == getTeam() || (pLoopPlot->isOwned() && GET_TEAM(pLoopPlot->getTeam()).isVassal(getTeam())))
- {
- if (atPlot(pLoopPlot) || canMoveInto(pLoopPlot))
- {
- iValue = AI_airOffenseBaseValue( pLoopPlot );
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
-
- if (pBestPlot != NULL)
- {
- if (!atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY);
- return true;
- }
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- return false;
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 04/25/10 jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- // Function for ranking the value of a plot as a base for offensive air units
- int CvUnitAI::AI_airOffenseBaseValue( CvPlot* pPlot )
- {
- if( pPlot == NULL || pPlot->area() == NULL )
- {
- return 0;
- }
- CvCity* pNearestEnemyCity = NULL;
- int iRange = 0;
- int iTempValue = 0;
- int iOurDefense = 0;
- int iOurOffense = 0;
- int iEnemyOffense = 0;
- int iEnemyDefense = 0;
- int iDistance = 0;
- CvPlot* pLoopPlot = NULL;
- CvCity* pCity = pPlot->getPlotCity();
- int iDefenders = pPlot->plotCount(PUF_canDefend, -1, -1, pPlot->getOwner());
- int iAttackAirCount = pPlot->plotCount(PUF_canAirAttack, -1, -1, NO_PLAYER, getTeam());
- iAttackAirCount += 2 * pPlot->plotCount(PUF_isUnitAIType, UNITAI_ICBM, -1, NO_PLAYER, getTeam());
- if (atPlot(pPlot))
- {
- iAttackAirCount += canAirAttack() ? -1 : 0;
- iAttackAirCount += (nukeRange() >= 0) ? -2 : 0;
- }
- if( pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()) )
- {
- iDefenders -= 1;
- }
- if( pCity != NULL )
- {
- if( pCity->getDefenseModifier(true) < 40 )
- {
- iDefenders -= 1;
- }
- if( pCity->getOccupationTimer() > 1 )
- {
- iDefenders -= 1;
- }
- }
- // Consider threat from nearby enemy territory
- iRange = 1;
- int iBorderDanger = 0;
- for (int iDX = -(iRange); iDX <= iRange; iDX++)
- {
- for (int iDY = -(iRange); iDY <= iRange; iDY++)
- {
- pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (pLoopPlot->area() == pPlot->area() && pLoopPlot->isOwned())
- {
- iDistance = stepDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
- if( pLoopPlot->getTeam() != getTeam() && !(GET_TEAM(pLoopPlot->getTeam()).isVassal(getTeam())) )
- {
- if( iDistance == 1 )
- {
- iBorderDanger++;
- }
- if (atWar(pLoopPlot->getTeam(), getTeam()))
- {
- if (iDistance == 1)
- {
- iBorderDanger += 2;
- }
- else if ((iDistance == 2) && (pLoopPlot->isRoute()))
- {
- iBorderDanger += 2;
- }
- }
- }
- }
- }
- }
- }
- iDefenders -= std::min(2,(iBorderDanger + 1)/3);
-
- // Don't put more attack air units on plot than effective land defenders ... too large a risk
- if (iAttackAirCount >= (iDefenders) || iDefenders <= 0)
- {
- return 0;
- }
-
- bool bAnyWar = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
- int iValue = 0;
- if( bAnyWar )
- {
- // Don't count assault assist, don't want to weight defending colonial coasts when homeland might be under attack
- bool bAssault = (pPlot->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT) || (pPlot->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT_MASSING);
- // Loop over operational range
- iRange = airRange();
- for (int iDX = -(iRange); iDX <= iRange; iDX++)
- {
- for (int iDY = -(iRange); iDY <= iRange; iDY++)
- {
- pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
-
- if ((pLoopPlot != NULL && pLoopPlot->area() != NULL))
- {
- iDistance = plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
- if( iDistance <= iRange )
- {
- bool bDefensive = pLoopPlot->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE;
- bool bOffensive = pLoopPlot->area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE;
- // Value system is based around 1 enemy military unit in our territory = 10 pts
- iTempValue = 0;
- if( pLoopPlot->isWater() )
- {
- if( pLoopPlot->isVisible(getTeam(),false) && !pLoopPlot->area()->isLake() )
- {
- // Defend ocean
- iTempValue = 1;
-
- if( pLoopPlot->isOwned() )
- {
- if( pLoopPlot->getTeam() == getTeam() )
- {
- iTempValue += 1;
- }
- else if ((pLoopPlot->getTeam() != getTeam()) && GET_TEAM(getTeam()).AI_getWarPlan(pLoopPlot->getTeam()) != NO_WARPLAN)
- {
- iTempValue += 1;
- }
- }
- // Low weight for visible ships cause they will probably move
- iTempValue += 2*pLoopPlot->getNumVisibleEnemyDefenders(this);
- if( bAssault )
- {
- iTempValue *= 2;
- }
- }
- }
- else
- {
- if( !(pLoopPlot->isOwned()) )
- {
- if( iDistance < (iRange - 2) )
- {
- // Target enemy troops in neutral territory
- iTempValue += 4*pLoopPlot->getNumVisibleEnemyDefenders(this);
- }
- }
- else if( pLoopPlot->getTeam() == getTeam() )
- {
- iTempValue = 0;
- if( iDistance < (iRange - 2) )
- {
- // Target enemy troops in our territory
- iTempValue += 5*pLoopPlot->getNumVisibleEnemyDefenders(this);
- if( pLoopPlot->getOwnerINLINE() == getOwnerINLINE() )
- {
- if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopPlot->area()) )
- {
- iTempValue *= 3;
- }
- else
- {
- iTempValue *= 2;
- }
- }
- if( bDefensive )
- {
- iTempValue *= 2;
- }
- }
- }
- else if ((pLoopPlot->getTeam() != getTeam()) && GET_TEAM(getTeam()).AI_getWarPlan(pLoopPlot->getTeam()) != NO_WARPLAN)
- {
- // Attack opponents land territory
- iTempValue = 3;
- CvCity* pLoopCity = pLoopPlot->getPlotCity();
- if (pLoopCity != NULL)
- {
- // Target enemy cities
- iTempValue += (3*pLoopCity->getPopulation() + 30);
- if( canAirBomb(pPlot) && pLoopCity->isBombardable(this) )
- {
- iTempValue *= 2;
- }
- if( pLoopPlot->area()->getTargetCity(getOwnerINLINE()) == pLoopCity )
- {
- iTempValue *= 2;
- }
- if( pLoopCity->AI_isDanger() )
- {
- // Multiplier for nearby troops, ours, teammate's, and any other enemy of city
- iTempValue *= 3;
- }
- }
- else
- {
- if( iDistance < (iRange - 2) )
- {
- // Support our troops in enemy territory
- iTempValue += 15*pLoopPlot->getNumDefenders(getOwnerINLINE());
- // Target enemy troops adjacent to our territory
- if( pLoopPlot->isAdjacentTeam(getTeam(),true) )
- {
- iTempValue += 7*pLoopPlot->getNumVisibleEnemyDefenders(this);
- }
- }
- // Weight resources
- if (canAirBombAt(pPlot, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
- {
- if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
- {
- iTempValue += 8*std::max(2, GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(pLoopPlot->getBonusType(getTeam()))/10);
- }
- }
- }
- if( (pLoopPlot->area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) )
- {
- // Extra weight for enemy territory in offensive areas
- iTempValue *= 2;
- }
- if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopPlot->area()) )
- {
- iTempValue *= 3;
- iTempValue /= 2;
- }
- if( pLoopPlot->isBarbarian() )
- {
- iTempValue /= 2;
- }
- }
- }
- iValue += iTempValue;
- }
- }
- }
- }
- // Consider available defense, direct threat to potential base
- iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(pPlot,0,true,false,true);
- iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pPlot,2,false,false);
- if( 3*iEnemyOffense > iOurDefense || iOurDefense == 0 )
- {
- iValue *= iOurDefense;
- iValue /= std::max(1,3*iEnemyOffense);
- }
- // Value forts less, they are generally riskier bases
- if( pCity == NULL )
- {
- iValue *= 2;
- iValue /= 3;
- }
- }
- else
- {
- if( pPlot->getOwnerINLINE() != getOwnerINLINE() )
- {
- // Keep planes at home when not in real wars
- return 0;
- }
- // If no wars, use prior logic with added value to keeping planes safe from sneak attack
- if (pCity != NULL)
- {
- iValue = (pCity->getPopulation() + 20);
- iValue += pCity->AI_cityThreat();
- }
- else
- {
- if( iDefenders > 0 )
- {
- iValue = (pCity != NULL) ? 0 : GET_PLAYER(getOwnerINLINE()).AI_getPlotAirbaseValue(pPlot);
- iValue /= 6;
- }
- }
- iValue += std::min(24, 3*(iDefenders - iAttackAirCount));
- if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pPlot->area()) )
- {
- iValue *= 4;
- iValue /= 3;
- }
- // No real enemies, check for minor civ or barbarian cities where attacks could be supported
- pNearestEnemyCity = GC.getMapINLINE().findCity(pPlot->getX_INLINE(), pPlot->getY_INLINE(), NO_PLAYER, NO_TEAM, false, false, getTeam());
- if (pNearestEnemyCity != NULL)
- {
- iDistance = plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pNearestEnemyCity->getX_INLINE(), pNearestEnemyCity->getY_INLINE());
- if (iDistance > airRange())
- {
- iValue /= 10 * (2 + airRange());
- }
- else
- {
- iValue /= 2 + iDistance;
- }
- }
- }
-
- if (pPlot->getOwnerINLINE() == getOwnerINLINE())
- {
- // Bases in our territory better than teammate's
- iValue *= 2;
- }
- else if( pPlot->getTeam() == getTeam() )
- {
- // Our team's bases are better than vassal plots
- iValue *= 3;
- iValue /= 2;
- }
- return iValue;
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_airDefensiveCity()
- {
- //PROFILE_FUNC();
- CvCity* pCity;
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- int iValue;
- int iBestValue;
- int iLoop;
- FAssert(getDomainType() == DOMAIN_AIR);
- FAssert(canAirDefend());
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/26/08 jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- if (canAirDefend() && getDamage() == 0)
- {
- pCity = plot()->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- if ( !(pCity->AI_isAirDefended(false,+1)) )
- {
- // Stay if very short on planes, regardless of situation
- getGroup()->pushMission(MISSION_AIRPATROL);
- return true;
- }
-
- if( !(pCity->AI_isAirDefended(true,-1)) )
- {
- // Stay if city is threatened but not seriously threatened
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
-
- if (iEnemyOffense > 0)
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- if( 3*iEnemyOffense < 4*iOurDefense )
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return true;
- }
- }
- }
- }
- }
- }
- iBestValue = 0;
- pBestPlot = NULL;
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- if (canAirDefend(pLoopCity->plot()))
- {
- if (atPlot(pLoopCity->plot()) || canMoveInto(pLoopCity->plot()))
- {
- int iExistingAirDefenders = pLoopCity->plot()->plotCount(PUF_canAirDefend, -1, -1, pLoopCity->getOwnerINLINE(), NO_TEAM, PUF_isDomainType, DOMAIN_AIR);
- if( atPlot(pLoopCity->plot()) )
- {
- iExistingAirDefenders -= 1;
- }
- int iNeedAirDefenders = pLoopCity->AI_neededAirDefenders();
-
- if ( iNeedAirDefenders > iExistingAirDefenders )
- {
- iValue = pLoopCity->getPopulation() + pLoopCity->AI_cityThreat();
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(pLoopCity->plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pLoopCity->plot(),2,false,false);
-
- iValue *= 100;
- // Increase value of cities needing air defense more
- iValue *= std::max(1, 3 + iNeedAirDefenders - iExistingAirDefenders);
- if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopCity->area()) )
- {
- iValue *= 4;
- iValue /= 3;
- }
- // Reduce value of endangered city, it may be too late to help
- if (3*iEnemyOffense > iOurDefense || iOurDefense == 0)
- {
- iValue *= iOurDefense;
- iValue /= std::max(1,3*iEnemyOffense);
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- if (pBestPlot != NULL && !atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_airCarrier()
- {
- //PROFILE_FUNC();
- CvUnit* pLoopUnit;
- CvUnit* pBestUnit;
- int iValue;
- int iBestValue;
- int iLoop;
- if (getCargo() > 0)
- {
- return false;
- }
- if (isCargo())
- {
- if (canAirDefend())
- {
- getGroup()->pushMission(MISSION_AIRPATROL);
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- }
- iBestValue = 0;
- pBestUnit = NULL;
- for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
- {
- if (canLoadUnit(pLoopUnit, pLoopUnit->plot()))
- {
- iValue = 10;
- if (!(pLoopUnit->plot()->isCity()))
- {
- iValue += 20;
- }
- if (pLoopUnit->plot()->isOwned())
- {
- if (isEnemy(pLoopUnit->plot()->getTeam(), pLoopUnit->plot()))
- {
- iValue += 20;
- }
- }
- else
- {
- iValue += 10;
- }
- iValue /= (pLoopUnit->getCargo() + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopUnit;
- }
- }
- }
- if (pBestUnit != NULL)
- {
- if (atPlot(pBestUnit->plot()))
- {
- setTransportUnit(pBestUnit); // XXX is this dangerous (not pushing a mission...) XXX air units?
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestUnit->getX_INLINE(), pBestUnit->getY_INLINE());
- return true;
- }
- }
- return false;
- }
- bool CvUnitAI::AI_missileLoad(UnitAITypes eTargetUnitAI, int iMaxOwnUnitAI, bool bStealthOnly)
- {
- //PROFILE_FUNC();
- CvUnit* pBestUnit = NULL;
- int iBestValue = 0;
- int iLoop;
- CvUnit* pLoopUnit;
- for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
- {
- if (!bStealthOnly || pLoopUnit->getInvisibleType() != NO_INVISIBLE)
- {
- if (pLoopUnit->AI_getUnitAIType() == eTargetUnitAI)
- {
- if ((iMaxOwnUnitAI == -1) || (pLoopUnit->getUnitAICargo(AI_getUnitAIType()) <= iMaxOwnUnitAI))
- {
- if (canLoadUnit(pLoopUnit, pLoopUnit->plot()))
- {
- int iValue = 100;
- iValue += GC.getGame().getSorenRandNum(100, "AI missile load");
- iValue *= 1 + pLoopUnit->getCargo();
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopUnit;
- }
- }
- }
- }
- }
- }
- if (pBestUnit != NULL)
- {
- if (atPlot(pBestUnit->plot()))
- {
- setTransportUnit(pBestUnit); // XXX is this dangerous (not pushing a mission...) XXX air units?
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestUnit->getX_INLINE(), pBestUnit->getY_INLINE());
- setTransportUnit(pBestUnit);
- return true;
- }
- }
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_airStrike()
- {
- //PROFILE_FUNC();
- CvUnit* pDefender;
- CvUnit* pInterceptor;
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iDamage;
- int iPotentialAttackers;
- int iInterceptProb;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- iSearchRange = airRange();
- iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (5 * m_pUnitInfo->getProductionCost()) / 6 : 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (canMoveInto(pLoopPlot, true))
- {
- iValue = 0;
- iPotentialAttackers = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);
- if (pLoopPlot->isCity())
- {
- iPotentialAttackers += GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ASSAULT, getGroup(), 1) * 2;
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 10/13/08 jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- /* original BTS code
- if (pLoopPlot->isWater() || (iPotentialAttackers > 0) || pLoopPlot->isAdjacentTeam(getTeam()))
- */
- // Bombers will always consider striking units adjacent to this team's territory
- // to soften them up for potential attack. This situation doesn't apply if this team's adjacent
- // territory is water, land units won't be able to reach easily for attack
- if (pLoopPlot->isWater() || (iPotentialAttackers > 0) || pLoopPlot->isAdjacentTeam(getTeam(),true))
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- {
- pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
- FAssert(pDefender != NULL);
- FAssert(pDefender->canDefend());
- // XXX factor in air defenses...
- iDamage = airCombatDamage(pDefender);
- iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));
- iValue += ((((iDamage * collateralDamage()) / 100) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / 2);
- iValue *= (3 + iPotentialAttackers);
- iValue /= 4;
- pInterceptor = bestInterceptor(pLoopPlot);
- if (pInterceptor != NULL)
- {
- iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
- iInterceptProb *= std::max(0, (100 - evasionProbability()));
- iInterceptProb /= 100;
- iValue *= std::max(0, 100 - iInterceptProb / 2);
- iValue /= 100;
- }
- if (pLoopPlot->isWater())
- {
- iValue *= 3;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD 9/16/08 jdog5000 */
- /* */
- /* Air AI */
- /********************************************************************************/
- // Air strike focused on weakening enemy stacks threatening our cities
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_defensiveAirStrike()
- {
- PROFILE_FUNC();
- CvUnit* pDefender;
- CvUnit* pInterceptor;
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iDamage;
- int iInterceptProb;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- iSearchRange = airRange();
- iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (60 * m_pUnitInfo->getProductionCost()) : 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (canMoveInto(pLoopPlot, true)) // Only true of plots this unit can airstrike
- {
- // Only attack enemy land units near our cities
- if( pLoopPlot->isPlayerCityRadius(getOwnerINLINE()) && !pLoopPlot->isWater() )
- {
- CvCity* pClosestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), getOwnerINLINE(), getTeam(), true, false);
- if( pClosestCity != NULL )
- {
- // City and pLoopPlot forced to be in same area, check they're still close
- int iStepDist = plotDistance(pClosestCity->getX_INLINE(), pClosestCity->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
- if( iStepDist < 3 )
- {
- iValue = 0;
- pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
- FAssert(pDefender != NULL);
- FAssert(pDefender->canDefend());
- iDamage = airCombatDamage(pDefender);
- iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));
- iValue += ((((iDamage * collateralDamage()) / 100) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / 2);
- iValue *= GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pClosestCity->plot(),2,false,false);
- iValue /= std::max(1, GET_TEAM(getTeam()).AI_getOurPlotStrength(pClosestCity->plot(),0,true,false,true));
- if( iStepDist == 1 )
- {
- iValue *= 5;
- iValue /= 4;
- }
- pInterceptor = bestInterceptor(pLoopPlot);
- if (pInterceptor != NULL)
- {
- iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
- iInterceptProb *= std::max(0, (100 - evasionProbability()));
- iInterceptProb /= 100;
- iValue *= std::max(0, 100 - iInterceptProb / 2);
- iValue /= 100;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- // Air strike around base city
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_defendBaseAirStrike()
- {
- PROFILE_FUNC();
- CvUnit* pDefender;
- CvUnit* pInterceptor;
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iDamage;
- int iInterceptProb;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- // Only search around base
- int iSearchRange = 2;
- iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (15 * m_pUnitInfo->getProductionCost()) : 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (canMoveInto(pLoopPlot, true) && !pLoopPlot->isWater()) // Only true of plots this unit can airstrike
- {
- if( plot()->area() == pLoopPlot->area() )
- {
- iValue = 0;
- pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
- FAssert(pDefender != NULL);
- FAssert(pDefender->canDefend());
- iDamage = airCombatDamage(pDefender);
- iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));
- iValue += ((iDamage * collateralDamage()) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / (2*100);
- // Weight towards stronger units
- iValue *= (pDefender->currCombatStr(NULL,NULL,NULL) + 2000);
- iValue /= 2000;
- // Weight towards adjacent stacks
- if( plotDistance(plot()->getX_INLINE(), plot()->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) == 1 )
- {
- iValue *= 5;
- iValue /= 4;
- }
- pInterceptor = bestInterceptor(pLoopPlot);
- if (pInterceptor != NULL)
- {
- iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
- iInterceptProb *= std::max(0, (100 - evasionProbability()));
- iInterceptProb /= 100;
- iValue *= std::max(0, 100 - iInterceptProb / 2);
- iValue /= 100;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- /********************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /********************************************************************************/
- bool CvUnitAI::AI_airBombPlots()
- {
- //PROFILE_FUNC();
- CvUnit* pInterceptor;
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iInterceptProb;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- iSearchRange = airRange();
- iBestValue = 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (!pLoopPlot->isCity() && pLoopPlot->isOwned() && pLoopPlot != plot())
- {
- if (canAirBombAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
- {
- iValue = 0;
- if (pLoopPlot->getBonusType(pLoopPlot->getTeam()) != NO_BONUS)
- {
- iValue += AI_pillageValue(pLoopPlot, 15);
- iValue += GC.getGameINLINE().getSorenRandNum(10, "AI Air Bomb");
- }
- else if (isSuicide())
- {
- //This should only be reached when the unit is desperate to die
- iValue += AI_pillageValue(pLoopPlot);
- // Guided missiles lean towards destroying resource-producing tiles as opposed to improvements like Towns
- if (pLoopPlot->getBonusType(pLoopPlot->getTeam()) != NO_BONUS)
- {
- //and even more so if it's a resource
- iValue += GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(pLoopPlot->getBonusType(pLoopPlot->getTeam()));
- }
- }
- if (iValue > 0)
- {
- pInterceptor = bestInterceptor(pLoopPlot);
- if (pInterceptor != NULL)
- {
- iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
- iInterceptProb *= std::max(0, (100 - evasionProbability()));
- iInterceptProb /= 100;
- iValue *= std::max(0, 100 - iInterceptProb / 2);
- iValue /= 100;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_AIRBOMB, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_airBombDefenses()
- {
- //PROFILE_FUNC();
- CvCity* pCity;
- CvUnit* pInterceptor;
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iPotentialAttackers;
- int iInterceptProb;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- iSearchRange = airRange();
- iBestValue = 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- pCity = pLoopPlot->getPlotCity();
- if (pCity != NULL)
- {
- iValue = 0;
- if (canAirBombAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
- {
- iPotentialAttackers = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);
- iPotentialAttackers += std::max(0, GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCity->plot(), NO_MISSIONAI, getGroup(), 2) - 4);
- if (iPotentialAttackers > 1)
- {
- iValue += std::max(0, (std::min((pCity->getDefenseDamage() + airBombCurrRate()), GC.getMAX_CITY_DEFENSE_DAMAGE()) - pCity->getDefenseDamage()));
- iValue *= 4 + iPotentialAttackers;
- if (pCity->AI_isDanger())
- {
- iValue *= 2;
- }
- if (pCity == pCity->area()->getTargetCity(getOwnerINLINE()))
- {
- iValue *= 2;
- }
- }
- if (iValue > 0)
- {
- pInterceptor = bestInterceptor(pLoopPlot);
- if (pInterceptor != NULL)
- {
- iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();
- iInterceptProb *= std::max(0, (100 - evasionProbability()));
- iInterceptProb /= 100;
- iValue *= std::max(0, 100 - iInterceptProb / 2);
- iValue /= 100;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_AIRBOMB, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_exploreAir()
- {
- PROFILE_FUNC();
- CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
- CvPlot* pBestPlot = NULL;
- int iBestValue = 0;
- CvPlot* pLoopPlot;
- int iSearchRange;
- int iValue;
- int iDX, iDY;
- /*
- for (int iI = 0; iI < MAX_PLAYERS; iI++)
- {
- if (GET_PLAYER((PlayerTypes)iI).isAlive() && !GET_PLAYER((PlayerTypes)iI).isBarbarian())
- {
- if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
- {
- for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
- {
- if (!pLoopCity->isVisible(getTeam(), false))
- {
- if (canReconAt(plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
- {
- iValue = 1 + GC.getGame().getSorenRandNum(15, "AI explore air");
- if (isEnemy(GET_PLAYER((PlayerTypes)iI).getTeam()))
- {
- iValue += 10;
- iValue += std::min(10, pLoopCity->area()->getNumAIUnits(getOwnerINLINE(), UNITAI_ATTACK_CITY));
- iValue += 10 * kPlayer.AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ASSAULT);
- }
- iValue *= plotDistance(getX_INLINE(), getY_INLINE(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE());
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_RECON, pBestPlot->getX(), pBestPlot->getY());
- return true;
- }
- */
- iSearchRange = airRange();
- iBestValue = 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (pLoopPlot != plot())
- {
- if (canReconAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
- {
- iValue = 1 + GC.getGame().getSorenRandNum(10, "AI explore air");
- iValue *= plotDistance(getX_INLINE(), getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
- if (pLoopPlot->isPeak())
- {
- iValue += 3;
- }
- if (!pLoopPlot->isVisible(getTeam(), false))
- {
- iValue += 10;
- }
- if (pLoopPlot->isOwned())
- {
- if (GET_TEAM(getTeam()).isAtWar(pLoopPlot->getTeam()))
- {
- iValue += 5;
- }
- if (pLoopPlot->getOwner() != getOwner())
- {
- iValue *= 2;
- }
- }
- if (pLoopPlot->isCity())
- {
- iValue *= 5;
- }
- if (!pLoopPlot->isRevealed(getTeam(), false))
- {
- iValue *= 2;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- logBBAI(" ...recon at %d, %d", pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- getGroup()->pushMission(MISSION_RECON, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
-
- return false;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_nuke()
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvCity* pBestCity;
- int iValue;
- int iBestValue;
- int iLoop;
- int iI;
- pBestCity = NULL;
- iBestValue = 0;
- for (iI = 0; iI < MAX_PLAYERS; iI++)
- {
- if (GET_PLAYER((PlayerTypes)iI).isAlive() && !GET_PLAYER((PlayerTypes)iI).isBarbarian())
- {
- if (isEnemy(GET_PLAYER((PlayerTypes)iI).getTeam()))
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) == ATTITUDE_FURIOUS)
- {
- for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
- {
- if (canNukeAt(plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
- {
- iValue = AI_nukeValue(pLoopCity);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestCity = pLoopCity;
- FAssert(pBestCity->getTeam() != getTeam());
- }
- }
- }
- }
- }
- }
- }
- if (pBestCity != NULL)
- {
- getGroup()->pushMission(MISSION_NUKE, pBestCity->getX_INLINE(), pBestCity->getY_INLINE());
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_nukeRange(int iRange)
- {
- CvPlot* pBestPlot = NULL;
- int iBestValue = 0;
- for (int iDX = -(iRange); iDX <= iRange; iDX++)
- {
- for (int iDY = -(iRange); iDY <= iRange; iDY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (canNukeAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
- {
- int iValue = -99;
- for (int iDX2 = -(nukeRange()); iDX2 <= nukeRange(); iDX2++)
- {
- for (int iDY2 = -(nukeRange()); iDY2 <= nukeRange(); iDY2++)
- {
- CvPlot* pLoopPlot2 = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iDX2, iDY2);
- if (pLoopPlot2 != NULL)
- {
- int iEnemyCount = 0;
- int iTeamCount = 0;
- int iNeutralCount = 0;
- int iDamagedEnemyCount = 0;
- CLLNode<IDInfo>* pUnitNode;
- CvUnit* pLoopUnit;
- pUnitNode = pLoopPlot2->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot2->nextUnitNode(pUnitNode);
- if (!pLoopUnit->isNukeImmune())
- {
- if (pLoopUnit->getTeam() == getTeam())
- {
- iTeamCount++;
- }
- else if (!pLoopUnit->isInvisible(getTeam(), false))
- {
- if (isEnemy(pLoopUnit->getTeam()))
- {
- iEnemyCount++;
- if (pLoopUnit->getDamage() * 2 > pLoopUnit->maxHitPoints())
- {
- iDamagedEnemyCount++;
- }
- }
- else
- {
- iNeutralCount++;
- }
- }
- }
- }
- iValue += (iEnemyCount + iDamagedEnemyCount) * (pLoopPlot2->isWater() ? 25 : 12);
- iValue -= iTeamCount * 15;
- iValue -= iNeutralCount * 20;
- int iMultiplier = 1;
- if (pLoopPlot2->getTeam() == getTeam())
- {
- iMultiplier = -2;
- }
- else if (isEnemy(pLoopPlot2->getTeam()))
- {
- iMultiplier = 1;
- }
- else if (!pLoopPlot2->isOwned())
- {
- iMultiplier = 0;
- }
- else
- {
- iMultiplier = -10;
- }
- if (pLoopPlot2->getImprovementType() != NO_IMPROVEMENT)
- {
- iValue += iMultiplier * 10;
- }
- if (pLoopPlot2->getBonusType() != NO_BONUS)
- {
- iValue += iMultiplier * 20;
- }
- if (pLoopPlot2->isCity())
- {
- iValue += std::max(0, iMultiplier * (-20 + 15 * pLoopPlot2->getPlotCity()->getPopulation()));
- }
- }
- }
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- getGroup()->pushMission(MISSION_NUKE, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_trade(int iValueThreshold)
- {
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- CvPlot* pBestTradePlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- int iI;
- iBestValue = 0;
- pBestPlot = NULL;
- pBestTradePlot = NULL;
- for (iI = 0; iI < MAX_PLAYERS; iI++)
- {
- if (GET_PLAYER((PlayerTypes)iI).isAlive())
- {
- for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
- {
- if (pLoopCity->isRevealed(getTeam(), false))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- if (getTeam() != pLoopCity->getTeam())
- {
- iValue = getTradeGold(pLoopCity->plot());
- if ((iValue >= iValueThreshold) && canTrade(pLoopCity->plot(), true))
- {
- if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
- {
- if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- FAssert(iPathTurns > 0);
- iValue /= (4 + iPathTurns);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- pBestTradePlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestTradePlot != NULL))
- {
- if (atPlot(pBestTradePlot))
- {
- logBBAI(" %S (%d) starting Trade Mission at %d, %d", getName().GetCString(), getID(), pBestPlot->getX(), pBestPlot->getY());
- getGroup()->pushMission(MISSION_TRADE);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- logBBAI(" %S (%d) moving to %d, %d for Trade Mission", getName().GetCString(), getID(), pBestPlot->getX(), pBestPlot->getY());
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- }
- return false;
- }
- bool CvUnitAI::AI_infiltrate()
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- int iI;
- iBestValue = 0;
- pBestPlot = NULL;
- if (canInfiltrate(plot()))
- {
- getGroup()->pushMission(MISSION_INFILTRATE);
- return true;
- }
- for (iI = 0; iI < MAX_PLAYERS; iI++)
- {
- if ((GET_PLAYER((PlayerTypes)iI).isAlive()) && GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
- {
- for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
- {
- if (canInfiltrate(pLoopCity->plot()))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check area for land units before generating path
- if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
- {
- continue;
- }
- iValue = getEspionagePoints(pLoopCity->plot());
-
- if (iValue > iBestValue)
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- FAssert(iPathTurns > 0);
- if (getPathLastNode()->m_iData1 == 0)
- {
- iPathTurns++;
- }
- iValue /= 1 + iPathTurns;
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL))
- {
- if (atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_INFILTRATE);
- return true;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- getGroup()->pushMission(MISSION_INFILTRATE, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0));
- return true;
- }
- }
- return false;
- }
- bool CvUnitAI::AI_reconSpy(int iRange)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- int iX, iY;
- CvPlot* pBestPlot = NULL;
- CvPlot* pBestTargetPlot = NULL;
- int iBestValue = 0;
- int iSearchRange = AI_searchRange(iRange);
- for (iX = -iSearchRange; iX <= iSearchRange; iX++)
- {
- for (iY = -iSearchRange; iY <= iSearchRange; iY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
- int iDistance = stepDistance(0, 0, iX, iY);
- if ((iDistance > 0) && (pLoopPlot != NULL) && AI_plotValid(pLoopPlot))
- {
- int iValue = 0;
- if (pLoopPlot->getPlotCity() != NULL)
- {
- iValue += GC.getGameINLINE().getSorenRandNum(4000, "AI Spy Scout City");
- }
- if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
- {
- iValue += GC.getGameINLINE().getSorenRandNum(1000, "AI Spy Recon Bonus");
- }
- for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- CvPlot* pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot != NULL)
- {
- if (!pAdjacentPlot->isRevealed(getTeam(), false))
- {
- iValue += 500;
- }
- else if (!pAdjacentPlot->isVisible(getTeam(), false))
- {
- iValue += 200;
- }
- }
- }
- if (iValue > 0)
- {
- int iPathTurns;
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= iRange)
- {
- // don't give each and every plot in range a value before generating the patch (performance hit)
- iValue += GC.getGameINLINE().getSorenRandNum(250, "AI Spy Scout Best Plot");
- iValue *= iDistance;
- /* Can no longer perform missions after having moved
- if (getPathLastNode()->m_iData2 == 1)
- {
- if (getPathLastNode()->m_iData1 > 0)
- {
- //Prefer to move and have movement remaining to perform a kill action.
- iValue *= 2;
- }
- } */
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestTargetPlot = getPathEndTurnPlot();
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- if ((pBestPlot != NULL) && (pBestTargetPlot != NULL))
- {
- if (atPlot(pBestTargetPlot))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestTargetPlot->getX_INLINE(), pBestTargetPlot->getY_INLINE());
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- }
-
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 10/25/09 jdog5000 */
- /* */
- /* Espionage AI */
- /************************************************************************************************/
- /// \brief Spy decision on whether to cause revolt in besieged city
- ///
- /// Have spy breakdown city defenses if we have troops in position to capture city this turn.
- bool CvUnitAI::AI_revoltCitySpy()
- {
- PROFILE_FUNC();
- CvCity* pCity = plot()->getPlotCity();
- FAssert(pCity != NULL);
- if( pCity == NULL )
- {
- return false;
- }
- if( !(GET_TEAM(getTeam()).isAtWar(pCity->getTeam())) )
- {
- return false;
- }
- if( pCity->isDisorder() )
- {
- return false;
- }
- int iOurPower = GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(),1,false,true);
- int iEnemyDefensePower = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),0,true,false);
- int iEnemyPostPower = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),0,false,false);
- if( iOurPower > 2*iEnemyDefensePower )
- {
- return false;
- }
- if( iOurPower < iEnemyPostPower )
- {
- return false;
- }
- if( 10*iEnemyDefensePower < 11*iEnemyPostPower )
- {
- return false;
- }
- for (int iMission = 0; iMission < GC.getNumEspionageMissionInfos(); ++iMission)
- {
- CvEspionageMissionInfo& kMissionInfo = GC.getEspionageMissionInfo((EspionageMissionTypes)iMission);
- if ((kMissionInfo.getCityRevoltCounter() > 0) || (kMissionInfo.getPlayerAnarchyCounter() > 0))
- {
- if (!GET_PLAYER(getOwnerINLINE()).canDoEspionageMission((EspionageMissionTypes)iMission, pCity->getOwnerINLINE(), pCity->plot(), -1, this))
- {
- continue;
- }
-
- if (!espionage((EspionageMissionTypes)iMission, -1))
- {
- continue;
- }
- return true;
- }
- }
- return false;
- }
- int CvUnitAI::AI_getEspionageTargetValue(CvPlot* pPlot, int iMaxPath)
- {
- PROFILE_FUNC();
- CvTeamAI& kTeam = GET_TEAM(getTeam());
- int iValue = 0;
- if (pPlot->isOwned() && pPlot->getTeam() != getTeam() && !GET_TEAM(getTeam()).isVassal(pPlot->getTeam()))
- {
- if (AI_plotValid(pPlot))
- {
- CvCity* pCity = pPlot->getPlotCity();
- if (pCity != NULL)
- {
- iValue += pCity->getPopulation();
- iValue += pCity->plot()->calculateCulturePercent(getOwnerINLINE())/8;
- // BBAI TODO: Should go to cities where missions will be cheaper ...
- int iRand = GC.getGame().getSorenRandNum(6, "AI spy choose city");
- iValue += iRand * iRand;
- if( area()->getTargetCity(getOwnerINLINE()) == pCity )
- {
- iValue += 30;
- }
- if( GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pPlot, MISSIONAI_ASSAULT, getGroup()) > 0 )
- {
- iValue += 30;
- }
- // BBAI TODO: What else? If can see production, go for wonders and space race ...
- }
- else
- {
- BonusTypes eBonus = pPlot->getNonObsoleteBonusType(getTeam());
- if (eBonus != NO_BONUS)
- {
- iValue += GET_PLAYER(pPlot->getOwnerINLINE()).AI_baseBonusVal(eBonus) - 10;
- }
- }
- int iPathTurns;
- if (generatePath(pPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= iMaxPath)
- {
- if (kTeam.AI_getWarPlan(pPlot->getTeam()) == NO_WARPLAN)
- {
- iValue *= 1;
- }
- else if (kTeam.AI_isSneakAttackPreparing(pPlot->getTeam()))
- {
- iValue *= (pPlot->isCity()) ? 15 : 10;
- }
- else
- {
- iValue *= 3;
- }
- iValue *= 3;
- iValue /= (3 + GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pPlot, MISSIONAI_ATTACK_SPY, getGroup()));
- }
- }
- }
- }
- return iValue;
- }
- bool CvUnitAI::AI_cityOffenseSpy(int iMaxPath, CvCity* pSkipCity)
- {
- PROFILE_FUNC();
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; ++iPlayer)
- {
- CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iPlayer);
- if (kLoopPlayer.isAlive() && kLoopPlayer.getTeam() != getTeam() && !GET_TEAM(getTeam()).isVassal(kLoopPlayer.getTeam()))
- {
- // Only move to cities where we will run missions
- if (GET_PLAYER(getOwnerINLINE()).AI_getAttitudeWeight((PlayerTypes)iPlayer) < (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 51 : 1)
- || GET_TEAM(getTeam()).AI_getWarPlan(kLoopPlayer.getTeam()) != NO_WARPLAN
- || GET_TEAM(getTeam()).getBestKnownTechScorePercent() < 85 )
- {
- int iLoop;
- for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
- {
- if( pLoopCity == pSkipCity )
- {
- continue;
- }
- if (pLoopCity->area() == area() || canMoveAllTerrain())
- {
- CvPlot* pLoopPlot = pLoopCity->plot();
- if (AI_plotValid(pLoopPlot))
- {
- int iValue = AI_getEspionageTargetValue(pLoopPlot, iMaxPath);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
-
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY );
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
- }
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_bonusOffenseSpy(int iRange)
- {
- PROFILE_FUNC();
- CvPlot* pBestPlot = NULL;
- int iBestValue = 10;
- int iSearchRange = AI_searchRange(iRange);
- for (int iX = -iSearchRange; iX <= iSearchRange; iX++)
- {
- for (int iY = -iSearchRange; iY <= iSearchRange; iY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
- if (NULL != pLoopPlot && pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
- {
- if( pLoopPlot->isOwned() && pLoopPlot->getTeam() != getTeam() )
- {
- // Only move to plots where we will run missions
- if (GET_PLAYER(getOwnerINLINE()).AI_getAttitudeWeight(pLoopPlot->getOwner()) < (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 51 : 1)
- || GET_TEAM(getTeam()).AI_getWarPlan(pLoopPlot->getTeam()) != NO_WARPLAN )
- {
- int iValue = AI_getEspionageTargetValue(pLoopPlot, iRange);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY);
- getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
- return true;
- }
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- //Returns true if the spy performs espionage.
- bool CvUnitAI::AI_espionageSpy()
- {
- PROFILE_FUNC();
- if (!canEspionage(plot()))
- {
- return false;
- }
- EspionageMissionTypes eBestMission = NO_ESPIONAGEMISSION;
- CvPlot* pTargetPlot = NULL;
- PlayerTypes eTargetPlayer = NO_PLAYER;
- int iExtraData = -1;
- eBestMission = GET_PLAYER(getOwnerINLINE()).AI_bestPlotEspionage(plot(), eTargetPlayer, pTargetPlot, iExtraData);
- if (NO_ESPIONAGEMISSION == eBestMission)
- {
- return false;
- }
- if (!GET_PLAYER(getOwnerINLINE()).canDoEspionageMission(eBestMission, eTargetPlayer, pTargetPlot, iExtraData, this))
- {
- return false;
- }
- if (!espionage(eBestMission, iExtraData))
- {
- return false;
- }
- return true;
- }
- bool CvUnitAI::AI_moveToStagingCity()
- {
- PROFILE_FUNC();
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iLoop;
- iBestValue = 0;
- pBestPlot = NULL;
- int iWarCount = 0;
- TeamTypes eTargetTeam = NO_TEAM;
- CvTeam& kTeam = GET_TEAM(getTeam());
- for (int iI = 0; iI < MAX_TEAMS; iI++)
- {
- if ((iI != getTeam()) && GET_TEAM((TeamTypes)iI).isAlive())
- {
- if (kTeam.AI_isSneakAttackPreparing((TeamTypes)iI))
- {
- eTargetTeam = (TeamTypes)iI;
- iWarCount++;
- }
- }
- }
- if (iWarCount > 1)
- {
- eTargetTeam = NO_TEAM;
- }
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 02/22/10 jdog5000 */
- /* */
- /* War tactics AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check same area
- if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
- {
- // BBAI TODO: Need some knowledge of whether this is a good city to attack from ... only get that
- // indirectly from threat.
- iValue = pLoopCity->AI_cityThreat();
- // Have attack stacks in assault areas move to coastal cities for faster loading
- if( (area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT) || (area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT_MASSING) )
- {
- CvArea* pWaterArea = pLoopCity->waterArea();
- if( pWaterArea != NULL && GET_TEAM(getTeam()).AI_isWaterAreaRelevant(pWaterArea) )
- {
- // BBAI TODO: Need a better way to determine which cities should serve as invasion launch locations
- // Inertia so units don't just chase transports around the map
- iValue = iValue/2;
- if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT )
- {
- // If in assault, transports may be at sea ... tend to stay where they left from
- // to speed reinforcement
- iValue += pLoopCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, UNITAI_ATTACK_CITY, -1, getOwnerINLINE());
- }
- // Attraction to cities which are serving as launch/pickup points
- iValue += 3*pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_ASSAULT_SEA, -1, getOwnerINLINE());
- iValue += 2*pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_ESCORT_SEA, -1, getOwnerINLINE());
- iValue += 5*GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_PICKUP);
- }
- else
- {
- iValue = iValue/8;
- }
- }
- if (iValue*200 > iBestValue)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- iValue *= 1000;
- iValue /= (5 + iPathTurns);
- if ((pLoopCity->plot() != plot()) && pLoopCity->isVisible(eTargetTeam, false))
- {
- iValue /= 2;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- //pBestPlot = getPathEndTurnPlot();
- pBestPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- logBBAI(" ...moving to Staging City %S at %d, %d", pBestPlot->getPlotCity()->getName().GetCString(), pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- }
- return false;
- }
- /*
- bool CvUnitAI::AI_seaRetreatFromCityDanger()
- {
- if (plot()->isCity(true) && GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) //prioritize getting outta there
- {
- if (AI_anyAttack(2, 40))
- {
- return true;
- }
- if (AI_anyAttack(4, 50))
- {
- return true;
- }
- if (AI_retreatToCity())
- {
- return true;
- }
- if (AI_safety())
- {
- return true;
- }
- }
- return false;
- }
- bool CvUnitAI::AI_airRetreatFromCityDanger()
- {
- if (plot()->isCity(true))
- {
- CvCity* pCity = plot()->getPlotCity();
- if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0 || (pCity != NULL && !pCity->AI_isDefended()))
- {
- if (AI_airOffensiveCity())
- {
- return true;
- }
- if (canAirDefend() && AI_airDefensiveCity())
- {
- return true;
- }
- }
- }
- return false;
- }
- bool CvUnitAI::AI_airAttackDamagedSkip()
- {
- if (getDamage() == 0)
- {
- return false;
- }
- bool bSkip = (currHitPoints() * 100 / maxHitPoints() < 40);
- if (!bSkip)
- {
- int iSearchRange = airRange();
- bool bSkiesClear = true;
- for (int iDX = -iSearchRange; iDX <= iSearchRange && bSkiesClear; iDX++)
- {
- for (int iDY = -iSearchRange; iDY <= iSearchRange && bSkiesClear; iDY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (bestInterceptor(pLoopPlot) != NULL)
- {
- bSkiesClear = false;
- break;
- }
- }
- }
- }
- bSkip = !bSkiesClear;
- }
- if (bSkip)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- return false;
- }
- */
- // Returns true if a mission was pushed or we should wait for another unit to bombard...
- bool CvUnitAI::AI_followBombard()
- {
- CLLNode<IDInfo>* pUnitNode;
- CvUnit* pLoopUnit;
- CvPlot* pAdjacentPlot1;
- CvPlot* pAdjacentPlot2;
- int iI, iJ;
- if (canBombard(plot()))
- {
- getGroup()->pushMission(MISSION_BOMBARD);
- return true;
- }
- if (getDomainType() == DOMAIN_LAND)
- {
- for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- pAdjacentPlot1 = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot1 != NULL)
- {
- if (pAdjacentPlot1->isCity())
- {
- if (AI_potentialEnemy(pAdjacentPlot1->getTeam(), pAdjacentPlot1))
- {
- for (iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
- {
- pAdjacentPlot2 = plotDirection(pAdjacentPlot1->getX_INLINE(), pAdjacentPlot1->getY_INLINE(), ((DirectionTypes)iJ));
- if (pAdjacentPlot2 != NULL)
- {
- pUnitNode = pAdjacentPlot2->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pAdjacentPlot2->nextUnitNode(pUnitNode);
- if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
- {
- if (pLoopUnit->canBombard(pAdjacentPlot2))
- {
- if (pLoopUnit->isGroupHead())
- {
- if (pLoopUnit->getGroup() != getGroup())
- {
- if (pLoopUnit->getGroup()->readyToMove())
- {
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return false;
- }
- // Returns true if the unit has found a potential enemy...
- bool CvUnitAI::AI_potentialEnemy(TeamTypes eTeam, const CvPlot* pPlot)
- {
- PROFILE_FUNC();
- if (getGroup()->AI_isDeclareWar(pPlot))
- {
- return isPotentialEnemy(eTeam, pPlot);
- }
- else
- {
- return isEnemy(eTeam, pPlot);
- }
- }
- // Returns true if this plot needs some defense...
- bool CvUnitAI::AI_defendPlot(CvPlot* pPlot)
- {
- CvCity* pCity;
- if (!canDefend(pPlot))
- {
- return false;
- }
- pCity = pPlot->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getOwnerINLINE() == getOwnerINLINE())
- {
- if (pCity->AI_isDanger())
- {
- return true;
- }
- }
- }
- else
- {
- if (pPlot->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE()) <= ((atPlot(pPlot)) ? 1 : 0))
- {
- if (pPlot->plotCount(PUF_cannotDefend, -1, -1, getOwnerINLINE()) > 0)
- {
- return true;
- }
- // if (pPlot->defenseModifier(getTeam(), false) >= 50 && pPlot->isRoute() && pPlot->getTeam() == getTeam())
- // {
- // return true;
- // }
- }
- }
- return false;
- }
- int CvUnitAI::AI_pillageValue(CvPlot* pPlot, int iBonusValueThreshold)
- {
- CvPlot* pAdjacentPlot;
- ImprovementTypes eImprovement;
- BonusTypes eNonObsoleteBonus;
- int iValue;
- int iTempValue;
- int iBonusValue;
- int iI;
- FAssert(getGroup()->canPillage(pPlot) || canAirBombAt(plot(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) || (getGroup()->getCargo() > 0));
- if (!(pPlot->isOwned()))
- {
- return 0;
- }
- // Advanced Tactics - pillage value is 0 for own plots
- if (pPlot->getOwner() == getOwner())
- {
- return 0;
- }
- // End Advanced Tactics
- CLLNode<IDInfo>* pUnitNode;
- CvUnit* pLoopUnit;
- bool bHasEnemyRouteTroops = false;
- pUnitNode = getGroup()->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- if (pLoopUnit->isEnemyRoute())
- {
- bHasEnemyRouteTroops = true;
- break;
- }
- }
- if (pPlot->getImprovementType() == NO_IMPROVEMENT && bHasEnemyRouteTroops) // loops triggered when stack is led by units without enemyroute (Stooges for example)
- {
- return 0;
- }
- iBonusValue = 0;
- eNonObsoleteBonus = pPlot->getNonObsoleteBonusType(pPlot->getTeam());
- if (eNonObsoleteBonus != NO_BONUS)
- {
- iBonusValue = (GET_PLAYER(pPlot->getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus));
- }
- if (iBonusValueThreshold > 0)
- {
- if (eNonObsoleteBonus == NO_BONUS)
- {
- return 0;
- }
- else if (iBonusValue < iBonusValueThreshold)
- {
- return 0;
- }
- }
- iValue = 0;
- if (getDomainType() != DOMAIN_AIR)
- {
- if (pPlot->isRoute() && !isEnemyRoute())
- {
- iValue++;
- if (eNonObsoleteBonus != NO_BONUS)
- {
- iValue += iBonusValue * 4;
- }
- for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
- {
- pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
- if (pAdjacentPlot != NULL && pAdjacentPlot->getTeam() == pPlot->getTeam())
- {
- if (pAdjacentPlot->isCity())
- {
- iValue += 10;
- }
- if (!(pAdjacentPlot->isRoute()))
- {
- if (!(pAdjacentPlot->isWater()) && !(pAdjacentPlot->isImpassable()))
- {
- iValue += 2;
- }
- }
- }
- }
- }
- }
- if (pPlot->getImprovementDuration() > ((pPlot->isWater()) ? 20 : 5))
- {
- eImprovement = pPlot->getImprovementType();
- }
- else
- {
- eImprovement = pPlot->getRevealedImprovementType(getTeam(), false);
- }
- if (eImprovement != NO_IMPROVEMENT)
- {
- if (pPlot->getWorkingCity() != NULL)
- {
- iValue += (pPlot->calculateImprovementYieldChange(eImprovement, YIELD_FOOD, pPlot->getOwnerINLINE()) * 5);
- iValue += (pPlot->calculateImprovementYieldChange(eImprovement, YIELD_PRODUCTION, pPlot->getOwnerINLINE()) * 4);
- iValue += (pPlot->calculateImprovementYieldChange(eImprovement, YIELD_COMMERCE, pPlot->getOwnerINLINE()) * 3);
- }
- if (getDomainType() != DOMAIN_AIR)
- {
- iValue += GC.getImprovementInfo(eImprovement).getPillageGold();
- // raiders
- iValue += (GC.getImprovementInfo(eImprovement).getPillageGold() * GET_PLAYER(getOwnerINLINE()).getPillagingGold()) / 100;
- }
- if (eNonObsoleteBonus != NO_BONUS)
- {
- //if (GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
- if (GET_PLAYER(pPlot->getOwnerINLINE()).doesImprovementConnectBonus(eImprovement, eNonObsoleteBonus)) // K-Mod
- {
- iTempValue = iBonusValue * 4;
- if (pPlot->isConnectedToCapital() && (pPlot->getPlotGroupConnectedBonus(pPlot->getOwnerINLINE(), eNonObsoleteBonus) == 1))
- {
- iTempValue *= 2;
- }
- iValue += iTempValue;
- }
- }
- }
- return iValue;
- }
- int CvUnitAI::AI_nukeValue(CvCity* pCity)
- {
- PROFILE_FUNC();
- FAssertMsg(pCity != NULL, "City is not assigned a valid value");
- for (int iI = 0; iI < MAX_TEAMS; iI++)
- {
- CvTeam& kLoopTeam = GET_TEAM((TeamTypes)iI);
- if (kLoopTeam.isAlive() && !isEnemy((TeamTypes)iI))
- {
- if (isNukeVictim(pCity->plot(), ((TeamTypes)iI)))
- {
- // Don't start wars with neutrals
- return 0;
- }
- }
- }
- int iValue = 1;
- iValue += GC.getGameINLINE().getSorenRandNum((pCity->getPopulation() + 1), "AI Nuke City Value");
- iValue += std::max(0, pCity->getPopulation() - 10);
- iValue += ((pCity->getPopulation() * (100 + pCity->calculateCulturePercent(pCity->getOwnerINLINE()))) / 100);
- iValue += -(GET_PLAYER(getOwnerINLINE()).AI_getAttitudeVal(pCity->getOwnerINLINE()) / 3);
- for (int iDX = -(nukeRange()); iDX <= nukeRange(); iDX++)
- {
- for (int iDY = -(nukeRange()); iDY <= nukeRange(); iDY++)
- {
- CvPlot* pLoopPlot = plotXY(pCity->getX_INLINE(), pCity->getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT)
- {
- iValue++;
- }
- if (pLoopPlot->getBonusType() != NO_BONUS)
- {
- iValue++;
- }
- }
- }
- }
- if (!(pCity->isEverOwned(getOwnerINLINE())))
- {
- iValue *= 3;
- iValue /= 2;
- }
- if (!GET_TEAM(pCity->getTeam()).isAVassal())
- {
- iValue *= 2;
- }
- if (pCity->plot()->isVisible(getTeam(), false))
- {
- iValue += 2 * pCity->plot()->getNumVisibleEnemyDefenders(this);
- }
- else
- {
- iValue += 6;
- }
- return iValue;
- }
- int CvUnitAI::AI_searchRange(int iRange)
- {
- if (iRange == 0)
- {
- return 0;
- }
- if (getDuration() > 0)
- {
- //iRange = getDuration();
- return getDuration() * baseMoves();
- }
- if (flatMovementCost() || (getDomainType() == DOMAIN_SEA))
- {
- return (iRange * baseMoves());
- }
- else
- {
- return ((iRange + 1) * (baseMoves() + 1));
- }
- }
- // XXX at some point test the game with and without this function...
- bool CvUnitAI::AI_plotValid(CvPlot* pPlot)
- {
- PROFILE_FUNC();
- if (m_pUnitInfo->isNoRevealMap() && willRevealByMove(pPlot))
- {
- return false;
- }
- switch (getDomainType())
- {
- case DOMAIN_SEA:
- if (pPlot->isWater() || canMoveAllTerrain())
- {
- return true;
- }
- else if (pPlot->isFriendlyCity(*this, true) && pPlot->isCoastalLand())
- {
- return true;
- }
- break;
- case DOMAIN_AIR:
- FAssert(false);
- break;
- case DOMAIN_LAND:
- if (pPlot->getArea() == getArea() || canMoveAllTerrain())
- {
- return true;
- }
- break;
- case DOMAIN_IMMOBILE:
- FAssert(false);
- break;
- default:
- FAssert(false);
- break;
- }
- return false;
- }
- int CvUnitAI::AI_finalOddsThreshold(CvPlot* pPlot, int iOddsThreshold)
- {
- PROFILE_FUNC();
- CvCity* pCity;
- int iFinalOddsThreshold;
- iFinalOddsThreshold = iOddsThreshold;
- pCity = pPlot->getPlotCity();
- if (pCity != NULL)
- {
- if (pCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE() * 3) / 4))
- {
- iFinalOddsThreshold += std::max(0, (pCity->getDefenseDamage() - pCity->getLastDefenseDamage() - (GC.getDefineINT("CITY_DEFENSE_DAMAGE_HEAL_RATE") * 2)));
- }
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/29/10 jdog5000 */
- /* */
- /* War tactics AI */
- /************************************************************************************************/
- /* original bts code
- if (pPlot->getNumVisiblePotentialEnemyDefenders(this) == 1)
- {
- if (pCity != NULL)
- {
- iFinalOddsThreshold *= 2;
- iFinalOddsThreshold /= 3;
- }
- else
- {
- iFinalOddsThreshold *= 7;
- iFinalOddsThreshold /= 8;
- }
- }
- if ((getDomainType() == DOMAIN_SEA) && !getGroup()->hasCargo())
- {
- iFinalOddsThreshold *= 3;
- iFinalOddsThreshold /= 2 + getGroup()->getNumUnits();
- }
- else
- {
- iFinalOddsThreshold *= 6;
- 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));
- }
- */
- int iDefenders = pPlot->getNumVisiblePotentialEnemyDefenders(this);
- if (iDefenders = 0 && pPlot->isVisible(getTeam(), false))
- {
- return 1;
- }
- // More aggressive if only one enemy defending city
- if (iDefenders == 1 && pCity != NULL)
- {
- iFinalOddsThreshold *= 2;
- iFinalOddsThreshold /= 3;
- }
- if ((getDomainType() == DOMAIN_SEA) && !getGroup()->hasCargo())
- {
- iFinalOddsThreshold *= 3 + (iDefenders/2);
- iFinalOddsThreshold /= 2 + getGroup()->getNumUnits();
- }
- else
- {
- iFinalOddsThreshold *= 6 + (iDefenders/((pCity != NULL) ? 1 : 2));
- int iDivisor = 3;
- iDivisor += GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pPlot, true);
- iDivisor += ((stepDistance(getX_INLINE(), getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) > 1) ? getGroup()->getNumUnits() : 0);
- iDivisor += (AI_isCityAIType() ? 2 : 0);
- iFinalOddsThreshold /= iDivisor;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- // Tholal AI - encourage attack when attackers have a numbers advantage
- if (getGroup()->getNumUnits() >= (iDefenders * 4))
- {
- iFinalOddsThreshold /= 2;
- }
- // End Tholal AI
-
- return range(iFinalOddsThreshold, 1, 99);
- }
- int CvUnitAI::AI_stackOfDoomExtra()
- {
- return ((AI_getBirthmark() % (1 + GC.getGameINLINE().getCurrentEra())) + 4);
- }
- bool CvUnitAI::AI_stackAttackCity(int iRange, int iPowerThreshold, bool bFollow)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- FAssert(canMove());
- if (bFollow)
- {
- iSearchRange = 1;
- }
- else
- {
- iSearchRange = AI_searchRange(iRange);
- }
- iBestValue = 0;
- pBestPlot = NULL;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot))
- {
- // Super Forts begin *AI_offense* - modified if statement so forts are attacked too
- if (pLoopPlot->isCity(GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_TACTICS)))
- //if (pLoopPlot->isCity() || (pLoopPlot->isCity(true) && pLoopPlot->isVisibleEnemyUnit(this))) - Original Code
- // Super Forts end
- {
- if (AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
- {
- if (!atPlot(pLoopPlot) && ((bFollow) ? canMoveInto(pLoopPlot, /*bAttack*/ true, /*bDeclareWar*/ true) : (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= iRange))))
- {
- iValue = getGroup()->AI_compareStacks(pLoopPlot, /*bPotentialEnemy*/ true, /*bCheckCanAttack*/ true, /*bCheckCanMove*/ true);
- if (iValue >= iPowerThreshold)
- {
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if( gUnitLogLevel >= 1 && pBestPlot->getPlotCity() != NULL )
- {
- 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 );
- logBBAI(" City %S has defense modifier %d, %d with ignore building", pBestPlot->getPlotCity()->getName(0).GetCString(), pBestPlot->getPlotCity()->getDefenseModifier(false), pBestPlot->getPlotCity()->getDefenseModifier(true) );
- }
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_moveIntoCity(int iRange)
- {
- PROFILE_FUNC();
- CvPlot* pLoopPlot;
- CvPlot* pBestPlot;
- int iSearchRange = iRange;
- int iPathTurns;
- int iValue;
- int iBestValue;
- int iDX, iDY;
- FAssert(canMove());
- iBestValue = 0;
- pBestPlot = NULL;
- if (plot()->isCity())
- {
- return false;
- }
- iSearchRange = AI_searchRange(iRange);
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (AI_plotValid(pLoopPlot) && (!isEnemy(pLoopPlot->getTeam(), pLoopPlot)))
- {
- if (pLoopPlot->isCity() || (pLoopPlot->isCity(true)))
- {
- if (canMoveInto(pLoopPlot, false) && (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= 1)))
- {
- iValue = 1;
- if (pLoopPlot->getPlotCity() != NULL)
- {
- iValue += pLoopPlot->getPlotCity()->getPopulation();
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = getPathEndTurnPlot();
- FAssert(!atPlot(pBestPlot));
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- return false;
- }
- //bolsters the culture of the weakest city.
- //returns true if a mission is pushed.
- bool CvUnitAI::AI_artistCultureVictoryMove()
- {
- bool bGreatWork = false;
- bool bJoin = true;
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/08/10 jdog5000 */
- /* */
- /* Victory Strategy AI */
- /************************************************************************************************/
- if (!(GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE1)))
- {
- return false;
- }
-
- if (GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE3))
- {
- //Great Work
- bGreatWork = true;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- int iCultureCitiesNeeded = GC.getGameINLINE().culturalVictoryNumCultureCities();
- FAssertMsg(iCultureCitiesNeeded > 0, "CultureVictory Strategy should not be true");
- CvCity* pLoopCity;
- CvPlot* pBestPlot;
- CvCity* pBestCity;
- SpecialistTypes eBestSpecialist;
- int iLoop, iValue, iBestValue;
- pBestPlot = NULL;
- eBestSpecialist = NO_SPECIALIST;
- pBestCity = NULL;
- iBestValue = 0;
- iLoop = 0;
- int iTargetCultureRank = iCultureCitiesNeeded;
- while (iTargetCultureRank > 0 && pBestCity == NULL)
- {
- for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/19/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- // BBAI efficiency: check same area
- if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- {
- // instead of commerce rate rank should use the culture on tile...
- if (pLoopCity->findCommerceRateRank(COMMERCE_CULTURE) == iTargetCultureRank)
- {
- // if the city is a fledgling, probably building culture, try next higher city
- if (pLoopCity->getCultureLevel() < 2)
- {
- break;
- }
- // if we cannot path there, try the next higher culture city
- if (!generatePath(pLoopCity->plot(), 0, true))
- {
- break;
- }
- pBestCity = pLoopCity;
- pBestPlot = pLoopCity->plot();
- if (bGreatWork)
- {
- if (canGreatWork(pBestPlot))
- {
- break;
- }
- }
- for (int iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
- {
- if (canJoin(pBestPlot, ((SpecialistTypes)iI)))
- {
- iValue = pLoopCity->AI_specialistValue(((SpecialistTypes)iI), pLoopCity->AI_avoidGrowth(), false);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestSpecialist = ((SpecialistTypes)iI);
- }
- }
- }
- if (eBestSpecialist == NO_SPECIALIST)
- {
- bJoin = false;
- if (canGreatWork(pBestPlot))
- {
- bGreatWork = true;
- break;
- }
- bGreatWork = false;
- }
- break;
- }
- }
- }
- iTargetCultureRank--;
- }
- FAssertMsg(bGreatWork || bJoin, "This wasn't a Great Artist");
- if (pBestCity == NULL)
- {
- //should try to airlift there...
- return false;
- }
- if (atPlot(pBestPlot))
- {
- if (bGreatWork)
- {
- getGroup()->pushMission(MISSION_GREAT_WORK);
- return true;
- }
- if (bJoin)
- {
- getGroup()->pushMission(MISSION_JOIN, eBestSpecialist);
- return true;
- }
- FAssert(false);
- return false;
- }
- else
- {
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- return true;
- }
- }
- bool CvUnitAI::AI_poach()
- {
- CvPlot* pLoopPlot;
- int iX, iY;
- int iBestPoachValue = 0;
- CvPlot* pBestPoachPlot = NULL;
- TeamTypes eBestPoachTeam = NO_TEAM;
- /*
- if (!GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI))
- {
- return false;
- }
- */
- if (GET_TEAM(getTeam()).getNumMembers() > 1)
- {
- return false;
- }
- int iNoPoachRoll = GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_WORKER);
- iNoPoachRoll += GET_PLAYER(getOwnerINLINE()).getNumCities();
- iNoPoachRoll = std::max(0, (iNoPoachRoll - 1) / 2);
- if (GC.getGameINLINE().getSorenRandNum(iNoPoachRoll, "AI Poach") > 0)
- {
- return false;
- }
- if (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0)
- {
- return false;
- }
- FAssert(canAttack());
- int iRange = 1;
- //Look for a unit which is non-combat
- //and has a capture unit type
- for (iX = -iRange; iX <= iRange; iX++)
- {
- for (iY = -iRange; iY <= iRange; iY++)
- {
- if (iX != 0 && iY != 0)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
- if ((pLoopPlot != NULL) && (pLoopPlot->getTeam() != getTeam()) && pLoopPlot->isVisible(getTeam(), false))
- {
- int iPoachCount = 0;
- int iDefenderCount = 0;
- CvUnit* pPoachUnit = NULL;
- CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
- if ((pLoopUnit->getTeam() != getTeam())
- && GET_TEAM(getTeam()).canDeclareWar(pLoopUnit->getTeam()))
- {
- if (!pLoopUnit->canDefend())
- {
- if (pLoopUnit->getCaptureUnitType(getCivilizationType()) != NO_UNIT)
- {
- iPoachCount++;
- pPoachUnit = pLoopUnit;
- }
- }
- else
- {
- iDefenderCount++;
- }
- }
- }
- if (pPoachUnit != NULL)
- {
- if (iDefenderCount == 0)
- {
- int iValue = iPoachCount * 100;
- iValue -= iNoPoachRoll * 25;
- if (iValue > iBestPoachValue)
- {
- iBestPoachValue = iValue;
- pBestPoachPlot = pLoopPlot;
- eBestPoachTeam = pPoachUnit->getTeam();
- }
- }
- }
- }
- }
- }
- }
- if (pBestPoachPlot != NULL)
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" Stack (led by %d, size %d) poaching (%d, %d)", getID(), getGroup()->getNumUnits(), pBestPoachPlot->getX(), pBestPoachPlot->getY());
- }
- //No war roll.
- if (!GET_TEAM(getTeam()).AI_performNoWarRolls(eBestPoachTeam))
- {
- GET_TEAM(getTeam()).declareWar(eBestPoachTeam, true, WARPLAN_LIMITED);
- FAssert(!atPlot(pBestPoachPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPoachPlot->getX_INLINE(), pBestPoachPlot->getY_INLINE(), MOVE_DIRECT_ATTACK);
- return true;
- }
- }
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/31/10 jdog5000 */
- /* */
- /* War tactics AI */
- /************************************************************************************************/
- bool CvUnitAI::AI_choke(int iRange, bool bDefensive)
- {
- PROFILE_FUNC();
- int iPercentDefensive;
- {
- int iDefCount = 0;
- CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
- CvUnit* pLoopUnit = NULL;
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- iDefCount += pLoopUnit->noDefensiveBonus() ? 0 : 1;
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- }
- iPercentDefensive = 100 * iDefCount / getGroup()->getNumUnits();
- }
- CvPlot* pBestPlot = 0;
- CvPlot* pEndTurnPlot = 0;
- int iBestValue = 0;
- for (int iX = -iRange; iX <= iRange; iX++)
- {
- for (int iY = -iRange; iY <= iRange; iY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
- if (pLoopPlot && isEnemy(pLoopPlot->getTeam()) && !pLoopPlot->isVisibleEnemyUnit(this))
- {
- int iPathTurns;
- if (pLoopPlot->getWorkingCity() && generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- FAssert(pLoopPlot->getWorkingCity()->getTeam() == pLoopPlot->getTeam());
- //int iValue = (bDefensive ? pLoopPlot->defenseModifier(getTeam(), false) : -15);
- int iValue = bDefensive ? pLoopPlot->defenseModifier(getTeam(), false) - 15 : 0; // K-Mod
- if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
- {
- iValue = GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(pLoopPlot->getBonusType(), 0);
- }
-
- iValue += pLoopPlot->getYield(YIELD_PRODUCTION) * 9; // was 10
- iValue += pLoopPlot->getYield(YIELD_FOOD) * 12; // was 10
- iValue += pLoopPlot->getYield(YIELD_COMMERCE) * 5;
- if (atPlot(pLoopPlot) && getGroup()->canPillage(pLoopPlot))
- {
- iValue += AI_pillageValue(pLoopPlot, 0) / (bDefensive ? 2 : 1);
- }
- if (iValue > 0)
- {
- iValue *= (bDefensive ? 25 : 50) + iPercentDefensive * pLoopPlot->defenseModifier(getTeam(), false) / 100;
- if (bDefensive)
- {
- // for defensive, we care a lot about path turns
- iValue *= 10;
- iValue /= std::max(1, iPathTurns);
- }
- else
- {
- // otherwise we just want to block as many tiles as possible
- iValue *= 10;
- iValue /= std::max(1, pLoopPlot->getNumDefenders(getOwnerINLINE()) + (pLoopPlot == plot() ? 0 : getGroup()->getNumUnits()));
- }
- if (iValue > iBestValue)
- {
- pBestPlot = pLoopPlot;
- pEndTurnPlot = getPathEndTurnPlot();
- iBestValue = iValue;
- }
- }
- }
- }
- }
- }
- if (pBestPlot)
- {
- FAssert(pBestPlot->getWorkingCity());
- CvPlot* pChokedCityPlot = pBestPlot->getWorkingCity()->plot();
- if (atPlot(pBestPlot))
- {
- FAssert(atPlot(pEndTurnPlot));
-
- if (plot()->getImprovementType() != NO_IMPROVEMENT || !isEnemyRoute())
- {
- if (getGroup()->canPillage(plot()))
- getGroup()->pushMission(MISSION_PILLAGE);
- else
- getGroup()->pushMission(MISSION_SKIP);
- }
- else
- {
- getGroup()->pushMission(MISSION_SKIP);
- }
- return true;
- }
- else
- {
- FAssert(!atPlot(pEndTurnPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pEndTurnPlot->getX(), pEndTurnPlot->getY());
- return true;
- }
- }
-
- return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- bool CvUnitAI::AI_solveBlockageProblem(CvPlot* pDestPlot, bool bDeclareWar)
- {
- PROFILE_FUNC();
- FAssert(pDestPlot != NULL);
- if (pDestPlot != NULL)
- {
- FAStarNode* pStepNode;
- CvPlot* pSourcePlot = plot();
- if (gDLL->getFAStarIFace()->GeneratePath(&GC.getStepFinder(), pSourcePlot->getX_INLINE(), pSourcePlot->getY_INLINE(), pDestPlot->getX_INLINE(), pDestPlot->getY_INLINE(), false, 0, true))
- {
- pStepNode = gDLL->getFAStarIFace()->GetLastNode(&GC.getStepFinder());
- while (pStepNode != NULL)
- {
- CvPlot* pStepPlot = GC.getMapINLINE().plotSorenINLINE(pStepNode->m_iX, pStepNode->m_iY);
- if (canMoveOrAttackInto(pStepPlot) && generatePath(pStepPlot, 0, true))
- {
- if (bDeclareWar && pStepNode->m_pPrev != NULL)
- {
- CvPlot* pPlot = GC.getMapINLINE().plotSorenINLINE(pStepNode->m_pPrev->m_iX, pStepNode->m_pPrev->m_iY);
- if (pPlot->getTeam() != NO_TEAM)
- {
- if (!canMoveInto(pPlot, true, true))
- {
- if (!isPotentialEnemy(pPlot->getTeam(), pPlot))
- {
- CvTeamAI& kTeam = GET_TEAM(getTeam());
- if (kTeam.canDeclareWar(pPlot->getTeam()))
- {
- WarPlanTypes eWarPlan = WARPLAN_LIMITED;
- WarPlanTypes eExistingWarPlan = kTeam.AI_getWarPlan(pDestPlot->getTeam());
- if (eExistingWarPlan != NO_WARPLAN)
- {
- if ((eExistingWarPlan == WARPLAN_TOTAL) || (eExistingWarPlan == WARPLAN_PREPARING_TOTAL))
- {
- eWarPlan = WARPLAN_TOTAL;
- }
- if (!kTeam.isAtWar(pDestPlot->getTeam()))
- {
- kTeam.AI_setWarPlan(pDestPlot->getTeam(), NO_WARPLAN);
- }
- }
- kTeam.AI_setWarPlan(pPlot->getTeam(), eWarPlan, true);
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 03/29/10 jdog5000 */
- /* */
- /* War tactics AI */
- /************************************************************************************************/
- /* original bts code
- return (AI_targetCity());
- */
- return (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2));
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
-
- }
- }
- }
- }
- }
- if (pStepPlot->isVisibleEnemyUnit(this))
- {
- FAssert(canAttack());
- CvPlot* pBestPlot = pStepPlot;
- //To prevent puppeteering attempt to barge through
- //if quite close
- if (getPathLastNode()->m_iData2 > 3)
- {
- pBestPlot = getPathEndTurnPlot();
- }
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_DIRECT_ATTACK);
- return true;
- }
- }
- pStepNode = pStepNode->m_pParent;
- }
- }
- }
- return false;
- }
- int CvUnitAI::AI_calculatePlotWorkersNeeded(CvPlot* pPlot, BuildTypes eBuild)
- {
- int iBuildTime = pPlot->getBuildTime(eBuild) - pPlot->getBuildProgress(eBuild);
- int iWorkRate = workRate(true);
- if (iWorkRate <= 0)
- {
- FAssert(false);
- return 1;
- }
- int iTurns = iBuildTime / iWorkRate;
- if (iBuildTime > (iTurns * iWorkRate))
- {
- iTurns++;
- }
- int iNeeded = std::max(1, (iTurns + 2) / 3);
- if (pPlot->getBonusType() != NO_BONUS)
- {
- iNeeded *= 2;
- }
- return iNeeded;
- }
- bool CvUnitAI::AI_canGroupWithAIType(UnitAITypes eUnitAI) const
- {
- if (eUnitAI != AI_getUnitAIType())
- {
- switch (eUnitAI)
- {
- case (UNITAI_ATTACK_CITY):
- if (plot()->isCity() && (GC.getGame().getGameTurn() - plot()->getPlotCity()->getGameTurnAcquired()) <= 1)
- {
- return false;
- }
- break;
- /*************************************************************************************************/
- /** BETTER AI (first city) Sephi **/
- /** **/
- /** **/
- /*************************************************************************************************/
- case (UNITAI_SETTLE):
- if (GC.getGame().getGameTurn()<10)
- {
- return false;
- }
- break;
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- default:
- break;
- }
- }
- return true;
- }
- bool CvUnitAI::AI_allowGroup(const CvUnit* pUnit, UnitAITypes eUnitAI) const
- {
- CvSelectionGroup* pGroup = pUnit->getGroup();
- CvPlot* pPlot = pUnit->plot();
- /*************************************************************************************************/
- /** BETTER AI (Group with Conquest stack) Sephi **/
- /*************************************************************************************************/
- CvUnit* tempUnit=getGroup()->getHeadUnit();
- if (tempUnit!=NULL)
- {
- if (tempUnit->AI_getGroupflag()==GROUPFLAG_CONQUEST || tempUnit->AI_getUnitAIType()==UNITAI_HERO)
- {
- if (pUnit == this)
- {
- return false;
- }
- if (!pUnit->isGroupHead())
- {
- return false;
- }
- if (pGroup == getGroup())
- {
- return false;
- }
- if (pUnit->isCargo())
- {
- return false;
- }
- //FfH: Added by Kael 08/18/2008
- if ((plot() != pPlot) && (pPlot->isVisibleEnemyUnit((PlayerTypes)getOwnerINLINE())))
- {
- return false;
- }
- //FfH: End Add
- switch (pGroup->AI_getMissionAIType())
- {
- case MISSIONAI_GUARD_CITY:
- // do not join groups that are guarding cities
- // intentional fallthrough
- case MISSIONAI_LOAD_SETTLER:
- case MISSIONAI_LOAD_ASSAULT:
- case MISSIONAI_LOAD_SPECIAL:
- // do not join groups that are loading into transports (we might not fit and get stuck in loop forever)
- return false;
- break;
- default:
- break;
- }
- if (!canJoinGroup(pPlot, pGroup))
- {
- return false;
- }
- if (eUnitAI == UNITAI_ASSAULT_SEA)
- {
- if (!pGroup->hasCargo())
- {
- return false;
- }
- }
- if (pUnit->getInvisibleType() != NO_INVISIBLE)
- {
- if (getInvisibleType() == NO_INVISIBLE)
- {
- return false;
- }
- }
- if (tempUnit->AI_getGroupflag()==GROUPFLAG_CONQUEST)
- {
- if (!pUnit->getGroup()->getHeadUnit())
- {
- return false;
- }
- else if (pUnit->getGroup()->getHeadUnit()->AI_getGroupflag()!=GROUPFLAG_CONQUEST)
- {
- return false;
- }
- }
- return true;
- }
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- if (pUnit == this)
- {
- return false;
- }
- if (!pUnit->isGroupHead())
- {
- return false;
- }
- if (pGroup == getGroup())
- {
- return false;
- }
- if (pUnit->isCargo())
- {
- return false;
- }
- // if (pUnit->AI_getUnitAIType() != eUnitAI)
- if (eUnitAI != UNITAI_UNKNOWN && pUnit->AI_getUnitAIType() != eUnitAI)
- {
- return false;
- }
- //FfH: Added by Kael 08/18/2008
- if ((plot() != pPlot) && (pPlot->isVisibleEnemyUnit((PlayerTypes)getOwnerINLINE())))
- {
- return false;
- }
- //FfH: End Add
- switch (pGroup->AI_getMissionAIType())
- {
- case MISSIONAI_GUARD_CITY:
- // do not join groups that are guarding cities
- // intentional fallthrough
- case MISSIONAI_LOAD_SETTLER:
- case MISSIONAI_LOAD_ASSAULT:
- case MISSIONAI_LOAD_SPECIAL:
- // do not join groups that are loading into transports (we might not fit and get stuck in loop forever)
- return false;
- break;
- // ALN - Barbs shouldn't go after a group already joining another group
- case MISSIONAI_GROUP:
- if (isBarbarian())
- {
- return false;
- }
- default:
- break;
- }
- if (pGroup->getActivityType() == ACTIVITY_HEAL)
- {
- // do not attempt to join groups which are healing this turn
- // (healing is cleared every turn for automated groups, so we know we pushed a heal this turn)
- return false;
- }
- if (!canJoinGroup(pPlot, pGroup))
- {
- return false;
- }
- if (eUnitAI == UNITAI_SETTLE)
- {
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD 08/20/09 jdog5000 */
- /* */
- /* Unit AI, Efficiency */
- /************************************************************************************************/
- //if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pPlot, 3) > 0)
- if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(pPlot, 3)) // Tholal NOte - Why is this here?
- {
- //return false;
- }
- /************************************************************************************************/
- /* BETTER_BTS_AI_MOD END */
- /************************************************************************************************/
- }
- else if (eUnitAI == UNITAI_ASSAULT_SEA)
- {
- if (!pGroup->hasCargo())
- {
- return false;
- }
- }
- if ((getGroup()->getHeadUnitAI() == UNITAI_CITY_DEFENSE))
- {
- if (plot()->isCity() && (plot()->getTeam() == getTeam()) && plot()->getBestDefender(getOwnerINLINE())->getGroup() == getGroup())
- {
- return false;
- }
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- CvPlot* pTargetPlot = pGroup->AI_getMissionAIPlot();
- if (pTargetPlot != NULL)
- {
- if (pTargetPlot->isOwned())
- {
- if (isPotentialEnemy(pTargetPlot->getTeam(), pTargetPlot))
- {
- //Do not join groups which have debarked on an offensive mission
- return false;
- }
- }
- }
- }
- if (pUnit->getInvisibleType() != NO_INVISIBLE)
- {
- if (getInvisibleType() == NO_INVISIBLE)
- {
- return false;
- }
- }
- return true;
- }
- void CvUnitAI::read(FDataStreamBase* pStream)
- {
- CvUnit::read(pStream);
- uint uiFlag=0;
- pStream->Read(&uiFlag); // flags for expansion
- pStream->Read(&m_iBirthmark);
- /*************************************************************************************************/
- /** BETTER AI (New Functions Definition) Sephi **/
- /*************************************************************************************************/
- pStream->Read(&m_bAllowedPermDefense);
- pStream->Read(&m_bPermanentSummon);
- pStream->Read(&m_bSuicideSummon);
- pStream->Read(&m_iGroupflag);
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- pStream->Read((int*)&m_eUnitAIType);
- pStream->Read(&m_iAutomatedAbortTurn);
- }
- void CvUnitAI::write(FDataStreamBase* pStream)
- {
- CvUnit::write(pStream);
- uint uiFlag=0;
- pStream->Write(uiFlag); // flag for expansion
- pStream->Write(m_iBirthmark);
- /*************************************************************************************************/
- /** BETTER AI (New Functions Definition) Sephi **/
- /*************************************************************************************************/
- pStream->Write(m_bAllowedPermDefense);
- pStream->Write(m_bPermanentSummon);
- pStream->Write(m_bSuicideSummon);
- pStream->Write(m_iGroupflag);
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- pStream->Write(m_eUnitAIType);
- pStream->Write(m_iAutomatedAbortTurn);
- }
- // Private Functions...
- //FfH: Added by Kael 09/19/2007
- void CvUnitAI::AI_summonAttackMove()
- {
- PROFILE_FUNC();
- // Floating Eyes
- if (getDomainType() == DOMAIN_AIR)
- {
- if (canRecon(plot()))
- {
- if (AI_exploreAir())
- {
- return;
- }
- else
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- bool bBombard = (bombardRate() > 0);
- bool bCollateral = (getUnitInfo().isExplodeInCombat() || (collateralDamage() > 0));
- if (getDuration() > 0)
- {
- if (bBombard)
- {
- if (AI_bombardCity())
- {
- return;
- }
- // check for distant bombard targets
- CvCity* pTargetCity = NULL;
- pTargetCity = AI_pickTargetCity(0, getDuration(), true);
-
- if( pTargetCity != NULL )
- {
- if( AI_goToTargetCity(0, (getDuration() - 1), pTargetCity) )
- {
- if (AI_bombardCity())
- {
- return;
- }
- return;
- }
- }
- }
-
- if (AI_anyAttack(getDuration(), (bCollateral ? 0 : 25)))
- {
- return;
- }
- }
- else
- {
- if (AI_anyAttack(baseMoves(), (bCollateral ? 0: 10)))
- {
- return;
- }
- }
- if (AI_patrol())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- //FfH: End Add
- /*************************************************************************************************/
- /** BETTER AI (New Functions) Sephi **/
- /** **/
- /** **/
- /*************************************************************************************************/
- int CvUnitAI::AI_getGroupflag() const
- {
- return m_iGroupflag;
- }
- void CvUnitAI::AI_setGroupflag(int newflag)
- {
- m_iGroupflag=newflag;
- }
- // Chooses the Groupflag for AI Units in CvUnit::DoTurn()
- void CvUnitAI::AI_chooseGroupflag()
- {
- CvPlayerAI &kPlayer = GET_PLAYER(getOwnerINLINE());
- if( AI_getGroupflag() != GROUPFLAG_NONE)
- {
- return;
- }
- //Don't Choose a Groupflag if we haven't already built a city
- if (kPlayer.getNumCities() == 0)
- {
- return;
- }
- if (isInvisibleFromPromotion())
- {
- return;
- }
- if (getDuration() > 0)
- {
- AI_setGroupflag(GROUPFLAG_SUICIDE_SUMMON);
- return;
- }
- if (isHiddenNationality())
- {
- AI_setGroupflag(GROUPFLAG_HNGROUP);
- return;
- }
- bool bWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
- switch (AI_getUnitAIType())
- {
- case UNITAI_MAGE:
- AI_setGroupflag(GROUPFLAG_PERMDEFENSE);
- return;
- break;
- case UNITAI_HERO:
- AI_setGroupflag(GROUPFLAG_HERO);
- return;
- break;
- case UNITAI_WARWIZARD:
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- return;
- break;
- case UNITAI_CITY_DEFENSE:
- case UNITAI_CITY_COUNTER:
- AI_setGroupflag(GROUPFLAG_PERMDEFENSE);
- return;
- break;
- case UNITAI_ATTACK_CITY:
- case UNITAI_COUNTER:
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- return;
- break;
- case UNITAI_ATTACK:
- AI_setGroupflag(GROUPFLAG_PATROL);
- return;
- break;
- default:
- break;
- }
- //Svartalfar Kidnap
- // ToDo - better code for this
- CivilizationTypes iSvartal=(CivilizationTypes)GC.getInfoTypeForString("CIVILIZATION_SVARTALFAR");
- if (iSvartal != NO_CIVILIZATION && getCivilizationType() == iSvartal)
- {
- UnitTypes iHunter = (UnitTypes)GC.getInfoTypeForString("UNIT_HUNTER");
- if(iHunter != NO_UNIT && getUnitType() == iHunter)
- {
- if(kPlayer.countGroupFlagUnits(GROUPFLAG_SVARTALFAR_KIDNAP) == 0)
- {
- AI_setGroupflag(GROUPFLAG_SVARTALFAR_KIDNAP);
- return;
- }
- }
- }
- if ((GET_TEAM(getTeam()).getAtWarCount(true) > 0)
- || bWarPlan
- || (bombardRate() > 0)
- || isRangedCollateral())
- {
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- if (AI_getUnitAIType() != UNITAI_MEDIC)
- {
- int iAttackCityCount = kPlayer.AI_totalAreaUnitAIs(plot()->area(), UNITAI_ATTACK_CITY);
- int iAttackCount = kPlayer.AI_totalAreaUnitAIs(plot()->area(), UNITAI_ATTACK);
- if ((iAttackCount * 2) > iAttackCityCount)
- {
- AI_setUnitAIType(UNITAI_ATTACK_CITY);
- }
- }
- return;
- }
- bool bDanger = (kPlayer.AI_getAnyPlotDanger(plot(), 3, false));
- if (bDanger)
- {
- AI_setGroupflag(GROUPFLAG_PATROL);
- return;
- }
- if(isUnitAllowedPermDefense())
- {
- AI_setGroupflag(GROUPFLAG_PERMDEFENSE);
- return;
- }
-
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- //Returns true if the Unit can be set to City Defense
- bool CvUnitAI::isUnitAllowedPermDefense()
- {
- CvUnitInfo& kUnitInfo = GC.getUnitInfo(getUnitType());
- if (getDomainType() != DOMAIN_LAND)
- {
- return false;
- }
- if (kUnitInfo.getCombat() > kUnitInfo.getCombatDefense())
- {
- return false;
- }
- if (getDuration()>0)
- {
- return false;
- }
- /*
- if (isPermanentSummon())
- {
- return false;
- }
- */
- if (noDefensiveBonus())
- {
- return false;
- }
- if (isHiddenNationality())
- {
- return false;
- }
- switch (AI_getUnitAIType())
- {
- case UNITAI_SETTLE:
- case UNITAI_WORKER:
- case UNITAI_HERO:
- case UNITAI_TERRAFORMER:
- case UNITAI_MANA_UPGRADE:
- case UNITAI_WARWIZARD:
- case UNITAI_MISSIONARY:
- case UNITAI_ANIMAL:
- case UNITAI_PROPHET:
- case UNITAI_ARTIST:
- case UNITAI_SCIENTIST:
- case UNITAI_GENERAL:
- case UNITAI_MERCHANT:
- case UNITAI_ENGINEER:
- case UNITAI_SETTLER_SEA:
- case UNITAI_WORKER_SEA:
- case UNITAI_ATTACK_SEA:
- case UNITAI_RESERVE_SEA:
- case UNITAI_ESCORT_SEA:
- case UNITAI_ASSAULT_SEA:
- case UNITAI_MISSIONARY_SEA:
- case UNITAI_SPY_SEA:
- case UNITAI_PIRATE_SEA:
- case UNITAI_INQUISITOR:
- case UNITAI_FEASTING:
- return false;
- break;
- default:
- break;
- }
- if (kUnitInfo.getTier() > 3)
- return false;
- return m_bAllowedPermDefense;
- }
- // Returns true if a mission was pushed...
- bool CvUnitAI::AI_groupheal(int iDamagePercent, int iMaxPath)
- {
- PROFILE_FUNC();
- CLLNode<IDInfo>* pEntityNode;
- std::vector<CvUnit*> aeDamagedUnits;
- CvSelectionGroup* pGroup;
- CvUnit* pLoopUnit;
- int iTotalDamage;
- int iTotalHitpoints;
- int iHurtUnitCount;
- if (plot()->getFeatureType() != NO_FEATURE)
- {
- if (GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() != 0)
- {
- //Pass through
- //(actively seeking a safe spot may result in unit getting stuck)
- if (!plot()->isCity() && AI_retreatToCity(false,false,1))
- {
- return true;
- }
- return false;
- }
- }
- //FfH: Added by Kael 10/01/2007 (so the AI won't try to sit and heal in areas where they cant heal)
- if (healRate(plot()) <= 0)
- {
- if (!plot()->isCity() && AI_retreatToCity(false,false,1))
- {
- return true;
- }
- return false;
- }
- //FfH: End Add
- pGroup = getGroup();
- if (iDamagePercent == 0)
- {
- iDamagePercent = 10;
- }
- iMaxPath = std::min(iMaxPath, 1);
- pEntityNode = getGroup()->headUnitNode();
- iTotalDamage = 0;
- iTotalHitpoints = 0;
- iHurtUnitCount = 0;
- while (pEntityNode != NULL)
- {
- pLoopUnit = ::getUnit(pEntityNode->m_data);
- FAssert(pLoopUnit != NULL);
- pEntityNode = pGroup->nextUnitNode(pEntityNode);
- int iDamageThreshold = (pLoopUnit->maxHitPoints() * iDamagePercent) / 100;
- if (pLoopUnit->getDamage() > iDamageThreshold)
- {
- iHurtUnitCount++;
- }
- iTotalDamage += pLoopUnit->getDamage();
- iTotalHitpoints += pLoopUnit->maxHitPoints();
- }
- if (iHurtUnitCount*3>pGroup->getNumUnits())
- {
- if (!plot()->isCity() && AI_retreatToCity(false,false,1))
- {
- return true;
- }
- if(canHeal(plot()))
- {
- pGroup->pushMission(MISSION_HEAL);
- return true;
- }
- }
- return false;
- }
- void CvUnitAI::AI_feastingmove()
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" %S (unit %d) starting feastingMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
-
- FAssertMsg(isVampire(), "Feasters are expected to be Vampires");
- CvCity* pCity = plot()->getPlotCity();
- CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
- // Tholal ToDo: move this into python? - Hardcode
- if ((pCity != NULL) && !isHasCasted())
- {
- if (pCity->angryPopulation() > 0 || pCity->unhealthyPopulation(false) > 1)
- {
- if (pCity->getPopulation() > 9 || pCity->foodDifference() < 0)
- {
- if (canCast(GC.getDefineINT("SPELL_FEAST"),false))
- {
- cast(GC.getDefineINT("SPELL_FEAST"));
- }
- //getGroup()->pushMission(MISSION_SKIP);
- //return;
- if( gUnitLogLevel > 2 ) logBBAI(" ...Unit %S (%d) making opportunistic feast at %S", getName().GetCString(), getID(), pCity->getName().GetCString());
- }
- }
- }
- /*
- if (!isVampire() || !isAlive())
- {
- //TODO - change this to a choose groupflag call then return
- if (AI_getUnitAIType() == UNITAI_FEASTING)
- {
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- AI_setUnitAIType(UNITAI_ATTACK_CITY);
- getGroup()->pushMission(MISSION_SKIP);
- }
- return;
- }
- */
- // TODO: Change this to Feast odds - higher if in peactime, more angry/unhealthy, larger cities
- int iNeededFeasters = std::max(1,(kPlayer.getNumCities() / 3));
- if (AI_getGroupflag() == GROUPFLAG_CONQUEST || AI_getGroupflag() == GROUPFLAG_PATROL)
- {
- if (kPlayer.AI_totalUnitAIs(UNITAI_FEASTING) < iNeededFeasters)
- {
- if ((getLevel() < 6) && (AI_getUnitAIType() != UNITAI_HERO))
- {
- //joinGroup(NULL);
- AI_setGroupflag(GROUPFLAG_NONE);
- AI_setUnitAIType(UNITAI_FEASTING);
- //getGroup()->pushMission(MISSION_SKIP);
- }
- }
- }
- if (AI_getUnitAIType() == UNITAI_FEASTING)
- {
- // High-level Feasters should head into combat
- // TODO - check for warplans
- if (getLevel() > 8)
- {
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- AI_setUnitAIType(UNITAI_ATTACK_CITY);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- else
- {
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- CvCity* pLoopCity;
- CvCity* pBestCity;
- CvPlot* pBestPlot;
- int iValue;
- int iBestValue;
- int iLoop;
- int iPathTurns;
- iBestValue = 0;
- pBestCity = NULL;
- iValue = 0;
- // Feasters should work alone
- if (getGroup()->getNumUnits() > 1)
- {
- joinGroup(NULL);
- }
- for (pLoopCity = kPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kPlayer.nextCity(&iLoop))
- {
- if (pLoopCity->getPopulation() > 3)
- {
- if (pLoopCity->angryPopulation() > 0 || pLoopCity->unhealthyPopulation() > 2 )
- {
- if( generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns) )
- {
- iValue += pLoopCity->getPopulation() * 2;
- iValue += pLoopCity->angryPopulation() * 10;
- iValue += pLoopCity->unhealthyPopulation() * 2;
- iValue += -(pLoopCity->foodDifference() * 5);
- iValue -= getLevel();
- iValue -= iPathTurns * 4;
- iValue = std::max(0, iValue);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestCity = pLoopCity;
- }
- }
- }
- }
- }
- if (pBestCity != NULL)
- {
- pBestPlot = pBestCity->plot();
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- if (canCast(GC.getDefineINT("SPELL_FEAST"),false))
- {
- cast(GC.getDefineINT("SPELL_FEAST"));
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- else
- {
- if( gUnitLogLevel > 2 ) logBBAI(" ....moving to %d, %d to Feast", pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- FAssert(!atPlot(pBestPlot));
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
- return;
- }
- }
- }
- else
- {
- if (AI_anyAttack(2, 80))
- {
- return;
- }
-
- if (!plot()->isCity())
- {
- if (AI_guardCity())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- }
- else
- {
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- AI_setUnitAIType(UNITAI_ATTACK_CITY);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_PatrolMove()
- {
- bool bFollow=false;
- int iMinStack=1;
- int iBestValue=-1;
- CvPlot* pBestPlot=NULL;
- bool bAtWar = (GET_TEAM(getTeam()).getAtWarCount(true) > 0);
- bool bHero = false;
- bool bWizard = false;
- switch (AI_getUnitAIType())
- {
- case UNITAI_HERO:
- bHero = true;
- break;
- case UNITAI_WARWIZARD:
- bWizard = true;
- break;
- default:
- break;
- }
- bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
- bool bAnyWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
- bool bFinancialTrouble = GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble();
- bool bInCity = plot()->isCity();
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting PatrolMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- // lfgr 05/2020: Slightly hacky, to ensure the first/only remaining city is defended no matter what.
- if( GET_PLAYER( getOwnerINLINE() ).getNumCities() == 1 ) {
- if( AI_guardCityMinDefender( true ) ) { // Search for the city
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... defends the only, (otherwise) undefended city!" );}
- return;
- }
- }
- // Heroes and Casters should seek larger groups
- if (bHero || bWizard)
- {
- if (bAtWar || bAnyWarPlan)
- {
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- }
- if (getGroup()->getNumUnits() < ((getLevel() / 2) +1))
- {
- /*
- if (AI_groupMergeRange(UNITAI_ATTACK, 10, false, true, false))
- {
- return;
- }
- */
- if (AI_group(UNITAI_ATTACK))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... hero/caster group with attack stack" );}
- return;
- }
- if (AI_moveToStagingCity())
- {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... hero/caster moving to staging city" );}
- return;
- }
- }
- }
- if( getGroup()->getNumUnits() > 5 || bFinancialTrouble)
- {
- if (bAnyWarPlan)
- {
- if (getGroup()->getNumUnits() > ((GET_PLAYER(getOwnerINLINE()).getNumCities() + 1) * 3))
- {
- if( gUnitLogLevel >= 3 ) {logBBAI(" ...switching to GROUPFLAG_CONQUEST");}
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- return;
- }
- }
- if (bAtWar)
- {
- UnitAITypes eGroupAI = getGroup()->getHeadUnitAI();
- if( eGroupAI == AI_getUnitAIType() )
- {
- if( plot()->getOwnerINLINE() == getOwnerINLINE() && !bDanger )
- {
- // Should never have attack city group lead by attack unit
- if( getGroup()->countNumUnitAIType(UNITAI_ATTACK_CITY) > 0 )
- {
- getGroup()->AI_separateAI(UNITAI_ATTACK_CITY); // will change group
- // Since ATTACK can try to join ATTACK_CITY again, need these units to
- // take a break to let ATTACK_CITY group move and avoid hang
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- }
- }
- if( AI_guardFortMinDefender() ) {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... guard fort on same plot" );}
- return;
- }
- // Jobs for small patrols
- if (getGroup()->getNumUnits() <= 3)// && !bAtWar)
- {
- if( gUnitLogLevel >= 3 ) logBBAI(" ...checking small group options");
- if (plot()->getOwnerINLINE() != getOwnerINLINE())
- {
- //if( gUnitLogLevel >= 3 ) logBBAI(" ...looking for Settlers to group with");
- if (AI_group(UNITAI_SETTLE, 5, -1, -1, false, false, false, 0, true))
- {
- if( gUnitLogLevel >= 3 ) logBBAI(" ...grouping with Settler in foreign territory");
- return;
- }
- }
- if (AI_cityAttack(1, 75))
- {
- if( gUnitLogLevel >= 3 ) logBBAI(" ...opportunistic city attack");
- return;
- }
- if (AI_pickupEquipment(3))
- {
- if( gUnitLogLevel >= 3 ) logBBAI(" ...picking up equipment");
- return;
- }
- if (AI_anyAttack(1, (bInCity ? 60 : 80)))
- {
- return;
- }
- if (!bDanger)
- {
- int iAttackRange = ((plot()->getOwner() == getOwner()) ? 3: 2);
- if (AI_anyAttack(iAttackRange,90))
- {
- return;
- }
- }
- if (AI_exploreLair(1))
- {
- return;
- }
- if (AI_exploreLairSea(1))
- {
- return;
- }
- }
- if (!bHero)
- {
- if ((GET_TEAM(getTeam()).getAtWarCount(false) == 0) || (!bDanger || !bInCity))
- {
- if (AI_group(UNITAI_SETTLE, 3, -1, -1, false, false, false, 3, false))
- {
- return;
- }
- }
- }
- if (AI_groupMergeRange(UNITAI_HERO, 0, true, true))
- {
- if( gUnitLogLevel >= 3 ) logBBAI(" ...merging with UNITAI_HERO");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_groupMergeRange(UNITAI_ATTACK, 0, true, true))
- {
- if( gUnitLogLevel >= 3 ) logBBAI(" ...merging with UNITAI_ATTACK");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- // this should be in the AI_guardcity function
- if (plot()->isCity() && plot()->getOwner() == getOwner() && bDanger)
- {
- if (plot()->getPlotCity()->AI_neededDefenders() >= plot()->getNumDefenders(getOwnerINLINE()))
- {
- logBBAI(" ...staying to guard city");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- // Attack choking units
- if( plot()->getOwnerINLINE() == getOwnerINLINE() && bDanger )
- {
- int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
- int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
- if( iOurDefense < 3*iEnemyOffense )
- {
- if (AI_guardCity(true))
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...guarding city");
- return;
- }
- }
- if( iOurDefense > 2*iEnemyOffense )
- {
- if (AI_anyAttack(2, 55))
- {
- return;
- }
- }
- if (AI_groupMergeRange(UNITAI_ATTACK, 2, true, true, false))
- {
- return;
- }
- /*
- if( iOurDefense > 2*iEnemyOffense )
- {
- if (AI_anyAttack(2, 30))
- {
- return;
- }
- }
- */
- }
- // Guard a city we're in if it needs it
- if (AI_guardCity(true))
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...Patrol - Guard City 1");
- return;
- }
- if (GC.getLeaderHeadInfo(GET_PLAYER(getOwnerINLINE()).getPersonalityType()).getMaxWarRand() < 75)
- {
- if (AI_poach())
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...poaching");
- return;
- }
- }
- if( !(plot()->isOwned()) )
- {
- // Group with settler after naval drop
- if( AI_groupMergeRange(UNITAI_SETTLE, 2, true, false, false) )
- {
- return;
- }
- }
- if( !(plot()->isOwned()) || (plot()->getOwnerINLINE() == getOwnerINLINE()) )
- {
- if( area()->getCitiesPerPlayer(getOwnerINLINE()) > GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(area(), UNITAI_CITY_DEFENSE) )
- {
- // Defend colonies in new world
- if (AI_guardCity(true, true, 3))
- {
- return;
- }
- }
- }
- if (AI_heal(30, 1))
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...healing");
- return;
- }
- if (AI_stackAttackCity(3, 140))
- {
- logBBAI(" ...Stack Attack City");
- return;
- }
- if (!bDanger && !bHero && !bAtWar)
- {
- if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 3, true))
- {
- return;
- }
- if (AI_group(UNITAI_SETTLE, 4, -1, -1, false, false, false, 3, true))
- {
- return;
- }
- }
- if( AI_guardFortMinDefender( true ) ) {
- if( gUnitLogLevel >= 3 ) {logBBAI( " ... guarding undefended fort" );}
- return;
- }
- if (AI_guardCityAirlift())
- {
- return;
- }
- if (AI_guardCity(false, true, 1))
- {
- return;
- }
- //join any city attacks in progress
- if (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE())
- {
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
- {
- return;
- }
- }
- AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
- if (plot()->isCity())
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
- {
- if (AI_offensiveAirlift())
- {
- return;
- }
- }
- }
- }
- if (bDanger)
- {
- if (AI_cityAttack(1, 65))
- {
- return;
- }
- if (AI_anyAttack(1, 65))
- {
- return;
- }
- if (collateralDamage() > 0 || getUnitInfo().isExplodeInCombat())
- {
- if (AI_anyAttack(1, 45, 3))
- {
- return;
- }
- }
- }
- if (AI_pickupEquipment(3))
- {
- return;
- }
- if (!isHuman())
- {
- if (AI_exploreLair(6))
- {
- return;
- }
- }
- if (!noDefensiveBonus())
- {
- if (AI_guardCity(false, false))
- {
- return;
- }
- }
- if (!bDanger)
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- bool bAssault = ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_MASSING) || (eAreaAIType == AREAAI_ASSAULT_ASSIST));
- if ( bAssault )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, -1, 1, MOVE_SAFE_TERRITORY, 3))
- {
- return;
- }
- bool bLandWar = GET_PLAYER(getOwnerINLINE()).AI_isLandWar(area());
- if (!bLandWar)
- {
- // Fill transports before starting new one, but not just full of our unit ai
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- // Pick new transport which has space for other unit ai types to join
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, 2, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) > 0)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- // Allow larger groups if outside territory
- if( getGroup()->getNumUnits() < 5 )
- {
- if( plot()->isOwned() && GET_TEAM(getTeam()).isAtWar(plot()->getTeam()) )
- {
- if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, true))
- {
- return;
- }
- }
- }
- if (AI_goody(3))
- {
- return;
- }
- if (AI_anyAttack(1, 70))
- {
- return;
- }
- if (bDanger)
- {
- if (AI_pillageRange(1, 20))
- {
- return;
- }
- if (AI_cityAttack(1, 55))
- {
- return;
- }
- if (AI_anyAttack(1, 55))
- {
- return;
- }
- if (AI_pillageRange(3, 20))
- {
- return;
- }
- if( getGroup()->getNumUnits() < 4 )
- {
- if (AI_choke(1))
- {
- return;
- }
- if (AI_groupMergeRange(UNITAI_ATTACK, 2, true, true, true))
- {
- return;
- }
- }
-
- if (AI_cityAttack(4, 80))
- {
- return;
- }
- if (AI_anyAttack(2, 60))
- {
- return;
- }
- }
-
- if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
- {
- if (AI_heal())
- {
- return;
- }
- }
- if (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
- {
- if (getGroup()->getNumUnits() > 1)
- {
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12))
- {
- return;
- }
- }
- }
- else if( area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE )
- {
- if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0)
- {
- //if (getGroup()->getNumUnits() >= GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getBarbarianInitialDefenders())
- if (getGroup()->getNumUnits() >= 5)
- {
- if (AI_goToTargetBarbCity(10))
- {
- return;
- }
- }
- }
- }
-
- if (AI_guardCity(false, true, 3))
- {
- return;
- }
- if (AI_protect(35, 5))
- {
- return;
- }
- if (AI_offensiveAirlift())
- {
- return;
- }
- if (!bDanger && (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE))
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) && !(getGroup()->isHasPathToAreaEnemyCity(false)) )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- }
- }
- if (AI_defend())
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...AI_defend");
- return;
- }
- if (AI_travelToUpgradeCity())
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...travelling to upgrade city");
- return;
- }
-
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...loading on ship due to Stranded status");
- return;
- }
- }
- if( !bDanger && !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
- {
- // If no other desireable actions, wait for pickup
- if( gUnitLogLevel > 3 ) logBBAI(" ...waiting for pickup");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- // switch to Conquest if we're at war and can't find anything to do
- if (getGroup()->getNumUnits() == 1)
- {
- if (bAtWar || bAnyWarPlan)
- {
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- if( gUnitLogLevel > 3 ) logBBAI(" ...switching to GROUPFLAG_CONQUEST");
- //AI_setUnitAIType(UNITAI_ATTACK_CITY);
- return;
- }
- if (AI_group(UNITAI_ATTACK, 5))
- {
- return;
- }
- }
- if( getGroup()->getNumUnits() < 4 )
- {
- if (AI_patrol())
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...patrolling");
- return;
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- if( gUnitLogLevel > 3 ) logBBAI(" ...ERROR? NOTHING TO DO!");
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_HiddenNationalityMove()
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting HiddenNationalityMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- if (!isHiddenNationality())
- {
- AI_setGroupflag(GROUPFLAG_NONE);
- return;
- }
- /*
- if (isAnimal())
- {
- if (!isInvisible(getTeam(), false))
- {
- setHasPromotion((PromotionTypes)GC.getDefineINT("HIDDEN_NATIONALITY_PROMOTION"), false);
- return;
- }
- }
- */
- if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL"))
- {
- if (AI_getUnitAIType() != UNITAI_PIRATE_SEA)
- {
- AI_setUnitAIType(UNITAI_PIRATE_SEA);
- }
- AI_pirateSeaMove();
- return;
- }
- else
- {
- AI_attackMove();
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- // look around for sea lairs to explore
- bool CvUnitAI::AI_exploreLairSea(int iRange)
- {
- if (GET_TEAM(getTeam()).isBarbarianAlly())
- {
- return false;
- }
- int iValue = 0;
- int iBestValue = 0;
- int iPathTurns;
- CvCity* pNearestCity;
- CvPlot* pBestPlot = NULL;
- for (int iX = -iRange; iX <= iRange; iX++)
- {
- for (int iY = -iRange; iY <= iRange; iY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
- if (pLoopPlot != NULL)
- {
- if (pLoopPlot->isWater())
- {
- if ( pLoopPlot->isRevealed(getTeam(), false) || pLoopPlot->isAdjacentRevealed(getTeam()) )
- {
- if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT)
- {
- if ((GC.getImprovementInfo((ImprovementTypes)pLoopPlot->getImprovementType()).isExploreTarget()))
- {
- if (!pLoopPlot->isVisibleEnemyDefender(this))
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= iRange)
- {
- iValue = 20 + getLevel();
- iValue /= (iPathTurns + 1);
- if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).isUnique())
- {
- // Tholal ToDo - make this less hardcoded and scale by game speed
- if (GC.getGameINLINE().getElapsedGameTurns() > ((20 * 100) / GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAITrainPercent()))
- {
- iValue += 2 * getLevel();
- }
- if (pLoopPlot->isOwned())
- {
- // cant explore unique lairs in other player's territory
- if (pLoopPlot->getOwner() != getOwner())
- {
- iValue = 0;
- }
- // dont explore lairs in our territory that offer up free bonuses
- // TODO - allow exploration after we have the tech and units to build the proper improvement
- else if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).getBonusConvert() != NO_BONUS)
- {
- iValue = 0;
- }
- }
- }
- pNearestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
- if (pNearestCity != NULL)
- {
- // avoid opening lairs near our team if they are lightly defended or its early in the game
- if (pNearestCity->getTeam() == getTeam())
- {
- if (!pNearestCity->AI_isDefended() || (GET_PLAYER(getOwnerINLINE()).getNumCities() == 1))
- {
- iValue = 0;
- }
- }
- }
- if (iValue > iBestValue)
- {
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- int ispell = chooseSpell();
- if (ispell != NO_SPELL)
- {
- cast(ispell);
- }
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- else
- {
- if( gUnitLogLevel > 2 ) logBBAI(" ....moving to %d, %d to explore Sea Lair", pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_2);
- return true;
- }
- }
- return false;
- }
- // look around for lairs to explore
- bool CvUnitAI::AI_exploreLair(int iRange)
- {
- if (GET_TEAM(getTeam()).isBarbarianAlly())
- {
- return false;
- }
- if (GET_PLAYER(getOwnerINLINE()).getNumCities() == 0)
- {
- return false;
- }
- int iValue = 0;
- int iBestValue = 0;
- int iPathTurns;
- CvCity* pNearestCity;
- CvPlot* pBestPlot = NULL;
- for (int iX = -iRange; iX <= iRange; iX++)
- {
- for (int iY = -iRange; iY <= iRange; iY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
- if (pLoopPlot != NULL)
- {
- if ( pLoopPlot->isRevealed(getTeam(), false) || pLoopPlot->isAdjacentRevealed(getTeam()) )
- {
- if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT)
- {
- if ((GC.getImprovementInfo((ImprovementTypes)pLoopPlot->getImprovementType()).isExploreTarget()))
- {
- if (!pLoopPlot->isVisibleEnemyDefender(this))
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= iRange)
- {
- iValue = 20 + getLevel();
- iValue /= (iPathTurns + 1);
- if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).isUnique())
- {
- // Tholal ToDo - make this less hardcoded and scale by game speed
- if (GC.getGameINLINE().getElapsedGameTurns() > ((20 * 100) / GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAITrainPercent()))
- {
- iValue += 2 * getLevel();
- }
- if (pLoopPlot->isOwned())
- {
- // cant explore unique lairs in other player's territory
- if (pLoopPlot->getOwner() != getOwner())
- {
- iValue = 0;
- }
- // dont explore lairs in our territory that offer up free bonuses
- // TODO - allow exploration after we have the tech and units to build the proper improvement
- else if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).getBonusConvert() != NO_BONUS)
- {
- iValue = 0;
- }
- }
- }
-
- pNearestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
- if (pNearestCity != NULL)
- {
- // avoid opening lairs near our team if they are lightly defended or its early in the game
- if (pNearestCity->getTeam() == getTeam())
- {
- if (!pNearestCity->AI_isDefended() || (GET_PLAYER(getOwnerINLINE()).getNumCities() == 1))
- {
- iValue = 0;
- }
- }
- }
- if (iValue > iBestValue)
- {
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- int ispell = chooseSpell();
- if (ispell != NO_SPELL)
- {
- cast(ispell);
- }
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- else
- {
- if( gUnitLogLevel > 2 ) logBBAI(" ....moving to %d, %d to explore Lair", pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_2);
- return true;
- }
- }
- return false;
- }
- //Look around for equipment
- bool CvUnitAI::AI_pickupEquipment(int iRange)
- {
- CvUnit* pLoopUnit;
- CvUnit* pBestUnit = NULL;
- CvPlot* pBestPlot;
- int iValue = 0;
- int iBestValue = iRange + 1;
- int iLoop;
- int iPathTurns;
- CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
- if (getMoves() > 1)
- {
- iRange ++;
- }
- // First, look for our equipment and treasure
- for (pLoopUnit = kPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = kPlayer.nextUnit(&iLoop))
- {
- if (pLoopUnit->getUnitInfo().isObject())
- {
- if (generatePath(pLoopUnit->plot(), 0, true, &iPathTurns))
- {
- if (iPathTurns <= iRange)
- {
- iValue = iPathTurns;
- if (iValue < iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopUnit;
- }
- }
- }
- }
- }
- if (pBestUnit != NULL)
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI("Player %d Unit %d (%S's %S) picking up %S\n", getOwnerINLINE(), getID(), GET_PLAYER(getOwnerINLINE()).getName(), getName().GetCString(), pBestUnit->getName().GetCString());
- }
- pBestPlot = pBestUnit->plot();
- if (atPlot(pBestPlot))
- {
- int ispell = chooseSpell();
- if (ispell != NO_SPELL)
- {
- cast(ispell);
- }
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_2);
- return true;
- }
- }
- // TODO - look for ENEMY equipment nearby
- /*
- CvPlot* pBestPlot = NULL;
- for (int iX = -iRange; iX <= iRange; iX++)
- {
- for (int iY = -iRange; iY <= iRange; iY++)
- {
- CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
- if (pLoopPlot != NULL)
- {
- if (pLoopPlot->isVisibleEnemy(GET_TEAM(getTeam())))
- {
- }
- }
- }
- }
- */
- return false;
- }
- void CvUnitAI::AI_ConquestMove()
- {
- CvSelectionGroup* pLoopSelectionGroup;
- CvUnit* pBestUnit;
- CvPlot* pLoopPlot;
- //CvPlot* pBestPlot;
- int iPathTurns;
- //int iDX, iDY;
- int iLoop;
- int iValue;
- int iBestValue;
- //int iSearchRange;
- bool bFollow=false;
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
- //bool bLandWar = !isBarbarian() && ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
- bool bLandWar = !isBarbarian() && kPlayer.AI_isLandWar(area());
- bool bAssault = !isBarbarian() && ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) || (eAreaAIType == AREAAI_ASSAULT_MASSING));
- bool bTurtle = kPlayer.AI_isDoStrategy(AI_STRATEGY_TURTLE);
- bool bAlert1 = kPlayer.AI_isDoStrategy(AI_STRATEGY_ALERT1);
- bool bIgnoreFaster = false;
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" Stack %d (led by %S (%d), size %d) starting ConquestMove", getGroup()->getID(), getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- if (kPlayer.AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
- {
- if (!bAssault && area()->getCitiesPerPlayer(getOwnerINLINE()) > 0)
- {
- bIgnoreFaster = true;
- }
- }
-
- bool bFinancialTrouble = kPlayer.AI_isFinancialTrouble();
- //int bStackSize = getGroup()->getNumUnits();
- //bool bLargeGroup = (bStackSize > (kPlayer.getNumCities() *6));
- bool bHero = false;
- bool bWizard = false;
- switch (AI_getUnitAIType())
- {
- case UNITAI_HERO:
- bHero = true;
- break;
- case UNITAI_WARWIZARD:
- bWizard = true;
- break;
- case UNITAI_RESERVE:
- AI_setUnitAIType(UNITAI_ATTACK_CITY);
- break;
- case UNITAI_ATTACK:
- if ((getLevel() > 4)
- || (kPlayer.AI_getNumAIUnits(UNITAI_ATTACK) > (kPlayer.getNumCities() * (bLandWar ? 2 : 4)))
- || (kPlayer.AI_getNumAIUnits(UNITAI_ATTACK_CITY) < kPlayer.getNumCities()))
- {
- AI_setUnitAIType(UNITAI_ATTACK_CITY);
- break;
- }
- default:
- break;
- }
- if (isHiddenNationality() || isInvisibleFromPromotion())
- {
- if (!bHero && !bWizard)
- {
- AI_setGroupflag(GROUPFLAG_NONE);
- joinGroup(NULL);
- AI_setUnitAIType(UNITAI_ATTACK);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- if (AI_getGroupflag() != GROUPFLAG_CONQUEST)
- {
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- }
- bool bInCity = plot()->isCity();
- if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
- {
- if ((getGroup()->getNumUnits() == 1) && (getDamage() > 0))
- {
- if (AI_heal())
- {
- return;
- }
- }
- if (AI_leaveAttack(1, 70, 175))
- {
- return;
- }
- if( bIgnoreFaster )
- {
- // BBAI TODO: split out slow units ... will need to test to make sure this doesn't cause loops
- }
- if (AI_guardCity(false)) // note. this will eject a unit to defend the city rather then using the whole group
- {
- if( gUnitLogLevel >= 3 ){logBBAI(" ...guarding city on plot");}
- return;
- }
- if (bAssault)
- {
- if (AI_offensiveAirlift())
- {
- return;
- }
- }
- }
- // Opportunistic attacks
- if (getGroup()->getNumUnits() == 1 && !bHero && !bWizard)
- {
- if (AI_anyAttack(1, 80))
- {
- return;
- }
- if (AI_anyAttack(2, 90))
- {
- return;
- }
- }
- // Heroes and Casters should seek larger groups
- if (bHero || bWizard)
- {
- //if (getGroup()->getNumUnits() < ((getLevel() / 2) +1))
- {
- if (AI_pickupEquipment(3))
- {
- return;
- }
- /*
- int iRange = 0;
- if (plot()->getOwner() == getOwner())
- {
- iRange = 5;
- }
- else
- {
- iRange = 10;
- }
- if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) == 0)
- {
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, iRange, false, true, false))
- {
- return;
- }
- }
- if (AI_moveToStagingCity())
- {
- return;
- }
- */
- }
- }
- else // Mainly affects Clan and the units they get from their World Spell
- {
- if (getGroup()->isStranded() && (getLevel() < 3) && bFinancialTrouble)
- {
- logBBAI(" Killing %S (delayed) -- disbanded because stranded and financial trouble (Unit %d - plot: %d, %d)",
- getName().GetCString(), getID(), getX(), getY());
- kill(true);
- return;
- }
- }
- bool bHuntBarbs = false;
- if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0 && !GET_TEAM(getTeam()).isBarbarianAlly())
- {
- if ((eAreaAIType != AREAAI_OFFENSIVE) && (eAreaAIType != AREAAI_DEFENSIVE) && !bAlert1 && !bTurtle)
- {
- bHuntBarbs = true;
- }
- }
- bool bReadyToAttack = false;
- if( !bTurtle )
- {
- bReadyToAttack = ((getGroup()->getNumUnits() >= ((bHuntBarbs) ? 3 : AI_stackOfDoomExtra())));
- }
-
- if (AI_guardCity(false, false))
- {
- return;
- }
- //ToDo - better incorporation of this section into rest of code
- iValue = 0;
- iBestValue = 0;
- if (plot()->getOwnerINLINE() == getOwnerINLINE() && !isCargo())
- {
- iBestValue = getGroup()->getNumUnits();
- pBestUnit = NULL;
- //if (getGroup()->getNumUnits() == 1)
- {
- if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) == 0)
- {
- for(pLoopSelectionGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopSelectionGroup != NULL; pLoopSelectionGroup = kPlayer.nextSelectionGroup(&iLoop))
- {
- if (pLoopSelectionGroup->getHeadUnit() != NULL)
- {
- if (pLoopSelectionGroup->getHeadUnit()->AI_getGroupflag() == GROUPFLAG_CONQUEST)
- {
- if (pLoopSelectionGroup != getGroup() && !pLoopSelectionGroup->getHeadUnit()->isCargo())
- {
- pLoopPlot = pLoopSelectionGroup->getHeadUnit()->plot();
- if (AI_plotValid(pLoopPlot))
- {
- if (!isEnemy(pLoopPlot->getTeam()))
- {
- if (AI_allowGroup(pLoopSelectionGroup->getHeadUnit(), UNITAI_UNKNOWN))
- {
- if (!(pLoopPlot->isVisibleEnemyUnit(this)))
- {
- if ((getGroup()->getNumUnits() == 1) ||
- atPlot(pLoopPlot))
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- iValue = 10 * pLoopSelectionGroup->getHeadUnit()->getLevel();
- iValue += pLoopSelectionGroup->getNumUnits();
- if (pLoopSelectionGroup->getHeadUnit()->AI_getUnitAIType() == UNITAI_HERO)
- {
- iValue *= 2;
- }
- if (pLoopSelectionGroup->getHeadUnit()->isAvatarOfCivLeader())
- {
- iValue *= 5;
- }
- if (atPlot(pLoopPlot))
- {
- iValue *= 2;
- }
- else
- {
- iValue /= (iPathTurns + 1);
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopSelectionGroup->getHeadUnit();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestUnit != NULL)
- {
- if (atPlot(pBestUnit->plot()))
- {
- if (getGroup()->getNumUnits() == 1)
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" ...joining group %d on plot", pBestUnit->getGroup());
- }
- joinGroup(pBestUnit->getGroup());
- return;
- }
- else
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" ...merging into group %d on plot", pBestUnit->getGroup());
- }
- getGroup()->mergeIntoGroup(pBestUnit->getGroup());
- return;
- }
- }
- else
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" ...moving to merge group");
- }
- getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
- return;
- }
- }
- }
- /*
- else
- {
- bool bMerge = false;
- pBestUnit = NULL;
- for(pLoopSelectionGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopSelectionGroup != NULL; pLoopSelectionGroup = kPlayer.nextSelectionGroup(&iLoop))
- {
- if (pLoopSelectionGroup->getHeadUnit() != NULL)
- {
- if (pLoopSelectionGroup->getHeadUnit()->AI_getGroupflag()==GROUPFLAG_CONQUEST)
- {
- if (pLoopSelectionGroup != getGroup() && !pLoopSelectionGroup->getHeadUnit()->isCargo())
- {
- CvPlot* pPlot = pLoopSelectionGroup->getHeadUnit()->plot();
- if (AI_plotValid(pPlot))
- {
- if (!isEnemy(pPlot->getTeam()))
- {
- if (!(pPlot->isVisibleEnemyUnit(this)))
- {
- if (AI_allowGroup(pLoopSelectionGroup->getHeadUnit(), UNITAI_UNKNOWN))
- {
- if (generatePath(pPlot, 0, true, &iPathTurns))
- {
- if (pLoopSelectionGroup->getNumUnits() > (getGroup()->getNumUnits() * 2))
- {
- if (iPathTurns < 5)
- {
- bMerge = true;
- pBestUnit = pLoopSelectionGroup->getHeadUnit();
- break;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (bMerge)
- {
- if (atPlot(pBestUnit->plot()))
- {
- getGroup()->mergeIntoGroup(pBestUnit->getGroup());
- return;
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
- return;
- }
- }
- }
- */
- }
- bool bAtWar = isEnemy(plot()->getTeam());
- // Look for local threats - mainly meant to deal with early barbarian or HN threats
- bool bDanger = (kPlayer.AI_getAnyPlotDanger(plot(), 3, false));
- if( bReadyToAttack )
- {
- // Check that stack has units which can capture cities
- bReadyToAttack = false;
- int iCityCaptureCount = 0;
- CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
- while (pUnitNode != NULL && !bReadyToAttack)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- if( !pLoopUnit->isOnlyDefensive() )
- {
- if( !(pLoopUnit->isNoCapture()) && (pLoopUnit->combatLimit() >= 100) )
- {
- iCityCaptureCount++;
- if( iCityCaptureCount > 5 || 3*iCityCaptureCount > getGroup()->getNumUnits() )
- {
- bReadyToAttack = true;
- }
- }
- }
- }
- }
- CvCity* pTargetCity = NULL;
- if (bReadyToAttack)
- {
- //if (AI_cityAttack(1, 80, true))
- if (AI_stackAttackCity(1, 160, true))
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" ...making opportunistic city attack");
- }
- return;
- }
- }
- if (AI_guardCity(false, false))
- {
- /*
- if( bReadyToAttack && (eAreaAIType != AREAAI_DEFENSIVE))
- {
- CvSelectionGroup* pOldGroup = getGroup();
- pOldGroup->AI_separateNonAI(UNITAI_ATTACK_CITY);
- }
- */
- return;
- }
- if (AI_groupMergeRange(UNITAI_HERO, 0, false, true, bIgnoreFaster))
- {
- logBBAI(" ...merging with hero unit");
- return;
- }
-
- if (AI_groupMergeRange(UNITAI_WARWIZARD, 0, false, true, bIgnoreFaster))
- {
- logBBAI(" ...merging with wizard unit");
- return;
- }
-
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 0, true, true, bIgnoreFaster))
- {
- logBBAI(" ...merging with attack city unit");
- return;
- }
- // BBAI TODO: Find some way of reliably targetting nearby cities with less defense ...
- pTargetCity = AI_pickTargetCity(0, MAX_INT, bHuntBarbs);
-
- if( pTargetCity != NULL && (getGroup()->getNumUnits() > 1))
- {
- if( gUnitLogLevel >= 3 ) logBBAI(" ...trying to assault target city");
- int iStepDistToTarget = stepDistance(pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), getX_INLINE(), getY_INLINE());
- //int iAttackRatio = std::max(100, GC.getBBAI_ATTACK_CITY_STACK_RATIO());
- int iAttackRatio = 150; //Todo - find better way to come up with an AttackRatio - should vary based on situation
- // loop through units. Add level Subtract if melee or collateral or explodeincombat. Add if mage or UNITAI_HERO
- int iComparePostBombard = 0;
- // AI gets a 1-tile sneak peak to compensate for lack of memory
- if( iStepDistToTarget <= 2 || pTargetCity->isVisible(getTeam(),false) )
- {
- iComparePostBombard = getGroup()->AI_compareStacks(pTargetCity->plot(), true, true, true);
- int iDefenseModifier = pTargetCity->getDefenseModifier(true);
- int iBombardTurns = getGroup()->getBombardTurns(pTargetCity);
- iDefenseModifier *= std::max(0, 20 - iBombardTurns);
- iDefenseModifier /= 20;
- iComparePostBombard *= 100 + std::max(0, iDefenseModifier);
- iComparePostBombard /= 100;
- }
- logBBAI(" ...iComparePostBombard = %d", iComparePostBombard);
- if( iStepDistToTarget <= 2 )
- {
- if( iComparePostBombard < iAttackRatio )
- {
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
- {
- return;
- }
- int iOurOffense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),1,false,false,true);
- int iEnemyOffense = kPlayer.AI_getEnemyPlotStrength(pTargetCity->plot(),2,false,false);
- // If in danger, seek defensive ground
- if( 4*iOurOffense < 3*iEnemyOffense)
- {
- if( AI_choke(1, true) )
- {
- logBBAI(" ...choking %S due to troop presence in city", pTargetCity->getName().GetCString());
- return;
- }
- }
- }
- if (iStepDistToTarget == 1)
- {
- // temp hack - Tholal ToDo: need to figure out why the AI is reluctant to attack empty cities
- logBBAI(" ...next to target city...");
- if (pTargetCity->plot()->getNumDefenders(pTargetCity->getOwner()) == 0)
- {
- logBBAI(" ...target city is empty!");
- getGroup()->pushMission(MISSION_MOVE_TO, pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), MOVE_DIRECT_ATTACK);
- return;
- }
- // If next to target city and we would attack after bombarding down defenses,
- // or if defenses have crept up past half
- if( (iComparePostBombard >= iAttackRatio) || (pTargetCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE() * 1) / 2)) )
- {
- logBBAI(" ...considering attack/bombard...");
- if( (iComparePostBombard < std::max(150, GC.getDefineINT("BBAI_SKIP_BOMBARD_MIN_STACK_RATIO"))) )
- {
-
- // Tholal Note: this section wasn't doing much useful
- // Move to good tile to attack from unless we're way more powerful
- /*
- if (plot()->defenseModifier(getTeam(), false) <= 0)
- {
- if( AI_goToTargetCity(0,1,pTargetCity) )
- {
- return;
- }
- }
- */
- }
- // Bombard may skip if stack is powerful enough
- if (AI_bombardCity())
- {
- logBBAI(" ...bombarding city");
- return;
- }
- //stack attack
- if (getGroup()->getNumUnits() > 1)
- {
- // BBAI TODO: What is right ratio?
- //if (AI_stackAttackCity(1, iAttackRatio, true))
- //if (AI_cityAttack(1, iAttackRatio, true))
- if (AI_stackAttackCity(1, iAttackRatio, true))
- {
- logBBAI(" ...stack attacking city");
- return;
- }
- }
- // If not strong enough alone, merge if another stack is nearby
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
- {
- logBBAI(" ...merging with another group");
- return;
- }
-
- if( getGroup()->getNumUnits() == 1 )
- {
- if( AI_cityAttack(1, 70) )
- {
- logBBAI(" ...solo city attack");
- return;
- }
- }
- }
- }
- }
- if( iComparePostBombard < iAttackRatio && GET_TEAM(getTeam()).isAtWar(pTargetCity->getTeam()))
- {
- // If not strong enough, pillage around target city without exposing ourselves
- if( AI_pillageRange(0) )
- {
- logBBAI(" ...pillaging");
- return;
- }
-
- if( AI_anyAttack(1, 80, 0, false) )
- {
- logBBAI(" ...AI_anyttack");
- return;
- }
- if (AI_heal(30, 1))
- {
- logBBAI(" ...healing");
- return;
- }
- // Pillage around enemy city
- if( AI_pillageAroundCity(pTargetCity, 11, 3) )
- {
- logBBAI(" ...pillage around city 1\n");
- return;
- }
- if( AI_pillageAroundCity(pTargetCity, 0, 5) )
- {
- logBBAI(" ...pillage around city 2\n");
- return;
- }
- if (getGroup()->getNumUnits() > pTargetCity->plot()->getNumDefenders(pTargetCity->getOwner()))
- {
- if( AI_choke(1) )
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" ...choking %S ", pTargetCity->getName().GetCString());
- }
- return;
- }
- }
- if (!pTargetCity->isVisible(getTeam(),false))
- {
- if (AI_goToTargetCity(0, 10, pTargetCity))
- {
- logBBAI(" ...moving to scout target city (%S)", pTargetCity->getName().GetCString());
- return;
- }
- }
- }
- else
- {
- if( AI_goToTargetCity(0,6,pTargetCity) )
- {
- logBBAI(" ...moving to target city (%S)", pTargetCity->getName().GetCString());
- return;
- }
- }
-
- // Tholal Note - seems that sometimes we have to force the AI to attack their targets
- // Note: This section can cause the AI to declare War before stack is near borders
- if (iComparePostBombard >= 120)
- {
- if (GET_TEAM(getTeam()).isAtWar(pTargetCity->getTeam()) || plot()->isAdjacentPlayer(pTargetCity->getOwner()))
- {
- if( AI_goToTargetCity(MOVE_THROUGH_ENEMY, 10 ,pTargetCity) )
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" ...moving to direct attack %S", pTargetCity->getName().GetCString());
- }
- return;
- }
- }
- else
- {
- if( AI_goToTargetCity(0, 10 ,pTargetCity) )
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" ...moving to attack %S", pTargetCity->getName().GetCString());
- }
- return;
- }
- }
- }
- }
- if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
- {
- return;
- }
-
- if (AI_heal(30, 1))
- {
- return;
- }
- // BBAI TODO: Stack v stack combat ... definitely want to do in own territory, but what about enemy territory?
- if (collateralDamage() > 0 && plot()->getOwnerINLINE() == getOwnerINLINE()) // note: this requires that the group leader has collateralDamage; doesnt check whole stack
- {
- if (AI_anyAttack(1, 45, 3, false))
- {
- return;
- }
- if( !bReadyToAttack )
- {
- if (AI_anyAttack(1, 25, 5, false))
- {
- return;
- }
- }
- }
- if (AI_anyAttack(1, 60, 0, false))
- {
- return;
- }
- if (bAtWar && (getGroup()->getNumUnits() <= 2))
- {
- if (AI_pillageRange(3, 11))
- {
- logBBAI(" ...pillage3 \n");
- return;
- }
- if (AI_pillageRange(1))
- {
- logBBAI(" ...pillage 4 \n");
- return;
- }
- }
- bHuntBarbs = false;
- if ((area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0) && !GET_TEAM(getTeam()).isBarbarianAlly())
- {
- if ((area()->getAreaAIType(getTeam()) != AREAAI_OFFENSIVE) && (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE))
- {
- bHuntBarbs = true;
- }
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- if (!bLandWar)
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- if( bReadyToAttack )
- {
- // Wait for units about to join our group
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- int iJoiners = kPlayer.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
-
- if( (iJoiners*5) > getGroup()->getNumUnits() )
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- else
- {
- if (eAreaAIType == AREAAI_DEFENSIVE)
- {
- // Use smaller attack city stacks on defenses
- if (AI_guardCity(false, true, 3))
- {
- return;
- }
- }
- if( bTurtle )
- {
- if (AI_guardCity(false, true, 7))
- {
- return;
- }
- }
- int iTargetCount = kPlayer.AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
- if ((iTargetCount * 5) > getGroup()->getNumUnits())
- {
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- int iJoiners = kPlayer.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
-
- if( (iJoiners*5) > getGroup()->getNumUnits() )
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_moveToStagingCity())
- {
- return;
- }
- }
- }
- }
- if (AI_heal(50, 3))
- {
- return;
- }
- if (!bAtWar)
- {
- if (AI_heal())
- {
- return;
- }
- if ((getGroup()->getNumUnits() == 1) && (getTeam() != plot()->getTeam()))
- {
- if (AI_retreatToCity())
- {
- return;
- }
- }
- }
- if (!bReadyToAttack && !noDefensiveBonus())
- {
- if (AI_guardCity(false, false))
- {
- return;
- }
- }
- bool bAnyWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);
- if (bReadyToAttack)
- {
- if (bHuntBarbs || pTargetCity == NULL)
- {
- if (AI_goToTargetBarbCity((bAnyWarPlan ? 7 : 15)))
- {
- return;
- }
- }
- else if (bLandWar && pTargetCity != NULL && (getGroup()->getNumUnits() > 1))
- {
- // Before heading out, check whether to wait to allow unit upgrades
- if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
- {
- if( !(kPlayer.AI_isFinancialTrouble()) )
- {
- // Check if stack has units which can upgrade
- int iNeedUpgradeCount = 0;
- CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
- while (pUnitNode != NULL)
- {
- CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = getGroup()->nextUnitNode(pUnitNode);
- if( pLoopUnit->getUpgradeCity(false) != NULL )
- {
- iNeedUpgradeCount++;
- if( (2 * iNeedUpgradeCount) > getGroup()->getNumUnits()) // was 8
- {
- if (getGroup()->getNumUnits() < (kPlayer.getNumCities() * 8))
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" ...waiting for upgrades. Groupsize: %d (potential upgrades: %d)\n", getGroup()->getNumUnits(), iNeedUpgradeCount);
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- }
- }
- }
- }
- }
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 5, pTargetCity))
- {
- return;
- }
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 2, 2))
- {
- return;
- }
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 8, pTargetCity))
- {
- return;
- }
- // Load stack if walking will take a long time
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 3))
- {
- return;
- }
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12, pTargetCity))
- {
- return;
- }
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 7))
- {
- return;
- }
-
- if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, MAX_INT, pTargetCity))
- {
- return;
- }
-
- if (bAnyWarPlan)
- {
- CvCity* pTargetCity = area()->getTargetCity(getOwnerINLINE());
- if (pTargetCity != NULL)
- {
- if( gUnitLogLevel >= 3 ) logBBAI(" ...%S, %d blockage problem", getName().GetCString(), getID());
- if (AI_solveBlockageProblem(pTargetCity->plot(), (GET_TEAM(getTeam()).getAtWarCount(true) == 0)))
- {
- return;
- }
- }
- }
- }
- }
- else
- {
- int iTargetCount = kPlayer.AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
- if( ((iTargetCount * 4) > getGroup()->getNumUnits()) || ((getGroup()->getNumUnits() + iTargetCount) >= (bHuntBarbs ? 5 : AI_stackOfDoomExtra())) )
- {
- MissionAITypes eMissionAIType = MISSIONAI_GROUP;
- int iJoiners = kPlayer.AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
-
- if( (iJoiners*6) > getGroup()->getNumUnits() )
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_safety())
- {
- return;
- }
- }
- if ((bombardRate() > 0) && noDefensiveBonus())
- {
- // BBAI Notes: Add this stack lead by bombard unit to stack probably not lead by a bombard unit
- // BBAI TODO: Some sense of minimum stack size? Can have big stack moving 10 turns to merge with tiny stacks
- if (AI_group(UNITAI_ATTACK_CITY, -1, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ false))
- {
- return;
- }
- }
- else
- {
- if (AI_group(UNITAI_ATTACK_CITY, AI_stackOfDoomExtra() * 2, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ false))
- {
- return;
- }
- }
- }
- if (plot()->getOwnerINLINE() == getOwnerINLINE() && bLandWar)
- {
- if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) )
- {
- // if no land path to enemy cities, try getting there another way
- if (AI_offensiveAirlift())
- {
- return;
- }
- if( pTargetCity != NULL )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
- {
- return;
- }
- }
- }
- }
- if (AI_moveToStagingCity())
- {
- return;
- }
- if (AI_offensiveAirlift())
- {
- return;
- }
- if (AI_guardFort(true))
- {
- return;
- }
- if (AI_travelToUpgradeCity())
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if( getGroup()->isStranded() )
- {
- if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
- {
- return;
- }
- if( !isHuman() && plot()->isCoastalLand() && kPlayer.AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
- {
- // If no other desireable actions, wait for pickup
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- if (AI_patrol())
- {
- return;
- }
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_heromove()
- {
- if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_NAVAL"))
- {
- if (isHiddenNationality())
- {
- AI_setUnitAIType(UNITAI_PIRATE_SEA);
- return;
- }
- else
- {
- AI_setUnitAIType(UNITAI_ATTACK_SEA);
- return;
- }
- }
- if (AI_heal())
- {
- return;
- }
- if (getUnitClassType()==GC.getDefineINT("UNITCLASS_GOVANNON"))
- {
- if (AI_Govannonmove())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
-
- if (getUnitClassType()==GC.getDefineINT("UNITCLASS_LOKI"))
- {
- if (AI_Lokimove())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
-
- if (getUnitClassType()==GC.getDefineINT("UNITCLASS_RANTINE"))
- {
- if (GET_TEAM(getTeam()).isBarbarianAlly() && getLevel() < 8)
- {
- if (AI_Rantinemove())
- {
- return;
- }
- }
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
-
- if (getGroup()->getNumUnits() > 1)
- {
- joinGroup(NULL);
- }
- if ((GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0) || isAvatarOfCivLeader())
- {
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- }
- else
- {
- AI_setGroupflag(GROUPFLAG_PATROL);
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- bool CvUnitAI::AI_Govannonmove()
- {
- if (GC.getDefineINT("SPELL_TEACH_SPELLCASTING") != -1)
- {
- if (canCast(GC.getDefineINT("SPELL_TEACH_SPELLCASTING"),false))
- cast(GC.getDefineINT("SPELL_TEACH_SPELLCASTING"));
- int iBestValue=0, iValue;
- int iLoop;
- int iPathTurns;
- CvSelectionGroup* pLoopSelectionGroup;
- CvUnit* pBestUnit=NULL;
- for(pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).firstSelectionGroup(&iLoop); pLoopSelectionGroup != NULL; pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).nextSelectionGroup(&iLoop))
- {
- if (pLoopSelectionGroup->getHeadUnit() != NULL)
- {
- if (pLoopSelectionGroup!=getGroup())
- {
- CvPlot* pPlot = pLoopSelectionGroup->getHeadUnit()->plot();
- if (AI_plotValid(pPlot))
- {
- if (pPlot->getOwnerINLINE()==getOwnerINLINE() && pPlot!=plot())
- {
- if (!(pPlot->isVisibleEnemyUnit(this)))
- {
- if (GC.getGameINLINE().getSorenRandNum(100, "GovannonScores")<10)
- {
- if (generatePath(pPlot, 0, true, &iPathTurns))
- {
- iValue = pLoopSelectionGroup->getNumUnits()/(iPathTurns+1);
- if (iValue >= iBestValue)
- {
- iBestValue = iValue;
- pBestUnit = pLoopSelectionGroup->getHeadUnit();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestUnit!=NULL)
- {
- if (atPlot(pBestUnit->plot()))
- {
- //Spell
- return false;
- }
- else if (generatePath(pBestUnit->plot(), 0, true, &iPathTurns))
- {
- //getGroup()->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, NO_MISSIONAI, NULL, pBestUnit);
- getGroup()->pushMission(MISSION_MOVE_TO, pBestUnit->getX_INLINE(), pBestUnit->getY_INLINE(), MOVE_DIRECT_ATTACK);
- return true;
- }
- }
- }
- return false;
- }
- bool CvUnitAI::AI_Lokimove()
- {
- logBBAI(" %S (unit %d) starting LokiMove", getName().GetCString(), getID());
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- bool bFinancialTrouble = kPlayer.AI_isFinancialTrouble();
- if (getGroup()->getNumUnits() > 1)
- {
- logBBAI(" ...leaving group");
- joinGroup(NULL);
- }
- // HARDCODE!
- if (plot()->isCity())
- {
- if (!bFinancialTrouble && plot()->getPlotCity()->getCulture(plot()->getPlotCity()->getOwnerINLINE())==0)
- {
- if (canCast(GC.getDefineINT("SPELL_DISRUPT"),false))
- cast(GC.getDefineINT("SPELL_DISRUPT"));
- }
- else
- {
- if (plot()->getOwnerINLINE() == getOwnerINLINE())
- {
- int ispell = chooseSpell();
- if (ispell != NO_SPELL)
- {
- cast(ispell);
- }
- }
- else
- {
- if (canCast(GC.getDefineINT("SPELL_ENTERTAIN"),false))
- cast(GC.getDefineINT("SPELL_ENTERTAIN"));
- }
- }
- }
-
- CvCity* pLoopCity;
- int iLoop = 0;
- int iPathTurns;
- CvPlot* pBestPlot = NULL;
- int iValue = 0;
- int iBestValue = 0;
- // find a target city - preference given to high population cities (for Entertain) and zero culture cities (for Disrupt)
- for (int iI = 0; iI < MAX_PLAYERS; iI++)
- {
- if (GET_PLAYER((PlayerTypes)iI).isAlive())
- {
- //don't target teammates or vassals
- if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam() && !GET_TEAM(GET_PLAYER((PlayerTypes)iI).getTeam()).isVassal(getTeam()))
- {
- for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
- {
- if (kPlayer.AI_deduceCitySite(pLoopCity))
- {
- if (!GET_TEAM(getTeam()).isAtWar(pLoopCity->getTeam()))
- {
- if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
- {
- iValue = pLoopCity->getPopulation();
- if (pLoopCity->getCulture(pLoopCity->getOwnerINLINE())==0)
- {
- if (pLoopCity->plot()->isAdjacentPlayer(getOwner()))
- {
- iValue *= 10;
- }
- else
- {
- iValue *= 2;
- }
- }
-
- iValue /= iPathTurns;
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopCity->plot();
- }
- }
- }
- }
- }
- }
- }
- }
-
- if (pBestPlot != NULL)
- {
- logBBAI(" ...targeting %S (value: %d)", pBestPlot->getPlotCity()->getName().GetCString(), iBestValue);
- if (atPlot(pBestPlot))
- {
- logBBAI(" ...at target city");
- getGroup()->pushMission(MISSION_SKIP);
- return true;
- }
- else
- {
- logBBAI(" ...moving to target city");
- getGroup()->pushMission(MISSION_MOVE_TO,pBestPlot->getX_INLINE(),pBestPlot->getY_INLINE(),MOVE_THROUGH_ENEMY);
- return true;
- }
- }
- if (AI_exploreRange(5))
- {
- logBBAI(" ...exploring");
- return true;
- }
- if (AI_retreatToCity())
- {
- return true;
- }
- if (AI_safety())
- {
- return true;
- }
- return false;
- }
- bool CvUnitAI::AI_Rantinemove()
- {
- //ToDo - figure out why this grouping code isn't working anymore - for now, just skip it
- //if (getGroup()->getNumUnits()<4)
- if (2 < 1)
- {
- if (!(plot()->isCity() && plot()->getOwnerINLINE()==getOwnerINLINE()))
- {
- if (AI_retreatToCity())
- {
- return true;
- }
- }
- int iSearchRange=5;
- int icount=0;
- int iDX, iDY;
- CvPlot* pLoopPlot;
- CvUnit* pLoopUnit;
- int iPathTurns;
- CLLNode<IDInfo>* pUnitNode;
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (pLoopPlot->getOwnerINLINE()==getOwnerINLINE())
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- pUnitNode = pLoopPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
- if (pLoopUnit)
- {
- if (!(pLoopUnit->getGroup()->getHeadUnit()==pLoopUnit) || pLoopUnit->getGroup()->getNumUnits()==1)
- {
- if (pLoopUnit->AI_getUnitAIType()==UNITAI_COUNTER && pLoopUnit->AI_getGroupflag()==GROUPFLAG_PATROL)
- {
- if(pLoopUnit->getGroup()->getHeadUnit()!=pLoopUnit || pLoopUnit->getGroup()->getNumUnits()==1)
- {
- if(pLoopUnit->atPlot(plot()))
- {
- pLoopUnit->joinGroup(NULL);
- pLoopUnit->AI_setGroupflag(GROUPFLAG_NONE);
- pLoopUnit->AI_setUnitAIType(UNITAI_ATTACK);
- pLoopUnit->joinGroup(getGroup());
- return false;
- }
- else
- {
- //pLoopUnit->getGroup()->pushMission(MISSION_MOVE_TO_UNIT, getOwnerINLINE(), getID(), 0, false, false, MISSIONAI_GROUP, NULL, this);
- pLoopUnit->getGroup()->pushMission(MISSION_MOVE_TO, getX_INLINE(), getY_INLINE(), MOVE_DIRECT_ATTACK);
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- else
- {
- CvCity* pLoopCity;
- CvCity* pBestCity = NULL;
- int iLoop;
- int iSearchRange=8;
- int icount=0;
- int iPathTurns;
- int iValue = 0;
- int iBestValue = 0;
- CvPlot* pBestPlot = NULL;
- if (plot()->isCity())
- {
- if (canCast(GC.getDefineINT("SPELL_CONVERT_CITY_RANTINE"),false))
- cast(GC.getDefineINT("SPELL_CONVERT_CITY_RANTINE"));
- }
- //ToDo: figure out how to load Rantine into a boat
- for (pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).nextCity(&iLoop))
- {
- if (AI_plotValid(pLoopCity->plot()))
- {
- if (pLoopCity->isRevealed(getTeam(), false) || pLoopCity->plot()->isAdjacentRevealed(getTeam()))
- {
- if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
- {
- iValue = (pLoopCity->getPopulation() * 10);
- if ((pLoopCity->plot())->isAdjacentPlayer(getOwnerINLINE(), false))
- {
- iValue *= 3;
- }
- iValue /= (iPathTurns + 1);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestCity = pLoopCity;
- }
- }
- }
- }
- }
- if (pBestCity != NULL)
- {
- pBestPlot = pBestCity->plot();
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
- return true;
- }
- }
- return false;
- }
- void CvUnitAI::AI_upgrademanaMove()
- {
- logBBAI(" %S (unit %d), starting AI_upgrademanaMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
- if (GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_TOWERMASTERY1))
- {
- if (GET_PLAYER(getOwnerINLINE()).countOwnedBonuses((BonusTypes)GC.getDefineINT("BONUSCLASS_MANA_RAW")) == 1)
- {
- if (GET_PLAYER(getOwnerINLINE()).countOwnedBonuses((BonusTypes)GC.getInfoTypeForString("BONUS_MANA_METAMAGIC")) == 0)
- {
- if( gUnitLogLevel > 2 ) logBBAI(" ...reserving a raw mana for Metamagic");
- if (plot()->isCity())
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...fortifying in city");
- getGroup()->pushMission(MISSION_FORTIFY);
- return;
- }
- else
- {
- if( gUnitLogLevel > 3 ) logBBAI(" ...retreating to city");
- if (AI_retreatToCity())
- return;
- }
- }
- }
- }
- bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
- if (bDanger)
- {
- if (AI_retreatToCity())
- {
- return;
- }
- }
- if (AI_heal())
- {
- return;
- }
-
- int iValue = 0;
- int iBestValue = 0;
- int iPathTurns;
- bool bBonusRawMana = false;
- bool bBonusMana = false;
- //int iRange = 15;
- CvPlot* pBestPlot = NULL;
- BuildTypes eBuild = NO_BUILD;
- BuildTypes eBestBuild = NO_BUILD;
- CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
- //ToDo - keep one spare raw mana node if we have more than X mana and are pursuing Tower victory (for metamagic node)
- bool bReadytoBuild = false;
- // loop through plots in range
- // ToDo - make this a map search?
- /*
- for (int iX = -iRange; iX <= iRange; iX++)
- {
- for (int iY = -iRange; iY <= iRange; iY++)
- {
- */
- {
- for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- //CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
- if (pLoopPlot != NULL)
- {
- if ( pLoopPlot->getOwner() == getOwner())
- {
- if (!pLoopPlot->isVisibleEnemyDefender(this) && !kPlayer.AI_getAnyPlotDanger(pLoopPlot))
- {
- if (pLoopPlot->getBonusType() != NO_BONUS)
- {
- bBonusRawMana = false;
- bBonusMana = false;
- // HARDCODE - should have some sort of global variable to let the AI know about mana - XML tag?
- //if (GC.getBonusInfo(pLoopPlot->getBonusType()).getBonusClassType() == GC.getDefineINT("BONUSCLASS_MANA"))
- if (GC.getBonusInfo(pLoopPlot->getBonusType()).isMana())
- {
- // check to make sure we don't check existing nodes
- if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT)
- {
- bBonusMana = true;
- }
- else
- {
- if (GC.getImprovementInfo(pLoopPlot->getImprovementType()).getBonusConvert() == NO_BONUS)
- {
- bBonusMana = true;
- }
- }
- }
- // HARDCODE
- if (GC.getBonusInfo(pLoopPlot->getBonusType()).getBonusClassType() == GC.getDefineINT("BONUSCLASS_MANA_RAW"))
- {
- bBonusRawMana = true;
- }
- if (bBonusMana || bBonusRawMana)
- {
- // found mana, now check path
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- // we can reach the mana, now make sure we have a build
- bool bFoundBuild = false;
- for (int iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
- {
- eBuild = ((BuildTypes)iJ);
- if (canBuild(pLoopPlot, eBuild))
- {
- bFoundBuild = true;
- break;
- }
- }
-
- if (bFoundBuild)
- {
- iValue = 100 / (iPathTurns +1);
- if (iValue > iBestValue)
- {
- pBestPlot = pLoopPlot;
- iBestValue = iValue;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- if (isHasCasted()) // casting blocks mana builds
- {
- getGroup()->pushMission(MISSION_FORTIFY);
- return;
- }
- iBestValue = 0;
- eBestBuild = NO_BUILD;
- // loop through various builds and find the best one
- for (int iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
- {
- eBuild = ((BuildTypes)iJ);
- if (canBuild(plot(), eBuild))
- {
- // we have to first get the improvement, then find out what mana this node will be converted to
- ImprovementTypes eImprovement = (ImprovementTypes)GC.getBuildInfo(eBuild).getImprovement();
- BonusTypes eNewBonus = (BonusTypes)GC.getImprovementInfo(eImprovement).getBonusConvert();
- iValue = kPlayer.AI_bonusVal(eNewBonus) + 1;
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" %S mana value: %d\n", GC.getBuildInfo((BuildTypes)eBuild).getDescription(), iValue);
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- eBestBuild = eBuild;
- }
- }
- }
- if (eBestBuild != NO_BUILD)
- {
- if( gUnitLogLevel >= 2 )
- {
- 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());
- }
- getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, false, false, MISSIONAI_BUILD, plot());
- return;
- }
- }
- else
- {
- if( gUnitLogLevel >= 3 )
- {
- logBBAI(" ...moving to mana node at plot %d, %d", pBestPlot->getX(), pBestPlot->getY());
- }
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_2);
- return;
- }
- }
-
- CyUnit* pyUnit1 = new CyUnit(this);
- CyArgsList argsList1;
- argsList1.add(gDLL->getPythonIFace()->makePythonObject(pyUnit1)); // pass in unit class
- long lResult=0;
- gDLL->getPythonIFace()->callFunction(PYGameModule, "AI_Mage_UPGRADE_MANA", argsList1.makeFunctionArgs(), &lResult);
- delete pyUnit1; // python fxn must not hold on to this pointer
- if (lResult == 1)
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
-
- if (AI_moveIntoCity(5))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- // this is called every turn once in DoTurnUnitsPre()
- // Tholal note - lots of hardcode
- void CvUnitAI::AI_mageCast()
- {
- CvCity* pCity;
- pCity=this->plot()->getPlotCity();
- // War Spells
- if (canCast(GC.getInfoTypeForString("SPELL_REPAIR"),false))
- {
- cast(GC.getInfoTypeForString("SPELL_REPAIR"));
- }
- if (canCast(GC.getInfoTypeForString("SPELL_RUST"),false))
- {
- cast(GC.getInfoTypeForString("SPELL_RUST"));
- }
- if (canCast(GC.getInfoTypeForString("SPELL_SLOW"),false))
- {
- cast(GC.getInfoTypeForString("SPELL_SLOW"));
- }
- // Spells to permanently improve new Units
- if (GET_PLAYER(getOwnerINLINE()).getCivilizationType() == GC.getInfoTypeForString("CIVILIZATION_BALSERAPHS"))
- if (canCast(GC.getInfoTypeForString("SPELL_MUTATION"),false))
- cast(GC.getInfoTypeForString("SPELL_MUTATION"));
- if (canCast(GC.getInfoTypeForString("SPELL_FLAMING_ARROWS"),false))
- cast(GC.getInfoTypeForString("SPELL_FLAMING_ARROWS"));
- if (canCast(GC.getInfoTypeForString("SPELL_ENCHANTED_BLADE"),false))
- cast(GC.getInfoTypeForString("SPELL_ENCHANTED_BLADE"));
- // Spells to permanently improve the City
- if (canCast(GC.getInfoTypeForString("SPELL_WALL_OF_STONE"),false))
- if (pCity->getNumBuilding((BuildingTypes)GC.getInfoTypeForString("BUILDING_WALL_OF_STONE")) == 0)
- cast(GC.getInfoTypeForString("SPELL_WALL_OF_STONE"));
- if (canCast(GC.getInfoTypeForString("SPELL_INSPIRATION"),false))
- if (pCity->getNumBuilding((BuildingTypes)GC.getInfoTypeForString("BUILDING_INSPIRATION")) == 0)
- cast(GC.getInfoTypeForString("SPELL_INSPIRATION"));
- if (canCast(GC.getInfoTypeForString("SPELL_HOPE"),false))
- if (pCity->getNumBuilding((BuildingTypes)GC.getInfoTypeForString("BUILDING_HOPE")) == 0)
- cast(GC.getInfoTypeForString("SPELL_HOPE"));
- // Spells to boost the Garrison Units
- if (canCast(GC.getInfoTypeForString("SPELL_DANCE_OF_BLADES"),false))
- cast(GC.getInfoTypeForString("SPELL_DANCE_OF_BLADES"));
- if (canCast(GC.getInfoTypeForString("SPELL_BLUR"),false))
- cast(GC.getInfoTypeForString("SPELL_BLUR"));
- }
- // MNAI - modified so that this function is used by the AI to keep its defensive Adept units spread out to different cities
- bool CvUnitAI::AI_mageMove()
- {
- // short-circuit this function for barbarians unless we're playing with the Raging Barbarians option
- if (isBarbarian() && !GC.getGameINLINE().isOption(GAMEOPTION_RAGING_BARBARIANS))
- {
- return false;
- }
- if( gUnitLogLevel > 2 ) logBBAI(" ...checking MageMove()", getID());
- if (getUnitCombatType() != GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
- {
- AI_setUnitAIType(UNITAI_ATTACK_CITY);
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- return true;
- }
- else if (GC.getUnitInfo(getUnitType()).getTier() > 2)
- {
- if( gUnitLogLevel > 2 ) logBBAI(" ...switching to WarWizard");
- AI_setUnitAIType(UNITAI_WARWIZARD);
- AI_setGroupflag(GROUPFLAG_CONQUEST);
- return true;
- }
- if (plot()->plotCount(PUF_isUnitAIType, UNITAI_MAGE, -1, NO_PLAYER, getTeam()) > 1)
- {
- if( gUnitLogLevel > 2 ) logBBAI(" ...current location is too crowded");
- CvCity* pLoopCity;
- CvCity* pBestCity = NULL;
- int iValue = 0;
- int iBestValue = 0;
- int iLoop;
- for (pLoopCity = GET_PLAYER(getOwner()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwner()).nextCity(&iLoop))
- {
- if (pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_MAGE, -1, NO_PLAYER, getTeam()) == 0)
- {
- int iPathTurns;
- if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
- {
- iValue = (pLoopCity->getPopulation() * 10) / (iPathTurns + 1);
- if (pLoopCity->isCapital())
- {
- iValue *= 2;
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestCity = pLoopCity;
- }
- }
- }
- }
- if (pBestCity != NULL)
- {
- if (!atPlot(pBestCity->plot()))
- {
- if( gUnitLogLevel > 2 ) logBBAI(" ....Mage moving to %S (%d, %d)", pBestCity->getName().GetCString(), pBestCity->plot()->getX_INLINE(), pBestCity->plot()->getY_INLINE());
- getGroup()->pushMission(MISSION_MOVE_TO, pBestCity->plot()->getX_INLINE(), pBestCity->plot()->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
- return true;
- }
- }
- }
- return false;
- }
- void CvUnitAI::AI_terraformerMove() // lfgr 03/2021: Tweaked
- {
- if( gUnitLogLevel >= 3)
- {
- logBBAI(" %S (Unit %d) starting terraformer move\n", getName().GetCString(), getID());
- }
- if (!isChanneler())
- {
- if( gUnitLogLevel >= 3)
- {
- logBBAI(" WARNING! Not a Channeler! Resetting AI for this unit.\n");
- }
- AI_setUnitAIType((UnitAITypes)m_pUnitInfo->getDefaultUnitAIType());
- AI_setGroupflag(GROUPFLAG_NONE);
- return;
- }
- if (GET_PLAYER(getOwnerINLINE()).getDisableSpellcasting() > 0)
- {
- if (AI_retreatToCity())
- {
- if( gUnitLogLevel >= 3)
- {
- logBBAI(" ...retreating to city due to disabled spellcasting\n");
- }
- return;
- }
- }
- if (plot()->isCity() && (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3)))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- CyUnit* pyUnit1 = new CyUnit(this);
- CyArgsList argsList1;
- argsList1.add(gDLL->getPythonIFace()->makePythonObject(pyUnit1)); // pass in unit class
- long lResult=-1;
- gDLL->getPythonIFace()->callFunction(PYGameModule, "AI_MageTurn", argsList1.makeFunctionArgs(), &lResult);
- delete pyUnit1; // python fxn must not hold on to this pointer
- if( gUnitLogLevel >= 3)
- {
- logBBAI(" ...python result of %d\n", lResult);
-
- if (isHasCasted())
- {
- logBBAI(" ...unit has already cast a spell this turn\n");
- }
- }
-
- if (lResult == 0) // Python found nothing to do
- {
- if (GET_TEAM(getTeam()).getAtWarCount(false) > 0) //nothing to do and we're at war
- {
- if (getUnitCombatType() == GC.getInfoTypeForString("UNITCOMBAT_ADEPT"))
- {
- if (isDeBuffer() || isBuffer() || isDirectDamageCaster())
- {
- AI_setUnitAIType(UNITAI_WARWIZARD);
- }
- else
- {
- AI_setUnitAIType(UNITAI_MAGE);
- }
- }
- else
- {
- AI_setUnitAIType((UnitAITypes)m_pUnitInfo->getDefaultUnitAIType());
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- else
- {
- if( !isHasCasted() && !GET_PLAYER(getOwnerINLINE()).isHuman() )
- {
- // Let's try to cast a random spell!
- int iSpell = chooseSpell();
- if (iSpell != NO_SPELL)
- {
- cast(iSpell);
- return;
- }
- }
- if( isHasCasted() )
- {
- // We're done. If we wanted to move somehwere, we'd have done this in python.
- getGroup()->pushMission(MISSION_SKIP); // LFGR_TODO: This does nothing if unit is busy!
- return;
- }
- }
- // Tholal note: terraformers can get stuck in loop, if they've casted, are at a terraformable plot and have movement left
-
- if (isHasCasted())
- {
- getGroup()->pushMission(MISSION_SENTRY); // LFGR_TODO: This does nothing if unit is busy!
- //finishMoves();
- }
-
- return;
- }
- //returns true if the Unit can Summon stuff
- bool CvUnitAI::isSummoner()
- {
- if (!isChanneler())
- {
- return false;
- }
-
- // LFGR_TODO: Use canCastWithCurrentPromotions
- for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
- {
- if (GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType() != NO_UNIT)
- {
- if( canCastWithCurrentPromotions( (SpellTypes) iSpell ) )
- {
- return true;
- }
- }
- }
- return false;
- }
- void CvUnitAI::AI_SummonCast()
- {
- if (isHasCasted())
- {
- return;
- }
- if (!isSummoner())
- {
- return;
- }
- int iBestValue = 0;
- int iBestSpell = NO_SPELL;
- int iTempValue = 0;
- int iValue = 0;
- CvPlot* pLoopPlot;
- for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
- {
- iValue = 0;
- if (GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType() != NO_UNIT)
- {
- if (canCast(iSpell, false))
- {
- bool bPermSummon = GC.getSpellInfo((SpellTypes)iSpell).isPermanentUnitCreate();
- bool bEnemy = false;
- if (!bPermSummon)
- {
- int iMoveRange = GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getMoves() + getExtraSpellMove();
- for (int i = -iMoveRange; i <= iMoveRange; ++i)
- {
- for (int j = -iMoveRange; j <= iMoveRange; ++j)
- {
- pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
- if (NULL != pLoopPlot)
- {
- if (pLoopPlot->isVisibleEnemyUnit(this))
- {
- bEnemy = true;
- }
- }
- }
- }
- }
- if (bEnemy || bPermSummon)
- {
- iTempValue = GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getCombat();
- for (int iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
- {
- iTempValue += GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getDamageTypeCombat(iI);
- }
- iTempValue *= 100;
- iTempValue *= GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitNum();
- iTempValue += GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getCollateralDamage() * GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getCollateralDamageMaxUnits();
- iTempValue *= GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getTier();
- iValue += iTempValue;
- }
- // Tholal AI - Floating Eyes
- if (GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getNumSeeInvisibleTypes() > 0)
- {
- iValue += 100;
- }
- }
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- iBestSpell = iSpell;
- }
- }
- if (iBestSpell != NO_SPELL)
- {
- cast(iBestSpell);
- }
- }
- //returns true if the Unit can Damage stuff
- // lfgr AI 04/2021: Ignores isHasCasted and uses canCastWithCurrentPromotions instead of canCast.
- bool CvUnitAI::isDirectDamageCaster()
- {
- if (!isChanneler())
- {
- return false;
- }
- for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
- {
- if (GC.getSpellInfo((SpellTypes)iSpell).getDamage() > 0)
- {
- if (canCastWithCurrentPromotions((SpellTypes)iSpell))
- {
- return true;
- }
- }
- }
- return false;
- }
- //Make sure iNumSummonSpells is big enough
- //Spell will only be Cast if it can damage Threshold Units
- void CvUnitAI::AI_DirectDamageCast(int Threshold)
- {
- if (isHasCasted())
- {
- return;
- }
- if (!isDirectDamageCaster())
- {
- return;
- }
- int iBestSpell = NO_SPELL;
- int iBestValue = 0;
- int iDmg = 0;
- int iDmgLimit = 0;
- int iRange = 0;
- int iValue = 0;
- CvPlot* pLoopPlot;
- CvUnit* pLoopUnit;
- CLLNode<IDInfo>* pUnitNode;
- for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
- {
- iRange = GC.getSpellInfo((SpellTypes)iSpell).getRange();
- iValue = 0;
- if (GC.getSpellInfo((SpellTypes)iSpell).getDamage() != 0)
- {
- if (canCast(iSpell, false))
- {
- iDmg = GC.getSpellInfo((SpellTypes)iSpell).getDamage();
- iDmgLimit = GC.getSpellInfo((SpellTypes)iSpell).getDamageLimit();
- for (int i = -iRange; i <= iRange; ++i)
- {
- for (int j = -iRange; j <= iRange; ++j)
- {
- pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
- if (NULL != pLoopPlot)
- {
- if (pLoopPlot->getX() != plot()->getX() || pLoopPlot->getY() != plot()->getY())
- {
- pUnitNode = pLoopPlot->headUnitNode();
- while (pUnitNode != NULL)
- {
- pLoopUnit = ::getUnit(pUnitNode->m_data);
- pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
- if (!pLoopUnit->isImmuneToSpell(this, iSpell))
- {
- if (pLoopUnit->isEnemy(getTeam()))
- {
- if (pLoopUnit->getDamage() < iDmgLimit)
- {
- iValue += iDmg * 10;
- }
- }
- if (pLoopUnit->getTeam() == getTeam())
- {
- iValue -= iDmg * 20;
- }
- if (pLoopUnit->getTeam() != getTeam() && pLoopUnit->isEnemy(getTeam()) == false)
- {
- iValue -= 1000;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- iBestSpell = iSpell;
- }
- }
- if (iBestSpell != NO_SPELL)
- {
- cast(iBestSpell);
- }
- }
- //returns true if the Unit can Debuff stuff
- bool CvUnitAI::isDeBuffer()
- {
- if (!isChanneler())
- {
- return false;
- }
-
- for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
- {
- bool bDebuffPromo = false;
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1() != NO_PROMOTION)
- {
- if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1()).getAIWeight() < 0)
- {
- bDebuffPromo = true;
- }
- }
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
- {
- if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2()).getAIWeight() < 0)
- {
- bDebuffPromo = true;
- }
- }
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
- {
- if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3()).getAIWeight() < 0)
- {
- bDebuffPromo = true;
- }
- }
- if (bDebuffPromo)
- {
- // lfgr AI 04/2021: Use canCastWithCurrentPromotions
- if( canCastWithCurrentPromotions( (SpellTypes) iSpell ) )
- {
- return true;
- }
- }
- }
-
- return false;
- }
- void CvUnitAI::AI_DeBuffCast()
- {
- if (this->m_bHasCasted)
- return;
- if (!isDeBuffer())
- return;
- int iBestSpell = NO_SPELL;
- int iBestValue = 0;
- int iValue = 0;
- for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
- {
- iValue = 0;
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1() != NO_PROMOTION)
- {
- if (canCast(iSpell, false))
- {
- iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1()).getAIWeight();
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
- {
- iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2()).getAIWeight();
- }
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
- {
- iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3()).getAIWeight();
- }
- }
- }
- if (iValue < iBestValue)
- {
- iBestValue = iValue;
- iBestSpell = iSpell;
- }
- }
- if (iBestSpell != NO_SPELL)
- {
- cast(iBestSpell);
- }
- }
- bool CvUnitAI::isMovementCaster()
- {
- if (AI_getUnitAIType()==UNITAI_MAGE || AI_getUnitAIType()==UNITAI_TERRAFORMER || AI_getUnitAIType()==UNITAI_FEASTING || AI_getUnitAIType()==UNITAI_INQUISITOR
- || AI_getUnitAIType()==UNITAI_MANA_UPGRADE)
- {
- return false;
- }
- if (AI_getUnitAIType() == UNITAI_HERO && isSummoner())
- {
- return false;
- }
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_BODY1")))
- return true;
- return false;
- }
- void CvUnitAI::AI_MovementCast()
- {
- if (canCast(GC.getInfoTypeForString("SPELL_HASTE"),false))
- cast(GC.getInfoTypeForString("SPELL_HASTE"));
- }
- bool CvUnitAI::isBuffer()
- {
- if (!isChanneler())
- {
- return false;
- }
- for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
- {
- bool bBuffPromo = false;
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1() != NO_PROMOTION)
- {
- if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1()).getAIWeight() > 0)
- {
- bBuffPromo = true;
- }
- }
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
- {
- if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2()).getAIWeight() > 0)
- {
- bBuffPromo = true;
- }
- }
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
- {
- if (GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3()).getAIWeight() > 0)
- {
- bBuffPromo = true;
- }
- }
- if (bBuffPromo)
- {
- // lfgr AI 04/2021: Use canCastWithCurrentPromotions
- if( canCastWithCurrentPromotions( (SpellTypes) iSpell ) )
- {
- return true;
- }
- }
- }
-
- return false;
- }
- // This is run often, so lets keep things simple
- void CvUnitAI::AI_BuffCast()
- {
- if (isHasCasted())
- {
- return;
- }
- if (!isBuffer()) // LFGR_TODO: Seems redundant
- {
- return;
- }
- int iBestSpell = NO_SPELL;
- int iBestValue = 0;
- int iValue = 0;
- for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
- {
- iValue = 0;
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1() != NO_PROMOTION)
- {
- if (canCast(iSpell, false))
- {
- iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1()).getAIWeight();
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
- {
- iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2()).getAIWeight();
- }
- if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
- {
- iValue += GC.getPromotionInfo((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3()).getAIWeight();
- }
- }
- }
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- iBestSpell = iSpell;
- }
- }
- if (iBestSpell != NO_SPELL)
- {
- cast(iBestSpell);
- }
- }
- bool CvUnitAI::isSuicideSummon()
- {
- return m_bSuicideSummon;
- }
- void CvUnitAI::setSuicideSummon(bool newvalue)
- {
- m_bSuicideSummon=newvalue;
- }
- bool CvUnitAI::isPermanentSummon()
- {
- return m_bPermanentSummon;
- }
- void CvUnitAI::setPermanentSummon(bool newvalue)
- {
- m_bPermanentSummon=newvalue;
- }
- // Tholal AI - rewritten to help with Religious victory strats
- void CvUnitAI::AI_InquisitionMove()
- {
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" %S (unit %d) starting InquisitionMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- if (kOwner.AI_isDoVictoryStrategy(AI_VICTORY_RELIGION2) && (AI_getUnitAIType() != UNITAI_HERO))
- {
- int iNeededInquisitors = (GET_PLAYER(getOwnerINLINE()).getNumCities() / 5);
- iNeededInquisitors = std::max(1, iNeededInquisitors);
- if (kOwner.AI_getNumAIUnits(UNITAI_INQUISITOR) < iNeededInquisitors)
- {
- joinGroup(NULL);
- AI_setGroupflag(GROUPFLAG_NONE);
- AI_setUnitAIType(UNITAI_INQUISITOR);
- }
- }
- if (AI_getUnitAIType() != UNITAI_INQUISITOR)
- {
- return;
- }
- CvCity* pLoopCity;
- CvCity* pBestCity = NULL;
- CvPlot* pBestPlot;
- int iValue = 0;
- int iBestValue = 0;
- int iLoop;
- int iStateRel = kOwner.getStateReligion();
- // Inquisitors should work alone
- if (getGroup()->getNumUnits() > 1)
- {
- joinGroup(NULL);
- }
- if (iStateRel != NO_RELIGION)
- {
- if (canCast((SpellTypes)GC.getInfoTypeForString("SPELL_INQUISITION"), false))
- {
- if (plot()->plotCount(PUF_isUnitAIType, UNITAI_INQUISITOR, -1, NO_PLAYER, getTeam()) == 1)
- {
- cast((SpellTypes)GC.getInfoTypeForString("SPELL_INQUISITION"));
- return;
- }
- }
- bool bValidTargetForInquisition = false;
- int iNumHeathenRels = 0;
- for (int iJ = 0; iJ < MAX_PLAYERS; iJ++)
- {
- if (GET_PLAYER((PlayerTypes)iJ).isAlive())
- {
- if ( GET_PLAYER((PlayerTypes)iJ).getStateReligion() == iStateRel)
- {
- for (pLoopCity = GET_PLAYER((PlayerTypes)iJ).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iJ).nextCity(&iLoop))
- {
- if (pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_INQUISITOR, -1, NO_PLAYER, getTeam()) == 0)
- {
- int iPathTurns;
- if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
- {
- bValidTargetForInquisition = false;
- iNumHeathenRels = 0;
- for (int iTarget=0; iTarget < GC.getNumReligionInfos(); iTarget++)
- {
- if (iStateRel != ((ReligionTypes)iTarget) && pLoopCity->isHasReligion((ReligionTypes)iTarget) && (!pLoopCity->isHolyCity((ReligionTypes)iTarget)))
- {
- bValidTargetForInquisition = true;
- iNumHeathenRels++;
- }
- }
- if (bValidTargetForInquisition)
- {
- iValue = pLoopCity->getPopulation() * (iNumHeathenRels * 2);
- if (pLoopCity->isHolyCity((ReligionTypes)iStateRel))
- {
- iValue *= 2;
- }
-
- iValue *= 2;
- iValue /= iPathTurns;
-
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestCity = pLoopCity;
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestCity != NULL)
- {
- pBestPlot = pBestCity->plot();
- logBBAI(" ...targeting %S for Inquisition (plot %d, %d)", pBestCity->getName().GetCString(), pBestCity->getX(), pBestCity->getY());
- if (atPlot(pBestPlot))
- {
- if (canCast((SpellTypes)GC.getInfoTypeForString("SPELL_INQUISITION"), false))
- {
- if (plot()->plotCount(PUF_isUnitAIType, UNITAI_INQUISITOR, -1, NO_PLAYER, getTeam()) == 1)
- {
- logBBAI(" ...Inquisitioning");
- cast((SpellTypes)GC.getInfoTypeForString("SPELL_INQUISITION"));
- return;
- }
- else
- {
- if( gUnitLogLevel > 2 ) logBBAI(" ...too many Inquisitioners at pBestPlot");
- }
- }
- }
- else
- {
- logBBAI(" ...moving to city");
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
- return;
- }
- }
- }
- if (AI_guardCity())
- {
- return;
- }
- if (AI_anyAttack(1, 90))
- {
- return;
- }
- if (AI_retreatToCity())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- //getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_SvartalfarKidnapMove()
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" %S (unit %d) starting SvartfalarKidnapMove (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- int iSpell = GC.getInfoTypeForString("SPELL_KIDNAP");
- if (iSpell != NO_SPELL && canCast(iSpell,false))
- {
- logBBAI(" ..Kidnapping at plot %d, %d!", plot()->getX(), plot()->getY());
- cast(iSpell);
- }
- CvPlot* pBestPlot=NULL;
- int iValue;
- int iBestValue=100;
- for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if(pLoopPlot)
- {
- if (AI_plotValid(pLoopPlot))
- {
- if(pLoopPlot->isCity())
- {
- if(pLoopPlot->getArea()==getArea() && pLoopPlot->getTeam()!=getTeam())
- {
- if (!pLoopPlot->isVisibleEnemyUnit(this))
- {
- CvCity* pLoopCity=pLoopPlot->getPlotCity();
- bool bValidTargetForKidnap=true;
- //too bad this is hardcoded in the Spell
- SpecialistTypes iGreatPriest=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_PRIEST");
- SpecialistTypes iGreatArtist=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_ARTIST");
- SpecialistTypes iGreatMerchant=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_MERCHANT");
- SpecialistTypes iGreatEngineer=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_ENGINEER");
- SpecialistTypes iGreatScientist=(SpecialistTypes)GC.getInfoTypeForString("SPECIALIST_GREAT_SCIENTIST");
- int iCountSpecialists=0;
- if(iGreatPriest!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatPriest);
- if(iGreatArtist!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatArtist);
- if(iGreatMerchant!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatMerchant);
- if(iGreatEngineer!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatEngineer);
- if(iGreatScientist!=-1) iCountSpecialists+=pLoopCity->getFreeSpecialistCount(iGreatScientist);
- if (iCountSpecialists==0)
- {
- bValidTargetForKidnap=false;
- }
- else if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude(pLoopPlot->getOwnerINLINE())>=ATTITUDE_PLEASED)
- {
- if((GET_TEAM(getTeam()).getPower(true)*2)<(GET_TEAM(pLoopPlot->getTeam()).getPower(true)*3))
- {
- //not enough Power to risk declare war
- bValidTargetForKidnap=false;
- }
- }
- else
- {
- if((GET_TEAM(getTeam()).getPower(true)*3)<(GET_TEAM(pLoopPlot->getTeam()).getPower(true)*2))
- {
- //not enough Power to risk declare war
- bValidTargetForKidnap=false;
- }
- }
- if (bValidTargetForKidnap && generatePath(pLoopPlot,0,true,&iValue))
- {
- if(iValue<iBestValue)
- {
- pBestPlot=pLoopPlot;
- iBestValue=iValue;
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot!=NULL)
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- void CvUnitAI::AI_ShadeMove()
- {
- const CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" %S (unit %d) starting Shade move (size %d)", getName().GetCString(), getID(), getGroup()->getNumUnits());
- }
- if (getGroup()->getNumUnits() > 1)
- {
- if( gUnitLogLevel >= 2 )
- {
- logBBAI(" ...degrouping");
- }
- AI_setGroupflag(GROUPFLAG_NONE);
- joinGroup(NULL);
- }
- if (AI_join())
- {
- return;
- }
- if (kOwner.getCapitalCity() != NULL)
- {
- const CvPlot* pPlot = kOwner.getCapitalCity()->plot();
- int iPathTurns;
- if (generatePath(pPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
- {
- logBBAI(" ...moving to capital");
- getGroup()->pushMission(MISSION_MOVE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
- return;
- }
- }
- if (AI_retreatToCity())
- {
- return;
- }
- }
- /*************************************************************************************************/
- /** Skyre Mod **/
- /** BETTER AI (Lanun Pirate Coves) merged Sephi **/
- /** **/
- /*************************************************************************************************/
- bool CvUnitAI::AI_buildPirateCove()
- {
- PROFILE_FUNC();
- SpellTypes eCoveSpell = (SpellTypes)GC.getDefineINT("PIRATE_COVE_SPELL");
- if (eCoveSpell == NO_SPELL)
- {
- return false;
- }
- std::vector<CvPlot*> apGoodPlots;
- int iBestPlotValue = 0;
- for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
- {
- CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
- if (AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->getOwnerINLINE() != getOwnerINLINE() || pLoopPlot->getWorkingCity() == NULL)
- {
- continue;
- }
- if (pLoopPlot->area() != area() && !plot()->isAdjacentToArea(pLoopPlot->area()))
- {
- continue;
- }
- if (pLoopPlot->isVisibleEnemyUnit(this))
- {
- continue;
- }
- if (!pLoopPlot->isPirateCoveValid(getOwnerINLINE()))
- {
- continue;
- }
- if (!atPlot(pLoopPlot) && !canMoveInto(pLoopPlot))
- {
- continue;
- }
- // MNAI (by Red Key) - smarter cove placement
- int idX = std::abs(pLoopPlot->getX() - pLoopPlot->getWorkingCity()->getX());
- int idY = std::abs(pLoopPlot->getY() - pLoopPlot->getWorkingCity()->getY());
- int iPlotValue = std::max(idX,idY) * 10 + std::min(idX,idY);
- iPlotValue -= pLoopPlot->getNumCultureRangeCities(getOwner());
- int iValueModifier = 1;
- for (int iX = -3; iX <= 3; iX++)
- {
- for (int iY = -3; iY <= 3; iY++)
- {
- if(std::abs(iX) != 3 || std::abs(iY) != 3)
- {
- CvPlot* pSearchPlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iX, iY);
- if (pSearchPlot != NULL && pSearchPlot->isPirateCove())
- {
- iValueModifier++;
- }
- }
- }
- }
- iPlotValue *= iValueModifier;
- // End MNAI
- if (iPlotValue > iBestPlotValue)
- {
- apGoodPlots.clear();
- apGoodPlots.push_back(pLoopPlot);
- iBestPlotValue = iPlotValue;
- }
- else if (iPlotValue == iBestPlotValue)
- {
- apGoodPlots.push_back(pLoopPlot);
- }
- }
- }
- CvPlot* pBestPlot = NULL;
- if (!apGoodPlots.empty())
- {
- int iShortestDistance = MAX_INT;
- std::vector<CvPlot*>::iterator it;
- for (it = apGoodPlots.begin(); it != apGoodPlots.end(); ++it)
- {
- int iPathTurns;
- generatePath(*it, 0, true, &iPathTurns);
- if (iPathTurns < iShortestDistance)
- {
- pBestPlot = *it;
- iShortestDistance = iPathTurns;
- }
- }
- }
- if (pBestPlot)
- {
- if (plot() != pBestPlot)
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_BUILD, pBestPlot);
- }
- else
- {
- if (canCast(eCoveSpell, false))
- {
- cast(eCoveSpell);
- }
- //getGroup()->pushMission(MISSION_SKIP);
- }
- return true;
- }
- return false;
- }
- /*************************************************************************************************/
- /** END **/
- /*************************************************************************************************/
- // Tholal AI - New functions
- // Hardcode!
- bool CvUnitAI::isInquisitor()
- {
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_INQUISITOR")))
- return true;
- return false;
- }
- bool CvUnitAI::isChanneler()
- {
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING1")))
- return true;
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING2")))
- return true;
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING3")))
- return true;
- return false;
- }
- // Priest check
- bool CvUnitAI::isDivine()
- {
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_DIVINE")))
- return true;
- return false;
- }
- bool CvUnitAI::isVampire()
- {
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_VAMPIRE")))
- return true;
- return false;
- }
- bool CvUnitAI::isIllusionary()
- {
- int iI;
- for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
- {
- if (isHasPromotion((PromotionTypes)iI))
- {
- if (GC.getPromotionInfo((PromotionTypes)iI).isRace() && GC.getPromotionInfo((PromotionTypes)iI).getCombatHealPercent() == 100)
- {
- return true;
- }
- }
- }
- return false;
- }
- int CvUnitAI::getChannelingLevel()
- {
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING1")))
- return 1;
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING2")))
- return 2;
- if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_CHANNELING3")))
- return 3;
- return 0;
- }
- // End Tholal AI
- // ALN lairguards Start
- void CvUnitAI::AI_lairGuardianMove()
- {
- // only barbarians should use this AI
- if (!isBarbarian())
- {
- joinGroup(NULL);
- AI_setUnitAIType(UNITAI_ATTACK);
- return;
- }
- CvPlot* pPlot = plot();
-
- if (pPlot->isLair(false, isAnimal()))
- {
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
-
- // go to any adjacent lairs
- if (AI_seekLair(1))
- {
- return;
- }
-
- // opportunistic attacks if not on a lair
- if (AI_anyAttack(1, 55))
- {
- return;
- }
-
- // if not on a lair, look for one in the area
- if (AI_seekLair(6))
- {
- return;
- }
-
- if (AI_heal())
- {
- return;
- }
-
- if (AI_patrol())
- {
- return;
- }
- if (AI_safety())
- {
- return;
- }
- getGroup()->pushMission(MISSION_SKIP);
- return;
- }
- // ALN End
- bool CvUnitAI::AI_seekLair(int iRange)
- {
- int iDX;
- int iDY;
- int iPathTurns;
- int iValue = 0;
- int iBestValue = 0;
- int iSearchRange = baseMoves() * iRange;
- CvPlot* pLoopPlot;
- CvPlot* pPlot = plot();
- CvPlot* pBestPlot = NULL;
- // only returns animal dens for animals, non-animal dens for all other barbarians
- for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
- {
- for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (pLoopPlot->isLair(false, isAnimal()) && AI_plotValid(pLoopPlot))
- {
- if (pLoopPlot->getArea() == getArea())
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns > iRange)
- {
- continue;
- }
- int iDefenders = pLoopPlot->plotCount(PUF_isUnitAIType, UNITAI_LAIRGUARDIAN, -1, (PlayerTypes)BARBARIAN_PLAYER);
- iValue = 10000;
- iValue /= (5 + iDefenders);
- iValue /= (1 + iPathTurns);
- if (iValue > iBestValue)
- {
- iBestValue = iValue;
- pBestPlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- if (pBestPlot != NULL)
- {
- if (atPlot(pBestPlot))
- {
- getGroup()->pushMission(MISSION_SKIP);
- }
- else
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL);
- }
- return true;
- }
- return false;
- }
- // A function to help the AI find nearby defensive ground
- // iRange: path range in which to search; bIncludeHealing: include any healing bonuses from the plot when calculating defensive advantage
- bool CvUnitAI::AI_seekDefensiveGround(int iRange, bool bIncludeHealing)
- {
- logBBAI(" %S (unit %d - %S) seeking defensive ground", getName().GetCString(), getID(), GC.getUnitAIInfo(AI_getUnitAIType()).getDescription());
- CvPlot* pBestDefensivePlot = NULL;
- CvPlot* pLoopPlot;
- int iBestPlotValue = (noDefensiveBonus() ? 0 : plot()->defenseModifier(getTeam(), false)) + healRate(plot());
- int iValue = 0;
- int iDX, iDY;
- int iDistance = 6; // ToDo - consider increasing this? With roads, haste, etc, some units could easily move farther than 6 squares
- int iPathTurns;
- for (iDX = -(iDistance); iDX <= iDistance; iDX++)
- {
- for (iDY = -(iDistance); iDY <= iDistance; iDY++)
- {
- pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
- if (pLoopPlot != NULL)
- {
- if (canMoveInto(pLoopPlot))
- {
- if (pLoopPlot->getNumVisibleEnemyDefenders(this) == 0)
- {
- iValue = (noDefensiveBonus() ? 0 : pLoopPlot->defenseModifier(getTeam(), false));
- if (!pLoopPlot->isVisibleToCivTeam())
- {
- iValue += 10;
- }
- if (pLoopPlot->isImpassable()) // being able to move into the plot is checked above
- {
- iValue += 100;
- }
- if (bIncludeHealing)
- {
- iValue += healRate(pLoopPlot);
- }
- if (iValue > iBestPlotValue)
- {
- if (generatePath(pLoopPlot, 0, true, &iPathTurns))
- {
- if (iPathTurns <= iRange)
- {
- iBestPlotValue = iValue;
- pBestDefensivePlot = pLoopPlot;
- }
- }
- }
- }
- }
- }
- }
- }
- if (pBestDefensivePlot != NULL)
- {
- getGroup()->pushMission(MISSION_MOVE_TO, pBestDefensivePlot->getX_INLINE(), pBestDefensivePlot->getY_INLINE());
- 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());
- return true;
- }
- return false;
- }
- // lfgr 03/2021: Helper function, to ensure consistency
- bool isCityAIType( UnitAITypes eUnitAI )
- {
- return (eUnitAI == UNITAI_CITY_DEFENSE) ||
- (eUnitAI == UNITAI_CITY_COUNTER) ||
- (eUnitAI == UNITAI_CITY_SPECIAL) ||
- (eUnitAI == UNITAI_RESERVE);
- }
- // lfgr 04/2021: See CvUnitAI.h
- bool CvUnitAI::AI_readyToMoveOrCast()
- {
- if( canMove() )
- {
- return true;
- }
- // For now, only the terrraformer AI might want to move and then cast.
- if( AI_getUnitAIType() == UNITAI_TERRAFORMER && canCastAnything() )
- {
- return true;
- }
- return false;
- }
|