1 Star 0 Fork 0

liuxuezhan / mylib

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
LC_NewBattle.go 246.34 KB
一键复制 编辑 原始数据 按行查看 历史
liuxuezhan 提交于 2020-12-19 16:15 . 'ok'
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091
package logic
import (
"fmt"
"math"
"math/rand"
"sort"
"strconv"
"strings"
"gitee.com/liuxuezhan/mylib/GameServer/CSV"
"gitee.com/liuxuezhan/mylib/GameServer/cache"
"gitee.com/liuxuezhan/mylib/GameServer/observer"
"gitee.com/liuxuezhan/mylib/GameServer/oss"
proto "gitee.com/liuxuezhan/mylib/Protocol"
"gitee.com/liuxuezhan/mylib/Utils/wlog"
"gitee.com/liuxuezhan/mylib/Utils/wsort"
"gitee.com/liuxuezhan/mylib/common"
"gitee.com/liuxuezhan/mylib/wtime"
)
//行为的目标类型,每次修改需要和客户端同步
const (
targetUnUse uint32 = 0
targetMainCity uint32 = 1 //主城
targetMine uint32 = 3 //矿
targetMonster uint32 = 4 //单人boss怪
targetMutiMonster uint32 = 5 //多人怪
targetCity uint32 = 6 //现在没用
targetBestationed uint32 = 7 //营地
targetRayolCity uint32 = 8 //大小奇迹
targetUndergroundPalace uint32 = 9 //星际之门
targetMineGem uint32 = 10 /// 钻石矿,埋点时有特殊需求
targetWarCity uint32 = 11 //城市争霸
targetAirShip uint32 = 12 //推图(飞艇)
targetBlockUnlock uint32 = 13 //地块解锁
targetMonsterEx uint32 = 14 //单人小怪
targetSummonMutiMonster uint32 = 15 //多人召唤野怪
targetLeagueCenter uint32 = 16 //联盟堡垒
targetCashhouse uint32 = 17 //联盟仓库
targetMultiCash uint32 = 18 //联盟超级矿
)
const (
actionBase_None uint32 = 0
actionBase_Monster uint32 = 1 //怪物(都是防守方)
actionBase_Atk uint32 = 2 //攻击方
actionBase_Def uint32 = 3 //防守方
)
const (
fightRlt_None uint32 = 0 //目标不存在
fightRlt_Hit uint32 = 1 //命中
fightRlt_Miss uint32 = 2 //闪避
)
const (
battleRlt_Error uint32 = 0 //逻辑错误
battleRlt_AtkEmpty uint32 = 1 //进攻方兵力耗尽
battleRlt_DefEmpty uint32 = 2 //防守方兵力耗尽
battleRlt_AllEmpty uint32 = 3 //双方兵力耗尽
battleRlt_Continue uint32 = 4 //战斗继续
battleRlt_Over uint32 = 5 //战斗结束
)
//英雄战斗信息
type stHeroBattleInfo struct {
heroID uint32
mainType uint32 //主属性类型 HeroBranchType
level uint32
star uint32
rank uint32
skillList []*proto.ST_HeroSkill_PB //存放技能ID
branceValue []uint32 //进入战斗时刻的3属性,顺序存放,不包括带兵量
fightBuff map[uint32]*stFightBuff //战斗buff
skillCDList map[uint32]uint32 //技能CD
specialBuff []*stFightBuff //特殊被动buff
}
//军团
type stCorps struct {
unitType proto.UnitBattleType
curUnits []*proto.ST_Unit_PB //当前战斗单位
startUnits []*proto.ST_Unit_PB //战斗开始时的战斗单位
summonUnits []*proto.ST_Unit_PB //找召唤的影子部队
fightBuff map[uint32]*stFightBuff //战斗buff
specialBuff []*stFightBuff //特殊被动buff
attributeMap map[uint32]uint64 //军团攻防属性等
unitHp map[uint32]uint64 //每个等级的战斗单位的衰减总生命
unitPower map[uint32]uint64 //每个战斗单位的战斗力
curAllUnitNum uint32 //当前战斗单位数量
}
//军团阵型
type stFormation struct {
id uint32 //阵型ID
unitData map[proto.CorpsPos][]*stCorps //最大4个,前中后天上顺序存放,每个5种等级
trapsData map[proto.UnitBattleType][]*stCorps //4种陷阱,每个5种等级
}
//城墙
type stWall struct {
wallLevel uint32 //城墙等级
startWallHp uint64 //城墙战斗开始时的血量
curWallHp uint64 //城墙当前血量
wallDef uint32 //城墙防御
fightBuff map[uint32]*stFightBuff //战斗buff
}
//战斗行为基本数据
type stBattleActionBaseData struct {
actionBaseType uint32 //0 怪物 1攻击方 2防守方
userData *cache.Info //玩家信息 (与怪物组ID互斥)
monsterGroupID int64 //怪物组ID (与玩家信息互斥)worldMonsterConfig
heroList []*stHeroBattleInfo //英雄信息
formation *stFormation //军团阵型信息,记录了总的详细兵力
globalAttribute map[uint64]uint64 //全局加成拷贝信息(例如:被动技能,英雄对士兵加成)
wall *stWall //城墙信息,攻打玩家主城时防守方才有
roundBaseInfo *proto.ST_RoundBaseInfo_PB //记录回合内的战斗信息
monsterAtk bool //怪物攻城
}
//以兵种类型为单位记录军团信息
type stCorpsMap struct {
unitList map[proto.UnitBattleType][]*stCorps //4种兵种
trapList map[proto.UnitBattleType][]*stCorps //4种陷阱
}
//战斗单位克制效果
type stRestrainParm struct {
damageParm map[uint32]uint32 //k:克制兵种 v:克制效果(CSV表配置)
}
//战斗通用参数
type stCommonBattleParm struct {
maxbattleRound uint32 //战斗最大回合
unitRestrainParm map[int64]*stRestrainParm //战斗单位克制效果 百分比
corpAtkOrder map[int64]int64 //战斗单位指定攻击目标,目前只有陷阱生效
hitParm []uint32 //命中公式参数 :A,B,C,命中下限 万分比
baoJiParm []uint32 //暴击公式参数 :A,B,C,暴击上限 万分比
battleDamageParm []uint32 //战斗伤害参数 :K,M,P,Q,Y 万分比
critDamageParm uint32 //暴击额外伤害,百分比
attriDamageLimit []uint32 //伤害加减范围 :下限,上限 万分比
skillSpecialParm []uint32 //特殊行为系数里的参数: P,Q
atkParm []uint32 //军团攻击公式参数 M幂
defParm []uint32 //军团防御公式参数 M幂
trapLossParm uint32 //陷阱自毁系数
hpParm []uint32 //军团及其陷阱的血量衰减系数,t|r
}
var CommonBattleParm *stCommonBattleParm
//战斗buff效果
type stFightBuff struct {
csvIndex int32
effectType uint32 //效果类型 1:增益 2:负面 3:伤害 4:持续伤害 5:特殊效果
effectValue uint64 //具体数值,在释放的一瞬间就计算好了的,除了dot、hot类效果,其余存的都是万分比的
effectRound uint32 //持续回合
triggerTime uint32 //触发时机 1立即
heroID uint32 //buff释放的英雄ID
orgiSkillID int64 //效果所属技能
params []uint32 // 效果参数
}
//兵力占比
type stUserUnitInfo struct {
isBigBrother bool //带队玩家
charUID uint64 //玩家UID
unitMap map[proto.UnitBattleType][]*stUnitInfo //按战斗等级记录的兵力数据
totalPower int64 //总战力
corpRatioMap map[proto.UnitBattleType]float32 //记录玩家各军团占【集结总兵团】的战力比
unitRatioMap map[uint32]float32 //记录玩家各等级兵种在同等级下的战力比(每个兵种占【集结总兵团】的百分比,区分等级)
}
type stUnitInfo struct {
unit *proto.ST_Unit_PB
power int64
powerRatio float32 //在同类型军团中的战力比(因为击杀数量是按军团算的,单个兵种的击杀数量根据它与军团的战力比来计算)
}
func getBigMiracleUnitCount(cityData *cache.WorldDataEntry) uint64 {
if nil == cityData {
return 0
}
return uint64(len(cityData.GetGActionList()))
}
/**
@brief v4转化成道具的数据结构
*/
func createItemByVector4(str string) []*proto.ST_ItemEntry_PB {
ret := make([]*proto.ST_ItemEntry_PB, 0)
if str == "" {
return ret
}
for _, v := range common.ParseStringToVector4(str) {
if v.GetX() == int32(proto.VectorType_VT_ITEM) {
itemenry := &proto.ST_ItemEntry_PB{
ItemId: proto.SetUint32(uint32(v.GetY())),
ItemNum: proto.SetUint32(uint32(v.GetW())),
}
ret = append(ret, itemenry)
} else if v.GetX() == int32(proto.VectorType_VT_DROP) {
for i := int32(0); i < v.GetW(); i++ {
ret = append(ret, CSV.GetDropItem(v.GetY())...)
}
}
}
return ret
}
/**
@brief 把数据组合成Appenddata数据 key|value
*/
func encodeActionAppendData(str, key string, value string) string {
var retstr string
var find bool = false
tmpstr := make([]string, 0)
tmpstrList := strings.Split(str, "|")
for _, v := range tmpstrList {
substrList := strings.Split(v, "=")
if len(substrList) < 2 {
continue
}
if substrList[0] == key {
find = true
substrList[1] = value
}
tmpstr = append(tmpstr, strings.Join(substrList, "="))
}
if find {
retstr = strings.Join(tmpstr, "|")
} else {
tmp := make([]string, 0)
tmp = append(tmp, key)
tmp = append(tmp, value)
tmpstr = append(tmpstr, strings.Join(tmp, "="))
retstr = strings.Join(tmpstr, "|")
}
return retstr
}
func splitKV(str, sep string) (string, string) {
strList := strings.Split(str, sep)
if len(strList) < 2 {
return "", ""
}
return strList[0], strings.Join(strList[1:], "=")
}
/**
@brief 根据指定字段解析Appenddata数据
*/
func decodeActionAppendData(str, key string) string {
tmpstrList := strings.Split(str, "|")
var retstr string
for _, v := range tmpstrList {
k, v1 := splitKV(v, "=")
switch k {
case key:
retstr = v1
}
}
return retstr
}
func DecodeActionAppendDataEx(str, key string) string {
return decodeActionAppendData(str, key)
}
/**
@brief 解析Appenddata里的单位或者资源信息
*/
func decodeAttackAppendData(str string) (*proto.ST_UnitAsset_PB, *proto.ST_CashAsset_PB) {
retUnit := &proto.ST_UnitAsset_PB{}
retResource := &proto.ST_CashAsset_PB{}
tmpstrList := strings.Split(str, "|")
for _, v := range tmpstrList {
k, v1 := splitKV(v, "=")
switch k {
case "units":
proto.Unmarshal([]byte(v1), retUnit)
case "resource":
proto.Unmarshal([]byte(v1), retResource)
default:
continue
}
}
return retUnit, retResource
}
/**
@brief 指定字段,然后删除Appenddata里对应的数据
*/
func deleteActionAppendData(str, key string) string {
var retStr = ""
tmpstrList := strings.Split(str, "|")
for _, v := range tmpstrList {
k, v1 := splitKV(v, "=")
if k == key {
continue
}
retStr = encodeActionAppendData(retStr, k, v1)
}
return retStr
}
/**
@brief 扣除战斗单位(ST_UnitAsset_PB)
*/
func reduceUnitsAsset(units *proto.ST_UnitAsset_PB, dieNum uint64) *proto.ST_UnitAsset_PB {
var (
dieUnit = make(map[uint32]uint64)
)
loop:
for i := int64(1); i <= 4; i++ {
for _, v := range units.GetUnits() {
unitConfig := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitConfig == nil {
continue
}
if unitConfig.UnitPosType != i {
continue
}
if dieNum > v.GetUnitnum() {
dieUnit[v.GetUnitid()] = v.GetUnitnum()
dieNum -= v.GetUnitnum()
} else {
dieUnit[v.GetUnitid()] = dieNum
dieNum = 0
}
if dieNum == 0 {
break loop
}
}
}
for _, v := range units.GetUnits() {
if v1, ok := dieUnit[v.GetUnitid()]; ok {
v.Unitnum = proto.SetUint64(v.GetUnitnum() - v1)
}
}
return createUnitAssetByMap(dieUnit)
}
/**
@brief 扣除战斗单位(stCorps)
*/
func reduceCorpsUnits(outTargetCorps, inSrcCorps *stCorps) {
if nil == outTargetCorps || nil == inSrcCorps {
return
}
if outTargetCorps.unitType != inSrcCorps.unitType {
return
}
for _, src := range inSrcCorps.curUnits {
for _, target := range outTargetCorps.curUnits {
if src.GetUnitid() == target.GetUnitid() {
if src.GetUnitnum() > target.GetUnitnum() {
target.Unitnum = proto.SetUint64(0)
} else {
target.Unitnum = proto.SetUint64(target.GetUnitnum() - src.GetUnitnum())
}
break
}
}
}
}
/**
@brief 根据数量直接扣除战斗单位(stCorps)
*/
func reduceCorpUnitsByNum(outCorps *stCorps, lostValue uint64) []*proto.ST_Unit_PB {
//扣除顺序从低级兵种到高级兵种
//理论上curUnits是从低到高排序
lostUnitList := make([]*proto.ST_Unit_PB, 0)
if nil == outCorps || uint64(0) == lostValue {
return lostUnitList
}
unitsLen := len(outCorps.curUnits)
if 0 == unitsLen {
return lostUnitList
}
for tmpLen := 0; tmpLen < unitsLen; tmpLen++ {
v := outCorps.curUnits[tmpLen]
if uint64(0) == v.GetUnitnum() {
continue
}
curUnitValue := v.GetUnitnum()
if curUnitValue > lostValue {
curUnitValue -= lostValue
lostValue = 0
} else {
lostValue -= curUnitValue
curUnitValue = 0
}
//当前单位剩余数量
oldNum := v.GetUnitnum()
v.Unitnum = proto.SetUint64(curUnitValue)
//记录损失的数量
tmp := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitid()),
Unitnum: proto.SetUint64(oldNum - curUnitValue),
}
lostUnitList = append(lostUnitList, tmp)
outCorps.curAllUnitNum -= uint32(tmp.GetUnitnum())
if lostValue <= uint64(0) {
return lostUnitList
}
}
return lostUnitList
}
/**
@brief 处理部队护盾
*/
func processShield(buffList map[uint32]*stFightBuff, lostHp float64) float64 {
for _, v := range buffList {
if v.csvIndex == int32(proto.FightBuffAttibute_DamageShield) && v.effectValue > 0 {
if float64(v.effectValue) >= lostHp {
v.effectValue -= uint64(lostHp)
lostHp = 0
} else {
lostHp -= float64(v.effectValue)
v.effectValue = 0
}
if lostHp <= 0 {
break
}
}
}
return lostHp
}
/**
@brief 根据衰减总血量来扣除军团的战斗单位
*/
func reduceCorpUnitsByHp(outCorps *stCorps, lostHp float64) ([]*proto.ST_Unit_PB, float64) {
//此函数主于陷阱及其军团攻击时调用
/*
理论上curUnits是从低到高排序
扣除顺序从低级兵种到高级兵种
【最终伤害】是否≥Tn衰减总生命
是:扣除Tn兵团总人数,计算【扣除Tn后伤害】= 【最终伤害】-Tn衰减总生命
否:扣除Tn兵团人数=【最终伤害】÷ Tn平均生命 ; 结束扣除人数流程
*/
lostUnitList := make([]*proto.ST_Unit_PB, 0)
realLossHp := float64(0) //实际已扣除的血量
if nil == outCorps {
return lostUnitList, realLossHp
}
unitsLen := len(outCorps.curUnits)
if 0 == unitsLen {
return lostUnitList, realLossHp
}
// 处理护盾buff逻辑
lostHp = processShield(outCorps.fightBuff, lostHp)
for tmpLen := 0; tmpLen < unitsLen; tmpLen++ {
unitInfo := outCorps.curUnits[tmpLen]
corpTotalNum := unitInfo.GetUnitnum() //当前等级的兵力
if uint64(0) == corpTotalNum {
continue
}
//计算损失
unitTotalHp := float64(outCorps.unitHp[unitInfo.GetUnitid()]) //当前等级的衰竭总生命
unitAvgHp := unitTotalHp / float64(corpTotalNum) //当前等级的平局衰竭生命
lostNum := uint64(0)
if unitTotalHp > lostHp {
lostNum = uint64(math.Ceil(lostHp / unitAvgHp))
if lostNum > corpTotalNum {
lostNum = corpTotalNum
}
realLossHp += lostHp
lostHp = float64(0)
} else {
realLossHp += unitTotalHp
lostHp -= unitTotalHp
lostNum = corpTotalNum
}
unitInfo.Unitnum = proto.SetUint64(corpTotalNum - lostNum)
//记录损失的数量
tmp := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(unitInfo.GetUnitid()),
Unitnum: proto.SetUint64(lostNum),
}
lostUnitList = append(lostUnitList, tmp)
outCorps.curAllUnitNum -= uint32(tmp.GetUnitnum())
if lostHp <= float64(0) {
return lostUnitList, realLossHp
}
}
return lostUnitList, realLossHp
}
/**
@brief 根据数量直接添加战斗单位(stCorps)
*/
func addCorpsUnits(outTargetCorps, inSrcCorps *stCorps) {
if nil == outTargetCorps || nil == inSrcCorps {
return
}
//先加数量
for _, src := range inSrcCorps.curUnits {
for _, target := range outTargetCorps.curUnits {
if src.GetUnitid() == target.GetUnitid() {
target.Unitnum = proto.SetUint64(src.GetUnitnum() + target.GetUnitnum())
break
}
}
}
//当前数量不允许超过战斗开始时的数量
for _, cur := range inSrcCorps.curUnits {
for _, start := range outTargetCorps.startUnits {
if cur.GetUnitid() == start.GetUnitid() {
if cur.GetUnitnum() > start.GetUnitnum() {
cur.Unitnum = proto.SetUint64(start.GetUnitnum())
}
break
}
}
}
}
func addUnits(target, scr []*proto.ST_Unit_PB) []*proto.ST_Unit_PB {
if nil == target || nil == scr {
return target
}
for _, scrv := range scr {
isFind := false
for _, tarv := range target {
if tarv.GetUnitid() == scrv.GetUnitid() {
tarv.Unitnum = proto.SetUint64(tarv.GetUnitnum() + scrv.GetUnitnum())
isFind = true
break
}
}
if false == isFind {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(scrv.GetUnitid()),
Unitnum: proto.SetUint64(scrv.GetUnitnum()),
}
target = append(target, unit)
}
}
return target
}
/**
@brief 增加军团的战斗单位数量
*/
func addCorpUnitsByNum(outCorps *stCorps, AddValue uint64) ([]*proto.ST_Unit_PB, uint64) {
//恢复顺序从高级兵种到低级兵种
//理论上curUnits是从低到高排序
addUnitList := make([]*proto.ST_Unit_PB, 0)
totalAddUnitNum := uint64(0)
tmpLen := len(outCorps.curUnits)
if nil == outCorps || uint64(0) == AddValue || 0 == tmpLen {
return addUnitList, totalAddUnitNum
}
tmpLen -= 1
for ; tmpLen >= 0; tmpLen-- {
v := outCorps.curUnits[tmpLen]
curNum := v.GetUnitnum()
maxNum := outCorps.startUnits[tmpLen].GetUnitnum()
if uint64(0) == curNum {
continue
}
lostNum := maxNum - curNum //已损失的当前等级的兵种数量
realAddNum := uint64(0)
if AddValue > lostNum {
realAddNum = lostNum
} else {
realAddNum = AddValue
}
AddValue -= realAddNum
oldNum := v.GetUnitnum()
v.Unitnum = proto.SetUint64(v.GetUnitnum() + realAddNum)
if v.GetUnitnum() > maxNum {
v.Unitnum = proto.SetUint64(maxNum)
}
//记录增加的的数量
tmp := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitid()),
Unitnum: proto.SetUint64(v.GetUnitnum() - oldNum),
}
addUnitList = append(addUnitList, tmp)
totalAddUnitNum += tmp.GetUnitnum()
outCorps.curAllUnitNum += uint32(v.GetUnitnum() - oldNum)
if AddValue <= uint64(0) {
return addUnitList, totalAddUnitNum
}
}
return addUnitList, totalAddUnitNum
}
/**
@brief 根据血量来增加军团的战斗单位(暂时没用2019_3_1)
*/
func addCorpUnitsByHp(outCorps *stCorps, AddHpValue float64) ([]*proto.ST_Unit_PB, uint64) {
//恢复顺序从高级兵种到低级兵种
//理论上curUnits是从低到高排序
addUnitList := make([]*proto.ST_Unit_PB, 0)
totalAddUnitNum := uint64(0)
if nil == outCorps || float64(0) == AddHpValue {
return addUnitList, totalAddUnitNum
}
tmpLen := len(outCorps.curUnits)
if 0 == tmpLen {
return addUnitList, totalAddUnitNum
}
tmpLen -= 1
for ; tmpLen >= 0; tmpLen-- {
v := outCorps.curUnits[tmpLen]
curNum := v.GetUnitnum()
maxNum := outCorps.startUnits[tmpLen].GetUnitnum()
if uint64(0) == curNum {
continue
}
if k, ok := outCorps.unitHp[v.GetUnitid()]; ok {
unitAvgHp := float64(k) / float64(curNum)
if unitAvgHp == 0 {
continue
}
lostHp := float64(maxNum-curNum) * unitAvgHp //已损失的总血量
realAddHp := float64(0)
if AddHpValue > lostHp {
realAddHp = lostHp
} else {
realAddHp = AddHpValue
}
AddHpValue -= realAddHp
oldNum := v.GetUnitnum()
v.Unitnum = proto.SetUint64(v.GetUnitnum() + uint64(realAddHp/unitAvgHp))
if v.GetUnitnum() > maxNum {
v.Unitnum = proto.SetUint64(maxNum)
}
//记录增加的的数量
tmp := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitid()),
Unitnum: proto.SetUint64(v.GetUnitnum() - oldNum),
}
addUnitList = append(addUnitList, tmp)
totalAddUnitNum += tmp.GetUnitnum()
outCorps.curAllUnitNum += uint32(v.GetUnitnum() - oldNum)
}
if AddHpValue <= float64(0) {
return addUnitList, totalAddUnitNum
}
}
return addUnitList, totalAddUnitNum
}
/**
@brief 以军团为单位,统计其中的战斗单位数量
*/
func countUnitsNumByCorps(corps *stCorps) {
total := uint64(0)
if nil == corps {
return
}
for _, v := range corps.curUnits {
total += v.GetUnitnum()
}
corps.curAllUnitNum = uint32(total)
}
func countUnitsNumFromList(unitList []*proto.ST_Unit_PB) uint64 {
total := uint64(0)
if nil == unitList || 0 == len(unitList) {
return total
}
for _, v := range unitList {
total += v.GetUnitnum()
}
return total
}
func countUnitsNum(unitAsset *proto.ST_UnitAsset_PB) uint32 {
total := uint64(0)
if nil == unitAsset {
return uint32(total)
}
for _, v := range unitAsset.Units {
total += v.GetUnitnum()
}
return uint32(total)
}
/**
@brief 从map转成PB结构
*/
func createUnitAssetByMap(in map[uint32]uint64) *proto.ST_UnitAsset_PB {
ret := &proto.ST_UnitAsset_PB{}
for k, v := range in {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k),
Unitnum: proto.SetUint64(v),
}
ret.Units = append(ret.Units, unit)
}
return ret
}
/**
@brief 从PB结构转成Map
*/
func genUnitInfoByAsset(in *proto.ST_UnitAsset_PB) map[uint32]uint64 {
ret := make(map[uint32]uint64)
for _, v := range in.GetUnits() {
if v1, ok := ret[v.GetUnitid()]; ok {
ret[v.GetUnitid()] = v1 + v.GetUnitnum()
} else {
ret[v.GetUnitid()] = v.GetUnitnum()
}
}
return ret
}
/**
@brief 从PB结构转成Map
*/
func recordBattleAllAttri(baseData *stBattleActionBaseData) *proto.ST_AttributeList_PB {
allBattleAttri := &proto.ST_AttributeList_PB{
List: make([]*proto.ST_Attribute_PB, 0),
}
if nil == baseData || nil == baseData.userData {
return allBattleAttri
}
for _, v := range proto.AtttibuteType_value {
tmpattr := &proto.ST_Attribute_PB{
Type: proto.SetUint32(uint32(v)),
Value: proto.SetUint32(baseData.userData.GetAttributeByType(proto.AtttibuteType(v))),
}
allBattleAttri.List = append(allBattleAttri.List, tmpattr)
}
return allBattleAttri
}
/**
@brief 获取在大奇迹里的第一个玩家
*/
func getBigMiracleGarrisonUser(cityData *cache.WorldDataEntry) *cache.Info {
if nil == cityData {
return nil
}
if len(cityData.GetWorldData().GetSimpleEntry().GetGActionList()) <= 0 {
return nil
}
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(cityData.GetWorldData().GetSimpleEntry().GetGActionList()[0])
if actionData == nil || actionData.Actiondata == nil {
return nil
}
return cache.GetCharinfo(actionData.Actiondata.GetUid())
}
/**
@brief 援助大奇迹, 城市
*/
func garrisonToBigMiracle(actionData *cache.GlobalActionEntry, cityData *cache.WorldDataEntry) bool {
if nil == cityData {
return false
}
if ownerIncludeMe(cityData, actionData.Actiondata.GetUid()) {
return false
}
if !checkCanGarrisonBigMiracle(actionData.Actiondata.GetUnits(), cityData) {
return false
}
userData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if nil == userData {
return false
}
tmpUser := getBigMiracleGarrisonUser(cityData)
if nil != tmpUser {
if tmpUser.GetLeagueID() != userData.GetLeagueID() {
return false
}
}
actionIds := cityData.CopyGActionList()
if len(actionIds) <= 0 {
details := make([]uint64, 0)
fuction := userData.GetBuildingFuctionByConfigType(int64(proto.BuildingType_BT_COMMAND))
capability := common.StringToUint64(fuction["capability"])
capability = countAdditional(capability, userData, proto.AtttibuteType_MaxAggregation) // 1003;//联盟集结上限(百分比)
var totalCount = countUnitNum(actionData.Actiondata.GetUnits())
details = append(details, capability)
details = append(details, totalCount)
actionData.Actiondata.Details = details
} else {
tmpActionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionIds[0])
if len(tmpActionData.Actiondata.Details) >= 2 {
if tmpActionData.Actiondata.Details[0] < tmpActionData.Actiondata.Details[1]+countUnitNum(actionData.Actiondata.GetUnits()) {
return false
}
tmpActionData.Actiondata.Details[1] += countUnitNum(actionData.Actiondata.GetUnits())
tmpActionData.Dirty()
} else {
return false
}
}
if getWorldDataTargetType(cityData) == targetRayolCity {
observer.ObserverSingleton.AsyncNotify(observer.AddMiracleWarRecordEvent, []interface{}{int32(2), userData, tmpUser})
}
actionData.UpdateStage(wtime.GetNow(), 5, uint32(proto.MapStageType_MST_WORKING)) //集结每支部队都处理,空城也需要
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_JOINMASS) {
// cache.Instance_GlobalAssetGlobalAction.DeleteGlobalAction(actionData.Actiondata.GetActionid())
// userData.RemoveGlobalActionID(actionData.Actiondata.GetActionid())
// newActionId := cache.Instance_GlobalAssetGlobalAction.AllocGlobalActionId()
// actionData.Actiondata.Actionid = proto.SetUint64(newActionId) //先赋值
actionData.SetActionType(uint32(proto.ActionType_AT_WORLDMAP_GARRISON))
deleteRadar(actionData.Actiondata)
// cache.Instance_GlobalAssetGlobalAction.AddCopyGlobalAction(newActionId, actionData)
// userData.AddGlobalActionID(newActionId)
}
cityData.BindGlobalActionId(actionData.Actiondata.GetActionid())
wlog.Error("garrisonToBigMiracle bind act:", actionData.Actiondata.GetActionid(), actionData.Actiondata.GetTotaltime())
remainTime := countMarchTime(actionData.Actiondata.GetUid(), actionData.Actiondata.GetStartTileID(),
actionData.Actiondata.GetEndTileID(), actionData.Actiondata.GetWorldDataID(), actionData.Actiondata.GetActiontype(),
actionData.Actiondata.GetHeroIDList(), actionData.Actiondata.GetUnits(), actionData.Actiondata.GetCrossSpecialTile())
actionData.Actiondata.Totaltime = proto.SetUint64(remainTime)
actionData.Dirty()
cityData.Dirty()
return true
}
func GarrisonToLeagueCenter(actionData *cache.GlobalActionEntry, cityData *cache.WorldDataEntry) bool {
if nil == cityData {
return false
}
userData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if nil == userData {
return false
}
actionIds := cityData.CopyGActionList()
if len(actionIds) <= 0 {
details := make([]uint64, 0)
wdataAsset := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(actionData.Actiondata.GetEndTileID())
var totalCount = countUnitNum(actionData.Actiondata.GetUnits())
details = append(details, wdataAsset.GetWorldData().DetailEntry.Detail_City.GetGarrisonCapalibity())
details = append(details, totalCount)
actionData.Actiondata.Details = details
} else {
tmpActionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionIds[0])
if len(tmpActionData.Actiondata.Details) >= 2 {
if tmpActionData.Actiondata.Details[0] < tmpActionData.Actiondata.Details[1]+countUnitNum(actionData.Actiondata.GetUnits()) {
return false
}
tmpActionData.Actiondata.Details[1] += countUnitNum(actionData.Actiondata.GetUnits())
tmpActionData.Dirty()
} else {
return false
}
}
actionData.UpdateStage(wtime.GetNow(), 5, uint32(proto.MapStageType_MST_WORKING)) //集结每支部队都处理,空城也需要
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_GARRISON) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_JOINMASS) {
actionData.SetActionType(uint32(proto.ActionType_AT_WORLDMAP_GARRISON))
deleteRadar(actionData.Actiondata)
}
cityData.BindGlobalActionId(actionData.Actiondata.GetActionid())
wlog.Error("garrisonToBigMiracle bind act:", actionData.Actiondata.GetActionid(), actionData.Actiondata.GetTotaltime())
remainTime := countMarchTime(actionData.Actiondata.GetUid(), actionData.Actiondata.GetStartTileID(),
actionData.Actiondata.GetEndTileID(), actionData.Actiondata.GetWorldDataID(), actionData.Actiondata.GetActiontype(),
actionData.Actiondata.GetHeroIDList(), actionData.Actiondata.GetUnits(), actionData.Actiondata.GetCrossSpecialTile())
actionData.Actiondata.Totaltime = proto.SetUint64(remainTime)
actionData.Dirty()
cityData.Dirty()
if cityData.GetWorldData().SimpleEntry.GetLid() != userData.GetLeagueID() {
x, y, _ := common.ConvertIdToCoordinate(cityData.GetWorldDataTileID())
conf := cityData.GetWorldEntryConfig()
if conf != nil {
sendLanguageIDMailToMembers(userData.GetLeagueID(), uint32(proto.MailType_MT_SYSTEM),
common.CreateTips(76300),
common.CreateTips(76032, userData.GetUserName(),
cache.Instance_GlobalAssetLeague.GetLeagueName(cityData.GetWorldData().SimpleEntry.GetLid()), common.Int64ToString(conf.EntryLevel),
common.Int32ToString(cityData.GetWorldDataTileID()), common.Int32ToString(x), common.Int32ToString(y)))
sendLanguageIDMailToMembers(cityData.GetWorldData().SimpleEntry.GetLid(), uint32(proto.MailType_MT_SYSTEM),
common.CreateTips(76297),
common.CreateTips(76033, cache.Instance_GlobalAssetLeague.GetLeagueName(userData.GetLeagueID()), common.Int64ToString(conf.EntryLevel),
common.Int32ToString(cityData.GetWorldDataTileID()), common.Int32ToString(x), common.Int32ToString(y)))
}
}
return true
}
/**
@brief 把行为转成援助
*/
func convertActionToGarrison(actionData *cache.GlobalActionEntry, cityData *cache.WorldDataEntry) {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) {
if !garrisonToBigMiracle(actionData, cityData) {
actionData.UpdateStage(wtime.GetNow(), actionData.Actiondata.GetTotaltime(), uint32(proto.MapStageType_MST_BACK))
}
} else if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
ret := garrisonToBigMiracle(actionData, cityData)
for _, v := range actionData.Actiondata.GetChildrenID() {
actionEntry := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if nil != actionEntry {
actionEntry.Actiondata.EndTileID = proto.SetInt32(actionData.Actiondata.GetEndTileID())
actionEntry.Actiondata.WorldDataID = proto.SetUint64(actionData.Actiondata.GetWorldDataID())
actionEntry.Actiondata.EndScope = actionData.Actiondata.GetEndScope()
if !garrisonToBigMiracle(actionEntry, cityData) {
actionData.UpdateStage(wtime.GetNow(), actionData.Actiondata.GetTotaltime(), uint32(proto.MapStageType_MST_BACK))
}
}
}
actionData.Actiondata.ChildrenID = make([]uint64, 0)
actionData.Dirty()
if !ret {
actionData.UpdateStage(wtime.GetNow(), actionData.Actiondata.GetTotaltime(), uint32(proto.MapStageType_MST_BACK))
}
}
}
/**
@brief 设置阵型
*/
func setFormation(formationID uint32, corpsMap *stCorpsMap) (bool, *stFormation) {
if nil == corpsMap {
return false, nil
}
formation := &stFormation{
id: formationID,
unitData: make(map[proto.CorpsPos][]*stCorps),
}
//默认步兵坦克火炮飞机
if 0 == formationID {
if v, ok := corpsMap.unitList[proto.UnitBattleType_UBT_NOMAL_BUBING]; ok {
formation.unitData[proto.CorpsPos_CP_FRONT] = v
}
if v, ok := corpsMap.unitList[proto.UnitBattleType_UBT_NOMAL_TANK]; ok {
formation.unitData[proto.CorpsPos_CP_MIDDLE] = v
}
if v, ok := corpsMap.unitList[proto.UnitBattleType_UBT_NOMAL_HUOPAO]; ok {
formation.unitData[proto.CorpsPos_CP_Behind] = v
}
if v, ok := corpsMap.unitList[proto.UnitBattleType_UBT_NOMAL_FEIJI]; ok {
formation.unitData[proto.CorpsPos_CP_SKY] = v
}
}
//陷阱
formation.trapsData = corpsMap.trapList
return true, formation
}
/**
@brief ST_UnitAsset_PB转化成map
*/
func unitAssetToMap(in *proto.ST_UnitAsset_PB) map[uint32]uint64 {
ret := make(map[uint32]uint64)
for _, v := range in.GetUnits() {
if v1, ok := ret[v.GetUnitid()]; ok {
ret[v.GetUnitid()] = v1 + v.GetUnitnum()
} else {
ret[v.GetUnitid()] = v.GetUnitnum()
}
}
return ret
}
/**
@brief 按等级从低到高排序
*/
func sortUnitLevel(orgiInfoList []*stUnitInfo) []*stUnitInfo {
//unitInfoList := make([]*stUnitInfo, 0)
if nil == orgiInfoList || 0 == len(orgiInfoList) {
return orgiInfoList
}
tmpMap := make(map[int64]*stUnitInfo)
levelList := make([]int64, 0)
for _, v := range orgiInfoList {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.unit.GetUnitid()))
if nil == unitCSV {
continue
}
tmpMap[unitCSV.UnitLevel] = v
levelList = append(levelList, unitCSV.UnitLevel)
}
sort.Sort(wsort.Int64Slice(levelList))
for k, v := range levelList {
/*unitInfo := &stUnitInfo{
unit: tmpMap[v].unit,
powerRatio: tmpMap[v].powerRatio,
}*/
orgiInfoList[k] = tmpMap[v]
}
return orgiInfoList
}
/**
@brief 按等级从低到高排序
*/
func sortUnitLevelEx(corp *stCorps) *stCorps {
if nil == corp || 0 == len(corp.startUnits) {
return corp
}
tmpMap := make(map[int64]*proto.ST_Unit_PB)
levelList := make([]int64, 0)
for _, unit := range corp.startUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if nil == unitCSV {
continue
}
tmpMap[unitCSV.UnitLevel] = unit
levelList = append(levelList, unitCSV.UnitLevel)
}
sort.Sort(wsort.Int64Slice(levelList))
corp.startUnits = make([]*proto.ST_Unit_PB, 0)
for _, v := range levelList {
corp.startUnits = append(corp.startUnits, tmpMap[v])
}
corp.curUnits = make([]*proto.ST_Unit_PB, 0)
for _, v := range corp.startUnits {
tmp := proto.Clone(v).(*proto.ST_Unit_PB)
corp.curUnits = append(corp.curUnits, tmp)
}
return corp
}
//计算士兵战斗力占比
func analysisUnitAssetToUserUnitInfo(units *proto.ST_UnitAsset_PB) *stUserUnitInfo {
userUnitInfo := &stUserUnitInfo{}
if nil == units {
return userUnitInfo
}
totalUnitPower := int64(0)
//var unitInfoList []*stUnitInfo
unitMap := make(map[proto.UnitBattleType][]*stUnitInfo)
for _, v := range units.Units {
unitInfo := &stUnitInfo{
unit: &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitid()),
Unitnum: proto.SetUint64(v.GetUnitnum()),
},
}
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if nil != unitCSV {
unitMap[proto.UnitBattleType(unitCSV.UnitPosType)] = append(unitMap[proto.UnitBattleType(unitCSV.UnitPosType)], unitInfo)
}
}
/*
for k, v := range unitMap {
unitInfoList = sortUnitLevel(v)
unitMap[k] = unitInfoList
}
*/
userUnitInfo.unitMap = unitMap
//不同等级兵种在同类型兵种中的战力比(eg:T1,T2,T3,T4在步兵中的战力占比)
for _, unitInfoList := range userUnitInfo.unitMap {
corpPower := int64(0)
for _, unitInfo := range unitInfoList {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unitInfo.unit.GetUnitid()))
unitInfo.power = int64(unitInfo.unit.GetUnitnum()) * unitCSV.Power
corpPower += unitInfo.power
}
for _, unitInfo := range unitInfoList {
if 0 == corpPower {
unitInfo.powerRatio = 0
} else {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unitInfo.unit.GetUnitid()))
unitInfo.powerRatio = float32(int64(unitInfo.unit.GetUnitnum())*unitCSV.Power) / float32(corpPower)
}
}
totalUnitPower += corpPower
}
userUnitInfo.totalPower = totalUnitPower
return userUnitInfo
}
func analysisUnitAssetToCorpsMap(corpsMap *stCorpsMap, unitAsset *proto.ST_UnitAsset_PB) bool {
if nil == corpsMap || nil == unitAsset {
return false
}
if nil == corpsMap.unitList {
corpsMap.unitList = make(map[proto.UnitBattleType][]*stCorps)
}
if nil == corpsMap.trapList {
corpsMap.trapList = make(map[proto.UnitBattleType][]*stCorps)
}
//unitsMap := unitAssetToMap(unitAsset)
for _, k := range unitAsset.GetUnits() {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(k.GetUnitid()))
if nil == unitCSV {
continue
}
//兵种
tmpUnitType := proto.UnitBattleType(unitCSV.UnitPosType)
if (proto.UnitBattleType_UBT_NOMAL_TANK <= tmpUnitType) &&
(proto.UnitBattleType_UBT_NOMAL_FEIJI >= tmpUnitType) {
var tmpActionUnit *stCorps
_, ok := corpsMap.unitList[tmpUnitType]
if !ok {
corpsMap.unitList[tmpUnitType] = make([]*stCorps, 5)
}
if corpsMap.unitList[tmpUnitType][unitCSV.UnitLevel-1] == nil {
tmpActionUnit = &stCorps{
unitType: tmpUnitType,
curUnits: make([]*proto.ST_Unit_PB, 0),
startUnits: make([]*proto.ST_Unit_PB, 0),
fightBuff: make(map[uint32]*stFightBuff),
unitHp: make(map[uint32]uint64),
}
tmpActionUnit.startUnits = append(tmpActionUnit.startUnits, k)
tmp := proto.Clone(k).(*proto.ST_Unit_PB)
tmpActionUnit.curUnits = append(tmpActionUnit.curUnits, tmp)
corpsMap.unitList[tmpUnitType][unitCSV.UnitLevel-1] = tmpActionUnit
}
//tmpActionUnit.curUnits = common.CombineUnit(tmpActionUnit.curUnits, k)
//tmpActionUnit.startUnits = common.CombineUnit(tmpActionUnit.startUnits, k)
} else if (proto.UnitBattleType_UBT_NOMAL_TRAP1 <= tmpUnitType) &&
(proto.UnitBattleType_UBT_NOMAL_TRAP4 >= tmpUnitType) { //陷阱
var tmpActionUnit *stCorps
_, ok := corpsMap.trapList[tmpUnitType]
if !ok {
corpsMap.trapList[tmpUnitType] = make([]*stCorps, 5)
}
if corpsMap.trapList[tmpUnitType][unitCSV.UnitLevel-1] == nil {
tmpActionUnit = &stCorps{
unitType: tmpUnitType,
curUnits: make([]*proto.ST_Unit_PB, 0),
startUnits: make([]*proto.ST_Unit_PB, 0),
fightBuff: make(map[uint32]*stFightBuff),
unitHp: make(map[uint32]uint64),
}
tmpActionUnit.startUnits = append(tmpActionUnit.startUnits, k)
tmp := proto.Clone(k).(*proto.ST_Unit_PB)
tmpActionUnit.curUnits = append(tmpActionUnit.curUnits, tmp)
corpsMap.trapList[tmpUnitType][unitCSV.UnitLevel-1] = tmpActionUnit
}
//tmp := proto.Clone(v).(*proto.ST_Unit_PB)
//corp.curUnits = append(corp.curUnits, tmp)
//tmpActionUnit.curUnits = common.CombineUnit(tmpActionUnit.curUnits, k)
//tmpActionUnit.startUnits = common.CombineUnit(tmpActionUnit.startUnits, k)
}
}
//for k, v := range corpsMap.unitList {
// corpsMap.unitList[k] = sortUnitLevelEx(v)
//}
//for k, v := range corpsMap.trapList {
// corpsMap.trapList[k] = sortUnitLevelEx(v)
//}
if nil == unitAsset {
wlog.Error("sort unitAsset Level error")
return false
}
//统计下各个军团的总数量
for _, lst := range corpsMap.unitList {
for _, v := range lst {
countUnitsNumByCorps(v)
}
}
for _, lst := range corpsMap.trapList {
for _, v := range lst {
countUnitsNumByCorps(v)
}
}
return true
}
/*
@brief 战斗关键信息
通用数据必须有
如果是大地图行为,则大地图行为数据必须有
反之,必须有本地行为数据
*/
type stBattleKey struct {
//通用数据,必须有
UID uint64 //攻击发起人UID
heroIDList []uint32 //攻击方英雄列表
units *proto.ST_UnitAsset_PB //攻击发起人战斗单位
formation uint32 //攻击方阵型
//大地图行为数据
actionID uint64 //攻击方行为ID
childrenID []uint64
endTileID int32 //目的地
//本地行为数据 targetTuiTu
targetType uint32 //目标类型
monsterGroupID int64 //怪物组ID
airShipConfId int64 //飞艇配置
}
func prepareBattleKey(dataAsset *cache.GlobalActionEntry) (bool, *stBattleKey) {
if nil == dataAsset || nil == dataAsset.Actiondata {
return false, nil
}
battleKey := &stBattleKey{
childrenID: make([]uint64, 0),
heroIDList: make([]uint32, 0),
}
//通用数据,必须有
battleKey.UID = dataAsset.Actiondata.GetUid()
battleKey.heroIDList = dataAsset.Actiondata.GetHeroIDList()
battleKey.units = dataAsset.Actiondata.GetUnits()
battleKey.formation = dataAsset.Actiondata.GetFormation()
//大地图行为数据
battleKey.actionID = dataAsset.Actiondata.GetActionid()
battleKey.childrenID = dataAsset.Actiondata.GetChildrenID()
battleKey.endTileID = dataAsset.Actiondata.GetEndTileID()
return true, battleKey
}
/**
@brief 不同战斗场景的逻辑入口
*/
func worldBattle(dataAsset *cache.GlobalActionEntry) {
//TODO
//战斗开始,不同的目标,需要根据自身规则处理相关前期逻辑
rlt, battleKey := prepareBattleKey(dataAsset)
if false == rlt {
return
}
//正式开始战斗
RobotWorldBattleManager.CreateInstance(battleKey.UID)
battleRlt, _, targetType, battleInfo, battleReport, monsterBattleReport := worldRealBattle(battleKey)
RobotWorldBattleManager.EndRobotBattle(battleKey.UID, battleRlt)
//TODO
//战斗结束,根据不同的目标根据结果处理相关逻辑
if targetMonster != targetType {
if dataAsset.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MACATTCK) {
processMacWorldBattleResult(battleRlt, targetType, dataAsset, battleReport, battleInfo)
} else {
processWorldBattleResult(battleRlt, targetType, dataAsset, battleReport, battleInfo)
}
} else {
processWildMonsterResult(dataAsset, monsterBattleReport, battleInfo)
}
}
func airShipBattle(bk *stBattleKey) (proto.RetActionType, bool, *proto.ST_BattleInfo_PB, *proto.ST_Vector4IntList_PB, uint32, *proto.ST_Vector4IntList_PB) {
//正式开始战斗
battleRlt, _, targetType, battleInfo, battleReport, _ := worldRealBattle(bk)
isWin, _ := checkFinalRlt(targetType, battleRlt, battleReport)
ret, items, star, firstPassItems := processAirShipBattleResult(isWin, targetType, bk, battleReport, battleInfo)
for _, v := range battleReport.GetAtkInfo() {
if nil == v.GetCommanderReport() {
continue
}
atkData := cache.GetCharinfo(v.CommanderReport.GetUid())
if atkData == nil {
continue
}
break
}
return ret, isWin, battleInfo, items, star, firstPassItems
}
/**
@brief 机器人战斗
*/
func RobotBattle(battleKey *stBattleKey) {
RobotWorldBattleManager.CreateInstance(battleKey.UID)
battleRlt, _, _, _, _, _ := worldRealBattle(battleKey)
RobotWorldBattleManager.EndRobotBattle(battleKey.UID, battleRlt)
}
func maincityBattle(userData *cache.Info, bk *stBattleKey) (bool, *proto.ST_BattleInfo_PB) {
//主城地块解锁正式开始战斗
battleRlt, _, targetType, battleInfo, battleReport, _ := worldRealBattle(bk)
isWin, _ := checkFinalRlt(targetType, battleRlt, battleReport)
if nil != userData {
//处理战后兵力信息
//AtkInfo只有自己
injuredUnitList := make(map[uint32]uint32)
for _, v := range battleReport.GetAtkInfo() {
units := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
for _, v1 := range v.GetUnitListReport() {
newUnit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v1.GetUnitID()),
Unitnum: proto.SetUint64(uint64(v1.GetSurvival())),
}
injuredUnitList[v1.GetUnitID()] = v1.GetInjured()
units.Units = common.CombineUnit(units.Units, newUnit)
}
userData.AddUnitAssets(units)
break
}
hurtUnit, _ := processBattleHospital(userData, injuredUnitList)
userData.AddHospitalUnitAsset(hurtUnit)
}
return isWin, battleInfo
}
/**
@brief 根据战斗对象和战损比来获取最终结果
*/
func checkFinalRlt(targetType uint32, battleRlt uint32, battleReport *proto.ST_BattleReport_PB) (bool, bool) {
threshold := CSV.GetGameConfigValueUint32("BATTLE_LOSS_RATIO") //攻方失败后,能否查看战报的阈值
isAtkWin := true
hasMailReport := true
atkPowerReport := battleReport.GetAtkPowerReport()
defPowerReport := battleReport.GetDefPowerReport()
defInfoLen := len(battleReport.GetDefInfo())
lastRoundDefInfo := battleReport.GetDefInfo()[defInfoLen-1] //防守方最后一回合信息
//单人野怪永远胜利
if targetType != targetMonster {
//战力比
if atkPowerReport.GetAllPower() == 0 {
isAtkWin = false
hasMailReport = false
goto end
}
allPowerRatio := uint32(defPowerReport.GetAllPower() / atkPowerReport.GetAllPower())
//进攻玩家主城时,城墙未破,则防守方胜利
if nil != lastRoundDefInfo.GetWallReport() && uint32(0) != lastRoundDefInfo.GetWallReport().GetAfterHp() {
isAtkWin = false
if allPowerRatio > threshold {
hasMailReport = false
}
goto end
}
//兵力耗尽或者回合结束,通过战损比判定胜负
if battleRlt_AllEmpty == battleRlt || battleRlt_Over == battleRlt {
wlog.Info(atkPowerReport.GetLossValue(), defPowerReport.GetLossValue())
if atkPowerReport.GetLossValue() >= defPowerReport.GetLossValue() {
isAtkWin = false
if allPowerRatio > threshold {
hasMailReport = false
}
}
goto end
}
//进攻方兵力耗尽
if battleRlt_AtkEmpty == battleRlt {
isAtkWin = false
if allPowerRatio > threshold {
hasMailReport = false
}
goto end
}
}
end:
return isAtkWin, hasMailReport
}
func processWildMonsterResult(actionDataAsset *cache.GlobalActionEntry, monsterBattleReport *proto.ST_MonsterKill_PB, battleInfo *proto.ST_BattleInfo_PB) {
actionDataEntry := actionDataAsset.Actiondata
if actionDataEntry == nil {
return
}
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(actionDataEntry.GetEndTileID())
if worldAssetData == nil || monsterBattleReport == nil {
return
}
if getWorldDataTargetType(worldAssetData) != targetMonster {
return
}
//actionDataEntry.Units = &proto.ST_UnitAsset_PB{}
csvWorldConfig := worldAssetData.GetWorldEntryConfig()
if csvWorldConfig == nil {
return
}
attUser := actionDataAsset.GetActionOwner()
if attUser == nil {
return
}
tmps := strings.Split(csvWorldConfig.ContinuityHurt, ";")
if len(tmps) < 2 {
wlog.Error("processWorldBattleResult targetMonster err: ", csvWorldConfig.ID)
return
}
//计算伤害
hot := uint32(0)
attUser.WithKillWildMonsterAsset(false, func(assert *cache.Asset_KillWildMonster) bool {
if assert.Dataid == worldAssetData.GetWorldDataID() {
if assert.Number > 0 {
hurtMaxNum := CSV.GetGameConfigValueUint32("Continuity_Hurt_Number")
hurtMaxNum = uint32(countAdditional(uint64(hurtMaxNum), attUser, proto.AtttibuteType_AttMonsCount))
if assert.Number <= hurtMaxNum {
hurtMaxNum = assert.Number
}
hot += common.StringToUint32(tmps[0])
if uint32(wtime.GetNow()-assert.Time) <= CSV.GetGameConfigValueUint32("Continuity_Hurt_Time")*60 {
hot += (hurtMaxNum - 1) * common.StringToUint32(tmps[1])
}
}
assert.Number += 1
} else {
assert.Dataid = worldAssetData.GetWorldDataID()
assert.Number = 1
}
assert.Time = wtime.GetNow()
monsterBattleReport.MonsterInf.Count = proto.SetUint32(assert.Number)
return true
})
hitCount := actionDataEntry.GetHit()
monsterBattleReport.MonsterInf.Times = proto.SetUint32(hitCount)
hp := uint64((10000+hot)*monsterBattleReport.GetMonsterInf().GetDropHP()/10000) * uint64(hitCount)
if worldAssetData.GetWorldData().SimpleEntry.GetHp() < hp {
hp = worldAssetData.GetWorldData().SimpleEntry.GetHp()
}
worldAssetData.GetWorldData().SimpleEntry.Hp = proto.SetUint64(worldAssetData.GetWorldData().SimpleEntry.GetHp() - hp)
monsterBattleReport.MonsterInf.CurrentHP = proto.SetUint32(uint32(worldAssetData.GetWorldData().SimpleEntry.GetHp()))
monsterBattleReport.MonsterInf.DropHP = proto.SetUint32(uint32(hp))
monsterBattleReport.Uid = proto.SetUint64(attUser.GetUid())
monsterBattleReport.Monsterid = proto.SetInt64(csvWorldConfig.ID)
monsterBattleReport.MonsterInf.AddDamage = proto.SetUint32(hot)
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "DelHp", common.Uint64ToString(hp)))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_DelHp)
//加英雄经验
entryConfig := common.ParseParameterStringToMap(csvWorldConfig.EntryConfig)
heroExpStr, ok := entryConfig["HeroExp"]
if ok {
heroExp := common.ParseStringToUint64List(heroExpStr)
if len(heroExp) == 2 {
var heroLevelUp []uint32
expRise := getPassiveAfterFightSkillEffect(attUser, actionDataEntry.GetHeroIDList(), "ExpRise")
for _, id := range actionDataEntry.GetHeroIDList() {
isLevelUp := false
attUser.WithHeroAsset(true, id, func(heroAsset *proto.ST_HeroEntry_PB) bool {
conf := CSV.Mgr.CSV_HeroLevel.GetEntryPtr(int64(heroAsset.GetLevel()))
exp := (heroExp[0]*uint64(conf.ExpCoefficient) + heroExp[1]) * uint64(hitCount)
exp = uint64(10000+expRise) * exp / 10000
flag, fixExp := attUser.CanAddHeroExp(id, exp)
if flag {
_, isLevelUp = attUser.AddHeroExp(id, fixExp)
}
if isLevelUp {
heroLevelUp = append(heroLevelUp, heroAsset.GetId())
}
heroReport := &proto.ST_HeroBattleReport_PB{
Id: proto.SetUint32(heroAsset.GetId()),
Level: proto.SetUint32(heroAsset.GetLevel()),
Star: proto.SetUint32(heroAsset.GetStar()),
Exp: proto.SetUint64(heroAsset.GetExp()),
AddExp: proto.SetUint64(fixExp),
IsLevelUp: proto.SetBool(isLevelUp),
//Rank: proto.SetUint32(heroAsset.GetRank()),
}
heroReport.SkillList = make([]*proto.ST_HeroSkill_PB, 0)
for _, v := range heroAsset.GetSkillList() {
skill := &proto.ST_HeroSkill_PB{
SkillLogicType: proto.SetUint32(v.GetSkillLogicType()),
SkillID: proto.SetUint32(v.GetSkillID()),
}
heroReport.SkillList = append(heroReport.SkillList, skill)
}
heroReport.BranchValue = make([]uint32, 0)
for _, v := range heroAsset.GetBranchValue() {
heroReport.BranchValue = append(heroReport.BranchValue, v)
}
monsterBattleReport.HeroListReport = append(monsterBattleReport.HeroListReport, heroReport)
return true
})
}
attUser.AddLevelUpHeroList(heroLevelUp)
}
}
commanderExpStr, ok := entryConfig["CommanderExp"]
addexp := uint64(0)
if ok {
commanderExp := common.ParseStringToUint64List(commanderExpStr)
if len(commanderExp) == 2 {
conf := CSV.Mgr.CSV_CommanderLevelUp.GetEntryPtr(int64(attUser.GetLevel()))
commanderExp := (commanderExp[0]*uint64(conf.ExpCoefficient) + commanderExp[1]) * uint64(actionDataEntry.GetHit())
addexp = attUser.AddExp(commanderExp)
monsterBattleReport.CommanderExp = proto.SetUint32(uint32(addexp))
}
}
//多次猎杀奖励
for i := actionDataEntry.GetHit(); i > 0; i-- {
itemList := createItemByVector4(entryConfig["Rward"])
for _, item := range itemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcTypeKillMonster)
}
monsterBattleReport.Reward = append(monsterBattleReport.Reward, itemList...)
activityItemList := processDropActivity(attUser, int32(proto.DropActivityType_DAT_AttackMonster), 0, 1)
for _, item := range activityItemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcDropActivity)
}
monsterBattleReport.Reward = append(monsterBattleReport.Reward, activityItemList...)
}
monsterBattleReport.Reward = common.CombineItemList(monsterBattleReport.Reward)
isWin := 2
if worldAssetData.GetWorldData().SimpleEntry.GetHp() == 0 {
isWin = 1
cache.Instance_GlobalAssetWorldData.WithWildMonsterListAsset(false, func(asset *cache.ST_WildMonsterList) bool {
asset.List[worldAssetData.GetWorldDataID()] = 0
return true
})
//RecallCityArmy(worldAssetData)
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "needDeleteID", common.Uint64ToString(worldAssetData.GetWorldDataID())))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_Delete)
//击杀奖励
AddLeagueGift(attUser.GetLeagueID(), uint32(csvWorldConfig.HitReward), "", 0)
attUser.SyncAchievementIfGraterSet(cache.LSMWDJEvent, uint64(csvWorldConfig.EntryLevel))
attUser.SyncAchievementAdd(cache.LJLSMWCSEvent, uint64(1))
//7日挑战积分
observer.ObserverSingleton.AsyncNotify(observer.ChallengeKillMonsterEvent, []interface{}{attUser, csvWorldConfig.EntryLevel, uint32(1)})
observer.ObserverSingleton.AsyncNotify(observer.ActivityTaskKillMonsterEvent, []interface{}{attUser, uint32(1), uint32(1)})
observer.ObserverSingleton.AsyncNotify(observer.KillMonsterEvent, []interface{}{attUser, uint32(1), uint32(1), uint32(csvWorldConfig.EntryLevel), targetMonster})
}
attUser.SyncAchievementAdd(cache.AtkMonEvent, uint64(actionDataEntry.GetHit()))
observer.ObserverSingleton.AsyncNotify(observer.AttackMonsterEvent, []interface{}{attUser, actionDataEntry.GetHit(), uint32(worldAssetData.GetWorldDataEntry().GetZ())})
SFUID := common.GetSFUID()
strSFUID := strconv.FormatInt(SFUID, 10)
// 暂时添加为测试英雄技能
//strInfo := string(proto.Marshal(battleInfo))
//cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
mailtype := uint32(proto.MailType_MT_MONSTER)
titleTips := common.CreateTips(90000093, uint32(csvWorldConfig.Name))
contentTips := common.CreateTips(72065, uint32(csvWorldConfig.Name), common.ConvertToString(csvWorldConfig.EntryLevel))
_, mailid := attUser.AddLanguageIDMailAsset(mailtype, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), titleTips, contentTips,
string(proto.Marshal(monsterBattleReport)), strSFUID)
//右下角战斗通知
atkBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(false)} //进攻方的战斗结果通知
atkBattleNotice.LanguageID = proto.SetUint32(75551) //您攻击了lv.$0$@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
atkBattleNotice.BattleRlt = proto.SetBool(true)
// 暂时添加为测试英雄技能
//atkBattleNotice.IsHaveBattleInfo = proto.SetBool(true)
atkBattleNotice.MailID = proto.SetUint64(mailid)
attUser.CreateBattleNotice(SFUID, atkBattleNotice)
newOssBattleRecord(attUser, oss.OBT_Monster, isWin == 1, 0, 1, targetMonster,
int32(monsterBattleReport.GetMonsterInf().GetTileID()), monsterBattleReport.GetHeroListReport(), monsterBattleReport.GetUints())
newOssMonsterBattle(attUser, 1, actionDataEntry.GetHit(), worldAssetData, hp, addexp, isWin, monsterBattleReport.GetHeroListReport(),
monsterBattleReport.GetUints(), monsterBattleReport.GetReward(), 0, []uint64{})
}
/**
@brief 根据不同的目标根据结果处理相关逻辑
*/
func processWorldBattleResult(battleRlt uint32, targetType uint32, actionDataAsset *cache.GlobalActionEntry, battleReport *proto.ST_BattleReport_PB, battleInfo *proto.ST_BattleInfo_PB) {
if battleReport == nil || actionDataAsset == nil {
wlog.Error("processWorldBattleResult:", targetType)
return
}
if len(battleReport.GetAtkInfo()) <= 0 || len(battleReport.GetDefInfo()) <= 0 {
wlog.Error("processWorldBattleResult < 0 ")
return
}
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(actionDataAsset.Actiondata.GetEndTileID())
if worldAssetData == nil {
return
}
csvWorldConfig := worldAssetData.GetWorldEntryConfig()
if csvWorldConfig == nil {
return
}
heroList := make([]uint32, 0)
monsterLevel := uint32(csvWorldConfig.EntryLevel)
actionDataEntry := actionDataAsset.Actiondata
function := common.ParseParameterStringToMap(csvWorldConfig.EntryConfig)
award := function["AttackRward"]
unitChannel := oss.UnitChangeTypePVP
initiatorRward := function["InitiatorRward"]
var attInfo = getBigBrother(battleReport.AtkInfo) //攻击方首回合信息
var defInfo = getBigBrother(battleReport.DefInfo) //防守方首回合信息
if attInfo == nil || defInfo == nil {
return
}
isMultiuserAtk := false //集结攻击
isMultiuserDef := false //援助
if actionDataAsset.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
isMultiuserAtk = true
}
if 1 < len(battleReport.GetDefInfo()) {
isMultiuserDef = true
}
defInfoLen := len(battleReport.GetDefInfo())
lastRoundDefInfo := battleReport.GetDefInfo()[defInfoLen-1] //防守方最后一回合信息
attUser := cache.GetCharinfo(attInfo.GetCommanderReport().GetUid())
if attUser == nil {
return
}
for _, v := range attInfo.GetHeroListReport() {
heroList = append(heroList, v.GetId())
}
// defUser 可能为nil
var defUser *cache.Info
if defInfo.CommanderReport != nil {
defUser = cache.GetCharinfo(defInfo.GetCommanderReport().GetUid())
}
isWin, hasMailReport := checkFinalRlt(targetType, battleRlt, battleReport)
battleInfo.IsAtkWin = proto.SetBool(isWin)
attActionUnitMap, defActionUnitMap, attRemainUnit := getActionUnitMapByBattleReport(battleReport)
//处理战斗后兵种资产
processGlobalActionAfterBattle(defActionUnitMap, worldAssetData, targetType, defUser, actionDataEntry.GetActiontype(), nil, isWin, false)
processGlobalActionAfterBattle(attActionUnitMap, worldAssetData, targetType, attUser, actionDataEntry.GetActiontype(), battleReport.GetReturnUnitsList(), isWin, true)
checkAtkDefAllDieout(attActionUnitMap, defActionUnitMap, targetType, worldAssetData)
//处理玩家统计信息
cid := GetcityID(worldAssetData)
pvp := true
if cid != 0 && defUser == nil {
pvp = false
}
kill, _ := processStatisticsAsset(isWin, targetType, attUser, defUser, true, battleReport.GetAtkInfo(), true, pvp)
defkill, _ := processStatisticsAsset(isWin, targetType, defUser, attUser, true, battleReport.GetDefInfo(), false, true)
atkBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //进攻方的战斗结果通知
targetBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //被进攻方的战斗结果通知
targetSubBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //援助方的战斗结果通知
atkTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())}
defTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())} //防守方主要对象收到的信息
defSubTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())} //防守方支援对象收到的信息
atkMutiMonsterContent := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())}
if isWin {
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 90000093)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 90000092)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 90000092)
atkBattleNotice.BattleRlt = proto.SetBool(true)
targetBattleNotice.BattleRlt = proto.SetBool(false)
targetSubBattleNotice.BattleRlt = proto.SetBool(false)
} else {
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 90000094)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 90000091)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 90000091)
atkBattleNotice.BattleRlt = proto.SetBool(false)
targetBattleNotice.BattleRlt = proto.SetBool(true)
targetSubBattleNotice.BattleRlt = proto.SetBool(true)
}
atkUsers := make([]uint64, 0)
switch targetType {
case targetMainCity:
battleReport.DefFailInfo = &proto.ST_DefFailInfo_PB{}
if nil != lastRoundDefInfo.GetWallReport() {
Speed := countAdditional(uint64(CSV.GetGameConfigValueUint32("WALL_BURN_SPEED")), attUser, proto.AtttibuteType_SiegeAttack)
battleReport.DefFailInfo.BurningTime = proto.SetUint32(ProcessMainCityDefenseLogic(worldAssetData.GetWorldDataOwner(), isWin, lastRoundDefInfo.WallReport.GetAfterHp(), Speed))
}
atkTitleTips.LanguageID = proto.SetUint32(90000012)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 20000125)
atkTitleTips.ParaString = append(atkTitleTips.ParaString, defUser.GetUserName())
defTitleTips.LanguageID = proto.SetUint32(90000011)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 20000125)
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
defSubTitleTips.LanguageID = proto.SetUint32(90000011)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 71026)
defSubTitleTips.ParaString = append(defSubTitleTips.ParaString, attUser.GetUserName())
//右下角战斗提示
atkBattleNotice.LanguageID = proto.SetUint32(75549) //您攻击了$0$
if isMultiuserAtk {
atkBattleNotice.LanguageID = proto.SetUint32(75555) //您集结攻击了$0$
}
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, defUser.GetUserName())
if isMultiuserAtk {
targetBattleNotice.LanguageID = proto.SetUint32(75558) //$0$集结攻击了您
} else {
targetBattleNotice.LanguageID = proto.SetUint32(75550) //$0$攻击了您
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
if isMultiuserAtk {
targetSubBattleNotice.LanguageID = proto.SetUint32(75599) //$0$集结攻击了您援助的$1$
}
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
if isWin {
// 资源掠夺
totalResource, actionResource := genGrabResource(attUser, defUser, attRemainUnit, attActionUnitMap, isWin, targetMainCity, heroList, worldAssetData.GetWorldDataID())
//>>>完成攻击成就[6501001]
attUser.SyncAchievementAdd(cache.LJGJWJHSEvent, uint64(1))
processPrisonAfterBattle(battleReport.GetAtkInfo(), attUser, defUser)
_, CaptureMap := captureCommander(attUser, defUser, true, targetType)
for k := range CaptureMap {
battleReport.DefFailInfo.PrisonID = proto.SetUint64(k)
break
}
//资源掠夺总奖励 key|Value
battleReport.TotalReward = proto.SetString(encodeActionAppendData("", "usrCash", string(proto.Marshal(totalResource))))
//参与玩家各自的奖励
for _, v := range battleReport.AtkInfo {
userInfo := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == userInfo {
continue
}
if rewardResource, ok := actionResource[v.GetActionID()]; ok {
v.Reward = proto.SetString(encodeActionAppendData("", "usrCash", string(proto.Marshal(rewardResource))))
}
itemList := processDropActivity(userInfo, int32(proto.DropActivityType_DAT_AttackMainCity), 0, 1)
for _, item := range itemList {
AddItem(userInfo, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcDropActivity)
v.MutirMonReward = append(v.MutirMonReward, item)
}
}
}
case targetMonsterEx:
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
atkMutiMonsterContent.ParaUint32 = append(atkMutiMonsterContent.ParaUint32, uint32(csvWorldConfig.Name))
atkMutiMonsterContent.ParaString = append(atkMutiMonsterContent.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
if isWin {
atkTitleTips.LanguageID = proto.SetUint32(90000093) //进攻胜利
atkMutiMonsterContent.LanguageID = proto.SetUint32(72065) //您成功摧毁了Lv.$0$ @0@
attUser.SyncAchievementAdd2(cache.NewTask1, int64(proto.WorldEntryType_WET_WILDMONSTEREX), int64(csvWorldConfig.EntryLevel), 1)
} else {
atkTitleTips.LanguageID = proto.SetUint32(90000094) //进攻失败
atkMutiMonsterContent.LanguageID = proto.SetUint32(72066) //进攻Lv.$0$ @0@失败
}
//右下角战斗通知
atkBattleNotice.LanguageID = proto.SetUint32(75551) //您攻击了lv.$0$@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
atkBattleNotice.BattleRlt = proto.SetBool(isWin)
atkBattleNotice.IsHaveBattleInfo = proto.SetBool(false)
// 暂时添加为测试英雄技能
//atkBattleNotice.IsHaveBattleInfo = proto.SetBool(true)
//加英雄经验
//成功击杀
if isWin {
entryConfig := common.ParseParameterStringToMap(csvWorldConfig.EntryConfig)
heroExpStr, ok := entryConfig["HeroExp"]
if ok {
heroExp := common.ParseStringToUint64List(heroExpStr)
if len(heroExp) == 2 {
expRise := getPassiveAfterFightSkillEffect(attUser, heroList, "ExpRise")
var heroLevelUp []uint32
for _, v := range attInfo.HeroListReport {
isLevelUp := false
attUser.WithHeroAsset(true, v.GetId(), func(heroAsset *proto.ST_HeroEntry_PB) bool {
conf := CSV.Mgr.CSV_HeroLevel.GetEntryPtr(int64(heroAsset.GetLevel()))
exp := heroExp[0]*uint64(conf.ExpCoefficient) + heroExp[1]
exp = (uint64(expRise) + 10000) * exp / 10000
flag, fixExp := attUser.CanAddHeroExp(v.GetId(), exp)
if flag {
_, isLevelUp = attUser.AddHeroExp(v.GetId(), fixExp)
}
if isLevelUp {
heroLevelUp = append(heroLevelUp, heroAsset.GetId())
v.Level = proto.SetUint32(heroAsset.GetLevel())
}
v.AddExp = proto.SetUint64(exp)
v.IsLevelUp = proto.SetBool(isLevelUp)
return true
})
}
attUser.AddLevelUpHeroList(heroLevelUp)
}
}
//指挥官经验
commanderExpStr, ok := entryConfig["CommanderExp"]
addexp := uint64(0)
if ok {
commanderExp := common.ParseStringToUint64List(commanderExpStr)
if len(commanderExp) == 2 {
conf := CSV.Mgr.CSV_CommanderLevelUp.GetEntryPtr(int64(attUser.GetLevel()))
exp := commanderExp[0]*uint64(conf.ExpCoefficient) + commanderExp[1]
addexp = attUser.AddExp(exp)
attInfo.CommanderReport.AddExp = proto.SetUint64(addexp)
}
}
//RecallCityArmy(worldAssetData)
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "needDeleteID", common.Uint64ToString(worldAssetData.GetWorldDataID())))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_Delete)
//给予首杀奖励
if uint32(csvWorldConfig.EntryLevel) > attUser.GetKilledMonsterLevel() {
firstReward, ok := entryConfig["FirstKillAward"]
if ok {
finilReward := &proto.ST_Vector4IntList_PB{}
itemList := createItemByVector4(firstReward)
for _, item := range itemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillMonsterEx)
tmp := &proto.ST_Vector4Int_PB{
Y: proto.SetInt32(int32(item.GetItemId())),
W: proto.SetInt32(int32(item.GetItemNum())),
}
finilReward.Reward = append(finilReward.Reward, tmp)
}
attInfo.Reward = proto.SetString(encodeActionAppendData("", "firstKill", string(proto.Marshal(finilReward))))
}
attUser.SetKilledMonsterLevel(uint32(csvWorldConfig.EntryLevel))
}
//给予击杀奖励
reward, ok := entryConfig["Rward"]
if ok {
//v := battleReport.AtkInfo[0]
itemList := createItemByVector4(reward)
for _, item := range itemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillMonsterEx)
attInfo.MutirMonReward = append(attInfo.MutirMonReward, item)
}
activityItemList := processDropActivity(attUser, int32(proto.DropActivityType_DAT_KillMonster), 0, 1)
for _, item := range activityItemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcDropActivity)
}
attInfo.MutirMonReward = append(attInfo.MutirMonReward, activityItemList...)
}
observer.ObserverSingleton.AsyncNotify(observer.KillMonsterExEvent, []interface{}{attUser, csvWorldConfig.EntryLevel})
observer.ObserverSingleton.AsyncNotify(observer.ActivityTaskKillMonsterEvent, []interface{}{attUser, uint32(3)})
}
case targetSummonMutiMonster:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkBattleNotice.LanguageID = proto.SetUint32(75556) //您集结攻击了lv.$0$@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.IsHaveBattleInfo = proto.SetBool(false)
// 暂时添加为测试英雄技能
//atkBattleNotice.IsHaveBattleInfo = proto.SetBool(true)
if isWin {
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "needDeleteID", common.Uint64ToString(worldAssetData.GetWorldDataID())))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_Delete)
//公会奖励
AddLeagueGift(attUser.GetLeagueID(), uint32(csvWorldConfig.HitReward), "", 0)
lid := worldAssetData.GetWorldData().SimpleEntry.GetMstLid()
//参与者奖励
for _, v := range battleReport.AtkInfo {
tmpUserData := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == tmpUserData {
continue
}
atkUsers = append(atkUsers, v.GetCommanderReport().GetUid())
//怪物攻城集结怪只有参与报名的成员才有奖励
if lid != 0 && attUser.GetLeagueID() != GetMacMgrInstance().GetOrgLid(tmpUserData) {
continue
}
award := function["Rward"]
itemList := createItemByVector4(award)
for _, item := range itemList {
AddItem(tmpUserData, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillSummonMonster)
v.MutirMonReward = append(v.MutirMonReward, item)
}
}
if lid != 0 {
GetMacMgrInstance().rallMonsterKilled(lid)
}
}
case targetMutiMonster:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkBattleNotice.LanguageID = proto.SetUint32(75557) //您集结攻击了lv.$0$@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
if isWin {
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "needDeleteID", common.Uint64ToString(worldAssetData.GetWorldDataID())))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_Delete)
AddLeagueGift(attUser.GetLeagueID(), uint32(csvWorldConfig.HitReward), "", 0)
for _, v := range battleReport.AtkInfo {
tmpUserData := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == tmpUserData {
continue
}
atkUsers = append(atkUsers, v.GetCommanderReport().GetUid())
observer.ObserverSingleton.AsyncNotify(observer.ActivityTaskKillMonsterEvent, []interface{}{tmpUserData, uint32(2)})
observer.ObserverSingleton.AsyncNotify(observer.KillMachineCenterEvent, []interface{}{tmpUserData, uint32(monsterLevel)})
tmpUserData.SyncAchievementAdd(cache.LJLSMWCSEvent, uint64(1))
// 活动积分
observer.ObserverSingleton.AsyncNotify(observer.KillMonsterEvent, []interface{}{tmpUserData, uint32(1), uint32(1), monsterLevel, targetMutiMonster})
//>>猎杀LV.1魔物[6503801]
tmpUserData.SyncAchievementIfGraterSet(cache.LSMWDJEvent, uint64(monsterLevel))
tmpUserData.SyncAchievementAdd(cache.Src2009, &cache.UInt64Tuple{uint64(monsterLevel), uint64(1)})
//if GetMutiMonsterRewardTimes(tmpUserData) > 0 {
itemList := createItemByVector4(award)
for _, item := range itemList {
AddItem(tmpUserData, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillMutliMonster)
v.MutirMonReward = append(v.MutirMonReward, item)
}
itemList = createItemByVector4(initiatorRward)
for _, item := range itemList {
AddItem(tmpUserData, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillMutliMonster)
v.MutirMonReward = append(v.MutirMonReward, item)
}
itemList = processDropActivity(tmpUserData, int32(proto.DropActivityType_DAT_KillMuliMonster), 0, 1)
for _, item := range itemList {
AddItem(tmpUserData, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcDropActivity)
v.MutirMonReward = append(v.MutirMonReward, item)
}
//ReduceMutiMonsterRewardTimes(tmpUserData)
//SetLastMutiMonsterRewardTime(tmpUserData, wtime.GetNow())
}
observer.ObserverSingleton.AsyncNotify(observer.MASSMutiMonsterEvent, []interface{}{monsterLevel, targetMutiMonster, attUser.GetLeagueID()})
}
//}
case targetRayolCity:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.LanguageID = proto.SetUint32(90000090)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75552) //您攻击了@0@
if isMultiuserAtk {
atkBattleNotice.LanguageID = proto.SetUint32(75556) //您集结攻击了@0@
}
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserAtk {
targetBattleNotice.LanguageID = proto.SetUint32(75622) //$0$集结攻击了您的@0@
} else {
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
if isMultiuserAtk {
targetSubBattleNotice.LanguageID = proto.SetUint32(75599) //$0$集结攻击了您援助的$1$
}
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
if isWin {
processMiracleWarEvent(attUser, GetcityID(worldAssetData))
if defUser != nil {
tips := common.CreateTips(75644, attUser.GetLeagueName(), uint32(csvWorldConfig.Name))
cache.Instance_GlobalAssetChat.AddLanguageIdGlobalMessage(tips)
go func() {
content := fmt.Sprintf("[%d][%s][%s][%s][%d]", 75573, attUser.GetUserName(), attUser.GetLeagueName(), defUser.GetLeagueName(), csvWorldConfig.Name)
//cache.Instance_GlobalAssetChat.AddSystemChat(int32(proto.ChatChannelType_CT_ALLIANCE), attUser.GetLeagueID(), content)
sendLeagueSystemMsg(attUser.GetLeagueID(), content)
content = fmt.Sprintf("[%d][%s][%s][%s][%d]", 75574, attUser.GetUserName(), defUser.GetLeagueName(), attUser.GetLeagueName(), csvWorldConfig.Name)
//cache.Instance_GlobalAssetChat.AddSystemChat(int32(proto.ChatChannelType_CT_ALLIANCE), defUser.GetLeagueID(), content)
sendLeagueSystemMsg(defUser.GetLeagueID(), content)
}()
}
}
for _, v := range battleReport.GetAtkInfo() {
if nil == v.GetCommanderReport() {
continue
}
tmpUser := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == tmpUser {
continue
}
observer.ObserverSingleton.AsyncNotify(observer.AddMiracleWarRecordEvent, []interface{}{int32(1), tmpUser, defUser})
}
// 重新计算大奇迹, 城市容量
calcBigMiracleGarrsonCapAfterBattle(worldAssetData)
case targetLeagueCenter:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.LanguageID = proto.SetUint32(90000090)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75552) //您攻击了@0@
if isMultiuserAtk {
atkBattleNotice.LanguageID = proto.SetUint32(75556) //您集结攻击了@0@
}
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserAtk {
targetBattleNotice.LanguageID = proto.SetUint32(75622) //$0$集结攻击了您的@0@
} else {
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
if isMultiuserAtk {
targetSubBattleNotice.LanguageID = proto.SetUint32(75599) //$0$集结攻击了您援助的$1$
}
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
case targetWarCity, targetCity:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.LanguageID = proto.SetUint32(90000090)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75552) //您攻击了@0@
if isMultiuserAtk {
atkBattleNotice.LanguageID = proto.SetUint32(75556) //您集结攻击了@0@
}
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserAtk {
targetBattleNotice.LanguageID = proto.SetUint32(75622) //$0$集结攻击了您的@0@
} else {
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
if isMultiuserAtk {
targetSubBattleNotice.LanguageID = proto.SetUint32(75599) //$0$集结攻击了您援助的$1$
}
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
if isWin {
DelWarCityData(actionDataAsset.Actiondata.GetEndTileID(), defInfo.GetActionID())
if AddWarCityData(actionDataAsset) != 0 {
unitChannel = oss.UnitChangeTypeCityWar
}
}
AddWarCityKill(actionDataAsset.Actiondata.GetEndTileID(), actionDataAsset.Actiondata.GetActionid(), kill)
AddWarCityKill(actionDataAsset.Actiondata.GetEndTileID(), defInfo.GetActionID(), defkill)
CountWarCityData(cid)
case targetBestationed:
atkTitleTips.LanguageID = proto.SetUint32(90000012)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 20000212)
atkTitleTips.ParaString = append(atkTitleTips.ParaString, defUser.GetUserName())
defTitleTips.LanguageID = proto.SetUint32(90000011)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 20000212)
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75553) //您攻击了$0$的@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, 20000212)
if defUser != nil {
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, defUser.GetUserName())
}
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, 20000212)
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if isWin {
DelWarCityData(actionDataAsset.Actiondata.GetEndTileID(), defInfo.GetActionID())
if AddWarCityData(actionDataAsset) != 0 {
unitChannel = oss.UnitChangeTypeCityWar
}
}
AddWarCityKill(actionDataAsset.Actiondata.GetEndTileID(), actionDataAsset.Actiondata.GetActionid(), kill)
AddWarCityKill(actionDataAsset.Actiondata.GetEndTileID(), defInfo.GetActionID(), defkill)
CountWarCityData(cid)
case targetMine, targetMineGem:
atkTitleTips.LanguageID = proto.SetUint32(90000012)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 20000211)
if defUser == nil {
atkTitleTips.ParaString = append(atkTitleTips.ParaString, "")
} else {
atkTitleTips.ParaString = append(atkTitleTips.ParaString, defUser.GetUserName())
}
defTitleTips.LanguageID = proto.SetUint32(90000011)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 20000211)
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75553) //您攻击了$0$的@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, 20000211)
if nil != defUser {
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, defUser.GetUserName())
}
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, 20000211)
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if isWin {
//worldAssetData.DeleteStatus(proto.WorldDataStatus_WDS_Work)
processCollectionBattleAtkWin(targetType, attUser, attActionUnitMap, defActionUnitMap, worldAssetData, isWin)
} else {
// 重新计算采矿时间
processBattleResultOnMine(actionDataAsset, worldAssetData, isWin)
}
}
ossBattleType := oss.OBT_Monster
ossFiledType := uint32(1)
if len(battleReport.AtkInfo) > 1 || len(battleReport.DefInfo) > 1 {
ossFiledType = 2
}
mailType := uint32(proto.MailType_MT_BATTLE)
if targetMonsterEx == targetType {
mailType = uint32(proto.MailType_MT_MONSTER_EX)
}
//发送防守方的邮件
defBattleReport := proto.Clone(battleReport).(*proto.ST_BattleReport_PB)
defBattleReport.IsWin = proto.SetBool(!isWin)
strInfo := string(proto.Marshal(battleInfo))
SFUID := common.GetSFUID()
strSFUID := strconv.FormatInt(SFUID, 10)
for _, v := range battleReport.DefInfo {
tmpUserInfo := cache.GetCharinfo(v.CommanderReport.GetUid())
if tmpUserInfo == nil {
continue
}
ossBattleType = oss.OBT_PVP
//攻打玩家城市,对发送给主城玩家和支援玩家的邮件标题做区分
//带头大哥和小弟的战斗提示框不同
if true == v.GetIsBigBrother() || targetType != targetMainCity {
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), defTitleTips, defTitleTips,
string(proto.Marshal(defBattleReport)), strSFUID)
if v.GetIsBigBrother() {
targetBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetBattleNotice)
}
} else {
targetSubBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetSubBattleNotice)
}
}
} else {
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), defSubTitleTips, defSubTitleTips,
string(proto.Marshal(defBattleReport)), strSFUID)
targetSubBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetSubBattleNotice)
}
}
newOssBattleRecord(tmpUserInfo, ossBattleType, !isWin, 0, ossFiledType, targetType,
actionDataAsset.Actiondata.GetEndTileID(), v.GetHeroListReport(), v.GetUnitListReport())
for _, u := range v.GetUnitListReport() {
newOssUnitChange(tmpUserInfo, uint32(unitChannel), u.GetUnitID(), int32(u.GetDeath()), int32(u.GetInjured()))
}
}
//送攻击方的邮件
atkBattleReport := proto.Clone(battleReport).(*proto.ST_BattleReport_PB)
atkBattleReport.IsWin = proto.SetBool(isWin)
//单人小怪、多人召唤怪不论输赢,永远有邮件,但是没战斗回放
if false == hasMailReport && targetType != targetMonsterEx && targetType != targetSummonMutiMonster {
atkBattleReport = &proto.ST_BattleReport_PB{
IsWin: proto.SetBool(isWin),
}
battleInfo = nil
atkBattleNotice.IsHaveBattleInfo = proto.SetBool(false)
// 暂时添加为测试英雄技能
//atkBattleNotice.IsHaveBattleInfo = proto.SetBool(true)
}
monRes := 1
if !isWin {
monRes = 0
}
if targetType == targetMainCity && battleInfo.GetIsAtkWin() {
attUser.UpdateFeedback(true, uint32(0), uint32(0))
}
for _, v := range battleReport.AtkInfo {
tmpUserInfo := cache.GetCharinfo(v.CommanderReport.GetUid())
if tmpUserInfo == nil {
continue
}
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), atkTitleTips, atkMutiMonsterContent,
string(proto.Marshal(atkBattleReport)), strSFUID)
atkBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, atkBattleNotice)
}
newOssBattleRecord(tmpUserInfo, ossBattleType, isWin, 0, ossFiledType, targetType,
actionDataAsset.Actiondata.GetEndTileID(), v.GetHeroListReport(), v.GetUnitListReport())
for _, u := range v.GetUnitListReport() {
newOssUnitChange(tmpUserInfo, uint32(unitChannel), u.GetUnitID(), int32(u.GetDeath()), int32(u.GetInjured()))
}
if targetType == targetMutiMonster || targetType == targetMonsterEx || targetType == targetSummonMutiMonster {
ossMultiMonsterBattle(tmpUserInfo, worldAssetData, monRes, v.GetHeroListReport(), v.GetUnitListReport(), award, attUser.GetUid(), atkUsers, targetType)
}
}
//清除体力返还(主要针对集结怪)
if battleRlt != battleRlt_Error && actionDataEntry.GetCostSta() > 0 {
actionDataEntry.CostSta = proto.SetUint64(0)
for _, v := range actionDataEntry.GetChildrenID() {
tmpactiondata := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpactiondata != nil && tmpactiondata.Actiondata.GetCostSta() > 0 {
tmpactiondata.Actiondata.CostSta = proto.SetUint64(0)
}
}
}
// 增加战斗日志
if attUser != nil && defUser != nil {
if attUser.GetLeagueID() != 0 || defUser.GetLeagueID() != 0 {
logEntry := createLeagueBattleLog(attUser, defUser, isWin, isMultiuserAtk)
if attUser.GetLeagueID() != 0 {
if cache.InstanceGlobalAssetLeagueBattleLog.AddLeagueBattleLog(attUser.GetLeagueID(), logEntry) {
NotifyLeagueBattleLog(attUser.GetLeagueID())
}
}
if defUser.GetLeagueID() != 0 {
if cache.InstanceGlobalAssetLeagueBattleLog.AddLeagueBattleLog(defUser.GetLeagueID(), proto.Clone(logEntry).(*proto.ST_LeagueBattle_Log_Entry)) {
NotifyLeagueBattleLog(defUser.GetLeagueID())
}
}
}
}
}
func NotifyLeagueBattleLog(lid uint64) {
memberIds := cache.Instance_GlobalAssetLeague.GetLeagueMemberIds(lid)
for _, id := range memberIds {
if cache.Sessionkey.IsRealOnline(id) {
userData := cache.GetCharinfo(id)
if userData != nil {
userData.AddLeagueBattleLogCount()
}
}
}
}
func createLeagueBattleLog(atkUser, defUser *cache.Info, isWid, isMulti bool) *proto.ST_LeagueBattle_Log_Entry {
atkInfo := &proto.ST_LeagueBattle_User{
Lid: proto.SetUint64(atkUser.GetLeagueID()),
UserName: proto.SetString(atkUser.GetUserName()),
Avatar: proto.SetString(atkUser.GetAvatar()),
AvatarBoxID: proto.SetUint32(atkUser.GetAvatarBoxId()),
AvatarID: proto.SetString(atkUser.GetLordIcon()),
LeagueShortName: proto.SetString(atkUser.GetLeagueShortName()),
Uid: proto.SetUint64(atkUser.GetUid()),
}
defInfo := &proto.ST_LeagueBattle_User{
Lid: proto.SetUint64(defUser.GetLeagueID()),
UserName: proto.SetString(defUser.GetUserName()),
Avatar: proto.SetString(defUser.GetAvatar()),
AvatarBoxID: proto.SetUint32(defUser.GetAvatarBoxId()),
AvatarID: proto.SetString(defUser.GetLordIcon()),
LeagueShortName: proto.SetString(defUser.GetLeagueShortName()),
Uid: proto.SetUint64(defUser.GetUid()),
}
logEntry := &proto.ST_LeagueBattle_Log_Entry{
Attacker: atkInfo,
Defer: defInfo,
IsMulti: proto.SetBool(isMulti),
IsWin: proto.SetBool(isWid),
Times: proto.SetInt32(1),
Timestamp: proto.SetUint64(wtime.GetNow()),
}
return logEntry
}
func getBigBrother(battleReport []*proto.ST_BattleReportDetail_PB) *proto.ST_BattleReportDetail_PB {
for _, v := range battleReport {
if v.GetIsBigBrother() {
return v
}
}
return nil
}
/**
@brief 处理资源矿和主城战的资源掠夺逻辑
*/
func genGrabResource(attUserData, defUserData *cache.Info, units *proto.ST_UnitAsset_PB,
actionUnitMap map[uint64]*proto.ST_UnitAsset_PB, win bool, targetType uint32, heroid []uint32, wdataid uint64) (*proto.ST_CashAsset_PB, map[uint64]*proto.ST_CashAsset_PB) {
mapresource := make(map[uint64]*proto.ST_CashAsset_PB)
resource := common.NewCashAsset()
if !win {
return resource, mapresource
}
if defUserData == nil {
return resource, mapresource
}
var c1, c2, c3, c4, c5, c100 uint64
switch targetType {
case targetMainCity:
c1, c2, c3, c4, c5 = getCanLostResource(defUserData)
case targetMine, targetMineGem:
c1, c2, c3, c4, c5, c100 = getCanGrabResourceOnMine(wdataid)
default:
return resource, mapresource
}
weight := getWeightByUnitAsset(attUserData, heroid, units)
if weight == 0 {
return resource, mapresource
}
tmpcashAsset := &proto.ST_CashAsset_PB{
Cash1: proto.SetUint64(c1),
Cash2: proto.SetUint64(c2),
Cash3: proto.SetUint64(c3),
Cash4: proto.SetUint64(c4),
Cash5: proto.SetUint64(c5),
Cash100: proto.SetUint64(c100),
}
totalcanlost := countCashWeightByNum(tmpcashAsset)
if totalcanlost <= 0 {
totalcanlost = 1
}
var robCash1, robCash2, robCash3, robCash4, robCash5, robCash100 uint64 = 0, 0, 0, 0, 0, 0
if weight < totalcanlost {
robCash1 = c1 * weight / totalcanlost
robCash2 = c2 * weight / totalcanlost
robCash3 = c3 * weight / totalcanlost
robCash4 = c4 * weight / totalcanlost
robCash5 = c5 * weight / totalcanlost
robCash100 = c100 * weight / totalcanlost
} else {
robCash1 = c1
robCash2 = c2
robCash3 = c3
robCash4 = c4
robCash5 = c5
robCash100 = c100
}
resource.Cash1 = proto.SetUint64(robCash1)
resource.Cash2 = proto.SetUint64(robCash2)
resource.Cash3 = proto.SetUint64(robCash3)
resource.Cash4 = proto.SetUint64(robCash4)
resource.Cash5 = proto.SetUint64(robCash5)
resource.Cash100 = proto.SetUint64(robCash100)
if targetType == targetMainCity {
defUserData.ReduceCashAsset(resource, oss.ReduceCashScrTypePVPGrab)
}
for k, v := range actionUnitMap {
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(k)
if actionData == nil {
continue
}
tmpUserData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if tmpUserData == nil {
continue
}
tmpWeight := getWeightByUnitAsset(tmpUserData, actionData.Actiondata.GetHeroIDList(), v)
tmpresource := &proto.ST_CashAsset_PB{
Cash100: proto.SetUint64(robCash100 * tmpWeight / weight),
Cash1: proto.SetUint64(robCash1 * tmpWeight / weight),
Cash2: proto.SetUint64(robCash2 * tmpWeight / weight),
Cash3: proto.SetUint64(robCash3 * tmpWeight / weight),
Cash4: proto.SetUint64(robCash4 * tmpWeight / weight),
Cash5: proto.SetUint64(robCash5 * tmpWeight / weight),
}
mapresource[k] = tmpresource
actionData.SetAppedData(encodeActionAppendData(actionData.Actiondata.GetAppenddata(), "resource", string(proto.Marshal(tmpresource))))
}
return resource, mapresource
}
/**
@brief 处理玩家统计信息
*/
func processStatisticsAsset(isWin bool, targetType uint32, atkUser, defUser *cache.Info, isCapCommander bool, battleReport []*proto.ST_BattleReportDetail_PB, isAtk bool, pvp bool) (
uint64, map[uint64]*proto.ST_UnitAsset_PB) {
if targetType == targetMonster ||
targetType == targetMutiMonster ||
targetType == targetSummonMutiMonster ||
targetType == targetMonsterEx {
return 0, nil
}
if isAtk && atkUser == nil {
return 0, nil
}
commanderExpParm := common.ParseStringToUint32List(
CSV.GetGameConfigValueString("COMMANDER_EXP_PARM"))
heroExpParm := common.ParseStringToUint32List(
CSV.GetGameConfigValueString("HERO_EXP_PARM"))
killsInfo := make(map[uint64]*proto.ST_UnitAsset_PB, 2)
WarCityKill := uint64(0)
for k, v := range battleReport {
if v.GetCommanderReport() == nil {
continue
}
tmpUser := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == tmpUser {
continue
}
attUserStatisticsAsset := tmpUser.GetStatisticsInnerAsset()
if k == 0 {
if targetType == targetMainCity ||
targetType == targetRayolCity ||
targetType == targetLeagueCenter ||
targetType == targetWarCity {
if isWin {
if isAtk {
attUserStatisticsAsset.UpdateAttackWin(1)
} else {
attUserStatisticsAsset.UpdateDefenceFail(1)
/*if isCapCommander {
attUserStatisticsAsset.UpdateCaptiveTimes()
attUserStatisticsAsset.UpdateArrestHeroNumber(1)
}*/
}
} else {
if isAtk {
attUserStatisticsAsset.UpdateAttackFail(1)
} else {
attUserStatisticsAsset.UpdateDefenceWin(1)
//attUserStatisticsAsset.UpdateEscapeTimes()
}
}
}
}
lostPower, totalKillUnits, heroKillUnits, corpsKillUnits, lostUnits, herokillunitsCnt :=
processUnitListReport(v.GetUnitListReport(), v.GetHeroListReport())
attUserStatisticsAsset.UpdateUnitLoss(lostPower)
if pvp {
attUserStatisticsAsset.UpdateKillUnit(totalKillUnits)
}
attUserStatisticsAsset.UpdateLossUnit(lostUnits)
killsInfo[v.GetActionID()] = totalKillUnits
// 处理跨服决战死兵
processTransferBattleDeathUnit(tmpUser, defUser, v.GetUnitListReport())
//攻击成就
killNum := uint64(0)
unitNumByLv := make(map[uint32]uint32, 0)
unitNumByLv2 := make(map[uint32]uint32, 0)
unitNumByLv3 := make(map[uint32]uint32, 0)
for _, v := range totalKillUnits.GetUnits() {
unitEntry := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitEntry != nil {
unitType := unitEntry.Type
if int64(proto.UnitType_UT_NORMAL_BEGIN) < unitType && int64(proto.UnitType_UT_NORMAL_END) > unitType {
//击杀士兵成就[6501701]
tmpUser.SyncAchievementAdd(cache.LJJSSBEvent, &cache.UInt64Tuple{uint64(unitEntry.UnitLevel), v.GetUnitnum()})
}
unitNumByLv[uint32(unitEntry.UnitLevel)] = unitNumByLv[uint32(unitEntry.UnitLevel)] + uint32(v.GetUnitnum())
}
killNum += v.GetUnitnum()
if pvp {
observer.ObserverSingleton.AsyncNotify(observer.PVPKillEvevt, []interface{}{tmpUser, uint32(unitEntry.UnitLevel), uint32(v.GetUnitnum()), isWin, defUser})
}
}
for _, v := range lostUnits.Units {
unitEntry := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitEntry != nil {
if pvp {
observer.ObserverSingleton.AsyncNotify(observer.PVPBeKilledEvent, []interface{}{tmpUser, uint32(unitEntry.UnitLevel), uint32(v.GetUnitnum()), defUser})
}
}
}
for _, v := range heroKillUnits.GetUnits() {
unitEntry := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitEntry != nil {
unitNumByLv2[uint32(unitEntry.UnitLevel)] = unitNumByLv2[uint32(unitEntry.UnitLevel)] + uint32(v.GetUnitnum())
}
}
for _, v := range corpsKillUnits.GetUnits() {
unitEntry := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitEntry != nil {
unitNumByLv3[uint32(unitEntry.UnitLevel)] = unitNumByLv3[uint32(unitEntry.UnitLevel)] + uint32(v.GetUnitnum())
}
}
commanderExp := uint64(0)
heroExp := uint64(0)
//通过英雄击杀来计算英雄经验
for k, v := range unitNumByLv2 {
num := float64(v)
heroExp += uint64(float64(heroExpParm[k-1]) / 10000 * num)
}
//通过军团击杀来计算指挥官经验
for k, v := range unitNumByLv3 {
num := float64(v)
commanderExp += uint64(float64(commanderExpParm[k-1]) / 10000 * num)
}
v.CommanderReport.AddExp = proto.SetUint64(commanderExp)
atkUser.AddExp(commanderExp)
var heroLevelUp []uint32
for _, heroReport := range v.GetHeroListReport() {
atkUser.WithHeroAsset(true, heroReport.GetId(), func(heroAsset *proto.ST_HeroEntry_PB) bool {
oldLevel := heroReport.GetLevel()
heroID := heroReport.GetId()
flag := false
fixExp := uint64(0)
flag, fixExp = atkUser.CanAddHeroExp(heroID, heroExp)
if flag {
atkUser.AddHeroExp(heroID, fixExp)
heroReport.AddExp = proto.SetUint64(fixExp)
}
if oldLevel != heroAsset.GetLevel() {
heroLevelUp = append(heroLevelUp, heroAsset.GetId())
heroReport.Level = proto.SetUint32(heroAsset.GetLevel())
heroReport.IsLevelUp = proto.SetBool(true)
}
//heroReport.Exp = proto.SetUint64(heroReport.GetExp())
return false
})
}
atkUser.AddLevelUpHeroList(heroLevelUp)
if (isAtk && !isWin) || (!isAtk && isWin) {
defeatRecoup(tmpUser, lostUnits)
}
//通知指挥官杀敌数量更新
if pvp {
observer.ObserverSingleton.AsyncNotify(observer.CommanderKilledUpgradeEvent, []interface{}{tmpUser, killNum})
observer.ObserverSingleton.AsyncNotify(observer.HeroKilledUpgradeEvent, []interface{}{tmpUser, herokillunitsCnt})
}
WarCityKill += killNum
}
return WarCityKill, killsInfo
}
func processTransferBattleDeathUnit(atkUser *cache.Info, defUser *cache.Info, unitReport []*proto.ST_UnitBattleReport_PB) {
if nil == atkUser || defUser == nil {
return
}
atkUser.WithTransferBattleAsset(false, func(asset *proto.ST_Asset_TransferBattle_PB) bool {
if asset.GetStage() == uint32(proto.ActivityStage_AS_ProcessingStage) {
if tbGroupInfo != nil {
if (tbGroupInfo.GetSid1() == defUser.GetSid() && tbGroupInfo.GetSid2() == atkUser.GetSid()) ||
(tbGroupInfo.GetSid1() == atkUser.GetSid() && tbGroupInfo.GetSid2() == defUser.GetSid()) {
deathUnits := &proto.ST_UnitAsset_PB{}
for _, unit := range unitReport {
if unit.GetDeath() > 0 {
deathUnits.Units = append(deathUnits.Units, &proto.ST_Unit_PB{
Unitnum: proto.SetUint64(uint64(unit.GetDeath())),
Unitid: unit.UnitID,
})
}
}
if asset.DeathUnits == nil {
asset.DeathUnits = &proto.ST_UnitAsset_PB{}
}
common.CombineUnitAsset(asset.DeathUnits, deathUnits)
return true
}
}
}
return false
})
}
func processUnitListReport(unitInfs []*proto.ST_UnitBattleReport_PB, heroBattleList []*proto.ST_HeroBattleReport_PB) (
uint64, *proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB, map[uint32]uint64) {
power := uint64(0)
totalKillUnits := &proto.ST_UnitAsset_PB{} //总击杀
heroKillUnits := &proto.ST_UnitAsset_PB{} //英雄击杀
corpsKillUnits := &proto.ST_UnitAsset_PB{} //军团击杀
lostUnits := &proto.ST_UnitAsset_PB{}
heroKillUnitsCnt := make(map[uint32]uint64, 5) //每个英雄击杀士兵数量
//英雄
for _, heroBattle := range heroBattleList {
killUnitAsset := &proto.ST_UnitAsset_PB{}
for _, killUnit := range heroBattle.KillList {
killUnitAsset.Units = append(killUnitAsset.Units, killUnit)
num, ok := heroKillUnitsCnt[heroBattle.GetId()]
if !ok {
heroKillUnitsCnt[heroBattle.GetId()] = uint64(killUnit.GetUnitnum())
} else {
heroKillUnitsCnt[heroBattle.GetId()] = uint64(killUnit.GetUnitnum()) + num
}
}
common.CombineUnitAsset(totalKillUnits, killUnitAsset)
common.CombineUnitAsset(heroKillUnits, killUnitAsset)
}
//战斗单位
for _, v := range unitInfs {
conf := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitID()))
if conf != nil {
power += uint64(conf.Power * int64(v.GetDeath()+v.GetInjured()))
}
tmpUnit := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
tmpUnit.Units = append(tmpUnit.Units, &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitID()),
Unitnum: proto.SetUint64(uint64(v.GetDeath() + v.GetInjured())),
})
common.CombineUnitAsset(lostUnits, tmpUnit)
common.CombineUnitAsset(totalKillUnits, v.GetKillList())
common.CombineUnitAsset(corpsKillUnits, v.GetKillList())
}
return power, totalKillUnits, heroKillUnits, corpsKillUnits, lostUnits, heroKillUnitsCnt
}
/**
@brief 战败补充
*/
func defeatRecoup(userData *cache.Info, lostUnits *proto.ST_UnitAsset_PB) {
trueLost := uint64(0)
rewList := &proto.ST_CashAsset_PB{}
for _, v := range CSV.Mgr.CSV_DefeatRecoup.GetIDList() {
csvRecoup := CSV.Mgr.CSV_DefeatRecoup.GetEntryPtr(v)
if csvRecoup == nil {
continue
}
lostNum := uint64(0)
cashCost := &proto.ST_CashAsset_PB{}
recoupNeed := common.ParseStringToInt64List(csvRecoup.RewLimit)
for _, unit := range lostUnits.GetUnits() {
csvUnit := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if csvUnit == nil {
continue
}
if csvUnit.Quality != recoupNeed[0] {
continue
}
lostNum += unit.GetUnitnum()
cost := common.ParseVector4ToCashAsset(common.ParseStringToVector4(csvUnit.AssetsRequire))
common.MultiResourceAsset(cost, float64(lostNum))
common.CombineResourceAsset(cashCost, cost)
}
if lostNum < uint64(recoupNeed[1]) {
continue
}
trueLost += lostNum
common.MultiResourceAsset(cashCost, float64(csvRecoup.Recoup)/100.0)
common.CombineResourceAsset(rewList, cashCost)
}
if trueLost <= 0 {
return
}
titleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())}
contentTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())}
titleTips.LanguageID = proto.SetUint32(CSV.GetGameConfigValueUint32("DefeatRecoupText"))
contentTips.LanguageID = proto.SetUint32(CSV.GetGameConfigParamUint32("DefeatRecoupText"))
userData.AddDefeatRecoupMailAsset(uint32(proto.MailType_MT_SYSTEM), titleTips, contentTips, rewList)
}
/**
@brief 从战报中获取战斗双方的GlobalActionMap
*/
func getActionUnitMapByBattleReport(battleReport *proto.ST_BattleReport_PB) (map[uint64]*proto.ST_UnitAsset_PB, map[uint64]*proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB) {
attUnitMap := make(map[uint64]*proto.ST_UnitAsset_PB)
defUnitMap := make(map[uint64]*proto.ST_UnitAsset_PB)
attRemainUnit := &proto.ST_UnitAsset_PB{}
if battleReport == nil {
wlog.Info("getActionUnitMapByBattleReport battleReport nil")
return attUnitMap, defUnitMap, attRemainUnit
}
for _, v := range battleReport.GetAtkInfo() {
units := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
for _, v1 := range v.GetUnitListReport() {
newUnit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v1.GetUnitID()),
Unitnum: proto.SetUint64(uint64(v1.GetSurvival())),
}
units.Units = common.CombineUnit(units.Units, newUnit)
}
attUnitMap[uint64(v.GetActionID())] = units
common.CombineUnitAsset(attRemainUnit, units)
}
for _, v := range battleReport.GetDefInfo() {
units := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
for _, v1 := range v.GetUnitListReport() {
newUnit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v1.GetUnitID()),
Unitnum: proto.SetUint64(uint64(v1.GetSurvival())),
}
units.Units = common.CombineUnit(units.Units, newUnit)
if v.GetActionID() == 0 && v.GetCommanderReport() != nil {
tmpUser := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if tmpUser != nil {
tmpUser.DeleteUnitAsset(v1.GetUnitID(), uint64(v1.GetJoin()))
}
}
}
defUnitMap[uint64(v.GetActionID())] = units
}
return attUnitMap, defUnitMap, attRemainUnit
}
/**
@brief 处理战斗后的GlobalAction
*/
func processGlobalActionAfterBattle(actionUintMap map[uint64]*proto.ST_UnitAsset_PB, wdata *cache.WorldDataEntry,
targetType uint32, userData *cache.Info, actionType uint32, returnUnitsList []*proto.ST_ReturnUnits_PB, win bool, isAtt bool) {
x, y, _ := common.ConvertIdToCoordinate(wdata.GetWorldData().SimpleEntry.GetTileId())
cid, _ := GetWarCityFromPos(x, y)
if !isAtt && win && wdata != nil {
// 防守失败
if targetType == targetRayolCity || cid != 0 {
actionIds := wdata.CopyGActionList()
if len(actionIds) > 0 {
actionAsset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionIds[0])
if actionAsset != nil {
recvActionIds := actionAsset.Actiondata.GetRecvActionIDList()
//获取出针对次地块的攻击、侦察、集结、援助行为
//然后从撤军的玩家的预警雷达中删除
for _, recvActionId := range recvActionIds {
otherActionAsset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(recvActionId)
if nil == otherActionAsset {
continue
}
actionType = otherActionAsset.Actiondata.GetActiontype()
if actionType == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionType == uint32(proto.ActionType_AT_WORLDMAP_SPYINTO) ||
actionType == uint32(proto.ActionType_AT_WORLDMAP_MASS) ||
actionType == uint32(proto.ActionType_AT_WORLDMAP_GARRISON) {
deleteRadar(otherActionAsset.Actiondata)
}
}
}
}
}
}
for k, v := range actionUintMap {
if k == 0 {
if targetType == targetMainCity && !isAtt {
userData.AddUnitAssets(v)
userData.CalcPower()
}
continue
}
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(k)
if actionData == nil {
continue
}
userData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if userData == nil {
continue
}
//进攻方返还多人战斗中死亡的兵力
if (targetType == targetMutiMonster || targetType == targetMonsterEx || targetType == targetSummonMutiMonster) && isAtt && nil != returnUnitsList {
for _, returnUnitInfo := range returnUnitsList {
if k != returnUnitInfo.GetActionID() {
continue
}
common.CombineUnitAsset(v, returnUnitInfo.ReturnUnitInfo)
returnUnitInfo.ReturnUnitInfo = &proto.ST_UnitAsset_PB{}
}
}
//deleteRadar(actionData.Actiondata)
if countUnitNum(v) <= 0 {
for _, herid := range actionData.Actiondata.GetHeroIDList() {
setHeroStatus(userData, herid, proto.HeroStatus_HS_NORMAL)
}
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_GARRISON) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_COLLECT) {
RadarCheckOtherGAction(actionData, true)
cache.Instance_GlobalAssetGlobalAction.DeleteGlobalAction(k)
wdata.UnBindGlobalActionId(actionData.Actiondata.GetActionid())
userData.RemoveGlobalActionID(actionData.Actiondata.GetActionid())
} else if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_BESTATIONED) {
RadarCheckOtherGAction(actionData, true)
cache.Instance_GlobalAssetGlobalAction.DeleteGlobalAction(k)
userData.RemoveGlobalActionID(actionData.Actiondata.GetActionid())
} else {
actionData.UpdateUnitAsset(v)
}
} else {
actionData.UpdateUnitAsset(v)
switch targetType {
case targetWarCity:
if isAtt {
// 进攻方胜利
if win {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
convertActionToGarrison(actionData, wdata)
processCityWarAsset(actionData)
}
}
}
case targetLeagueCenter:
if isAtt {
// 进攻方胜利
if win {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
GarrisonToLeagueCenter(actionData, wdata)
wdata.UpdateOwner(userData.GetLeagueID(), userData.GetUid())
TimeLeagueCenter(wdata) //驻扎后开始计算时间
}
}
}
case targetRayolCity:
if isAtt {
// 进攻方胜利
if win {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
convertActionToGarrison(actionData, wdata)
cityAsset := wdata.GetWorldData().DetailEntry.GetDetail_City()
if cityAsset != nil {
cityAsset.NpcUnits = &proto.ST_UnitAsset_PB{}
wdata.Dirty()
}
}
}
}
case targetBestationed:
if isAtt {
// 进攻方胜利
if win {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) {
garrisonToCityWarBestationed(actionData) //攻击水泥地后驻扎
}
}
}
case targetMine, targetMineGem:
if !isAtt {
// 采集防守失败
if win {
actionData.UpdateStage(wtime.GetNow(), actionData.Actiondata.GetTotaltime(), uint32(proto.MapStageType_MST_BACK))
wdata.UnBindGlobalActionId(k)
}
}
default:
}
}
userData.CalcPower()
}
if !isAtt && win && wdata != nil {
// 防守失败
defenderFailed(targetType, cid, wdata)
}
}
//进攻方和防守方都死完了,判定为防守防胜,由于防守方没有兵了,要自动撤军
func checkAtkDefAllDieout(atk, def map[uint64]*proto.ST_UnitAsset_PB, targetType uint32, wdata *cache.WorldDataEntry) {
for _, v := range atk {
for _, unit := range v.Units {
if unit.GetUnitnum() > 0 {
return
}
}
}
for _, v := range def {
for _, unit := range v.Units {
if unit.GetUnitnum() > 0 {
return
}
}
}
if wdata != nil {
x, y, _ := common.ConvertIdToCoordinate(wdata.GetWorldData().SimpleEntry.GetTileId())
cid, _ := GetWarCityFromPos(x, y)
defenderFailed(targetType, cid, wdata)
}
}
func defenderFailed(targetType, cid uint32, wdata *cache.WorldDataEntry) {
if targetType == targetRayolCity || targetType == targetLeagueCenter || targetType == targetBestationed || cid != 0 {
//CountLeagueCenter(wdata) //返回前计算
actionIds := wdata.CopyGActionList()
if len(actionIds) > 0 {
for _, v := range actionIds {
recallArmy(v, false)
}
}
}
if targetType == targetMine && len(wdata.GetGActionList()) == 0 {
wdata.UpdateOwner(0, 0)
}
if targetType == targetBestationed {
cache.Instance_GlobalAssetWorldData.DeleteDataEntry(wdata.GetWorldDataID(), false)
}
}
/**
@brief 生成英雄报告
*/
func createHeroReport(userInfo *cache.Info, heroID uint32, battleInfo *proto.ST_BattleInfo_PB, isAtk bool) (bool, *proto.ST_HeroBattleReport_PB) {
report := &proto.ST_HeroBattleReport_PB{}
if nil == userInfo || uint32(0) == heroID || nil == battleInfo {
return false, report
}
userInfo.WithHeroAsset(true, heroID, func(heroAsset *proto.ST_HeroEntry_PB) bool {
report.Id = proto.SetUint32(heroAsset.GetId())
report.Level = proto.SetUint32(heroAsset.GetLevel())
report.Star = proto.SetUint32(heroAsset.GetStar())
report.Power = proto.SetUint64(heroAsset.GetPower())
report.IsLevelUp = proto.SetBool(false)
report.SkillList = make([]*proto.ST_HeroSkill_PB, 0)
for _, v := range heroAsset.GetSkillList() {
skill := &proto.ST_HeroSkill_PB{
SkillLogicType: proto.SetUint32(v.GetSkillLogicType()),
SkillID: proto.SetUint32(v.GetSkillID()),
}
report.SkillList = append(report.SkillList, skill)
}
report.BranchValue = make([]uint32, 0)
for _, v := range heroAsset.GetBranchValue() {
report.BranchValue = append(report.BranchValue, v)
}
for _, v := range battleInfo.RoundInfo {
var roundInfo *proto.ST_RoundBaseInfo_PB
if isAtk {
roundInfo = v.AtkRoundInfo
} else {
roundInfo = v.DefRoundInfo
}
for _, heroBattleInfo := range roundInfo.HeroList {
if heroBattleInfo.GetHeroID() != heroID {
continue
}
//计算技能释放次数
if heroBattleInfo.GetUseOrder() != 0 {
report.UseSkillTimes = proto.SetUint32(report.GetUseSkillTimes() + 1)
}
//击杀单位数量
report.DestoryUnitCount = proto.SetUint64(report.GetDestoryUnitCount() + countUnitsNumFromList(heroBattleInfo.KillList))
//治疗单位数量
report.RecoveryUnitCount = proto.SetUint64(report.GetRecoveryUnitCount() + countUnitsNumFromList(heroBattleInfo.RecoveryList))
for _, killUnit := range heroBattleInfo.KillList {
tmpUnit := proto.Clone(killUnit).(*proto.ST_Unit_PB)
report.KillList = append(report.KillList, tmpUnit)
}
}
}
return false
})
return true, report
}
/**
@brief 生成战斗报告详细数据
*/
func createReportDetail(targetType uint32, worldAssetData *cache.WorldDataEntry, battleInfo *proto.ST_BattleInfo_PB,
orgiUnitAssetMap map[uint64]*stUserUnitInfo, unitBattleInfoMap map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, isAtk bool) ([]*proto.ST_BattleReportDetail_PB, *proto.ST_PowerReport_PB) {
if nil == battleInfo || nil == orgiUnitAssetMap {
return nil, nil
}
totalLossPower := int64(0)
totalStartPower := int64(0)
reportDetailList := make([]*proto.ST_BattleReportDetail_PB, 0)
powerReport := &proto.ST_PowerReport_PB{}
for actionID, userUnitInfo := range orgiUnitAssetMap {
var actionAsset *cache.GlobalActionEntry
if 0 == actionID {
//玩家主城的拥有者
} else {
actionAsset = cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionID)
}
var userInfo *cache.Info
if actionAsset != nil && actionAsset.Actiondata != nil {
userInfo = cache.GetCharinfo(actionAsset.Actiondata.GetUid())
} else if nil != worldAssetData {
userInfo = cache.GetCharinfo(worldAssetData.GetWorldDataOwner())
}
if actionAsset != nil && actionAsset.Actiondata.GetMacMonsterId() > 0 && userInfo == nil {
userInfo = cache.GetCharinfo(worldAssetData.GetWorldDataOwner())
}
battleReportDetail := &proto.ST_BattleReportDetail_PB{
IsBigBrother: proto.SetBool(userUnitInfo.isBigBrother),
ActionID: proto.SetUint64(actionID),
}
battleReportDetail.CommanderReport = &proto.ST_BattleCommanderSimpleInfo_PB{}
if nil != userInfo {
if userInfo.GetCommanderStatus() == uint32(proto.HeroStatus_HS_IMPRISONED) {
battleReportDetail.IsArrest = proto.SetBool(true)
}
//指挥官信息
battleReportDetail.CommanderReport.Uid = proto.SetUint64(userInfo.GetUid())
battleReportDetail.CommanderReport.Name = proto.SetString(userInfo.GetUserName())
battleReportDetail.CommanderReport.LeagueName = proto.SetString(userInfo.GetLeagueName())
//英雄
if actionAsset != nil && actionAsset.Actiondata != nil {
for _, heroID := range actionAsset.Actiondata.HeroIDList {
if ok, heroBattleReport := createHeroReport(userInfo, heroID, battleInfo, isAtk); ok {
battleReportDetail.HeroListReport = append(battleReportDetail.HeroListReport, heroBattleReport)
}
}
} else {
//守城英雄ID
userInfo.ForeachHero(true, func(heroAsset *proto.ST_HeroEntry_PB) bool {
if heroAsset == nil {
return false
}
if heroAsset.GetHeroStatus() == uint32(proto.HeroStatus_HS_DEFENSE) {
if ok, heroBattleReport := createHeroReport(userInfo, heroAsset.GetId(), battleInfo, isAtk); ok {
battleReportDetail.HeroListReport = append(battleReportDetail.HeroListReport, heroBattleReport)
}
}
return true
})
}
//天赋
battleReportDetail.NaturalGift = make([]uint32, 0)
userInfo.ForeachTalentAsset(true, func(rid uint32) bool {
if conf := CSV.Mgr.CSV_Talent.GetEntryPtr(int64(rid)); conf != nil {
if conf.TalentType == 1 {
battleReportDetail.NaturalGift = append(battleReportDetail.NaturalGift, rid)
}
}
return true
})
//科技等级
battleReportDetail.TechnologyLevel = make([]uint32, 0)
techAsset := userInfo.GetResearchAsset()
if techAsset != nil {
for _, v := range techAsset.GetEntryList() {
battleReportDetail.TechnologyLevel = append(battleReportDetail.TechnologyLevel, v.GetRID())
}
}
//雕像
battleReportDetail.Statue = make([]*proto.ST_Simple_Statue, 0)
statueAsset := userInfo.GetStatueAsset()
if statueAsset != nil {
for _, v := range statueAsset.AssetData.StatueList {
tmpMap := common.StatueFuncArrayToMap(v.GetFuncKeyArr(), v.GetFuncValueArr())
for k2, v2 := range tmpMap {
tmpData := &proto.ST_Simple_Statue{}
tmpData.EffectType = proto.SetString(k2)
tmpData.EffectValue = proto.SetUint32(v2)
battleReportDetail.Statue = append(battleReportDetail.Statue, tmpData)
}
}
}
//装备
battleReportDetail.EquipList = make([]uint32, 0)
userInfo.WithCommanderEquipAsset(true, func(asset *cache.Asset_CommanderEquip) {
for _, v := range asset.AssetData_WearEquip {
battleReportDetail.EquipList = append(battleReportDetail.EquipList, v.GetCsvid())
}
})
if actionAsset != nil && actionAsset.Actiondata != nil {
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(actionAsset.Actiondata.GetStartTileID()))
} else {
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(worldAssetData.GetWorldDataTileID()))
}
} else if false == isAtk &&
(targetType == uint32(targetMutiMonster) || targetType == uint32(targetCity) || targetType == uint32(targetRayolCity) || targetType == uint32(targetLeagueCenter) || targetType == uint32(targetWarCity)) {
//把多人野怪的坐标记录到指挥官信息里
battleReportDetail.CommanderReport = &proto.ST_BattleCommanderSimpleInfo_PB{}
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(worldAssetData.GetWorldDataTileID()))
}
if isAtk && actionAsset != nil && actionAsset.Actiondata.GetMacMonsterId() > 0 {
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(actionAsset.Actiondata.GetStartTileID()))
}
//战斗力
battleReportDetail.TotalPower = proto.SetInt64(userUnitInfo.totalPower)
totalStartPower += userUnitInfo.totalPower
//战斗单位
powerlost := int64(0)
if unitBattleInfoMap, ok := unitBattleInfoMap[actionID]; ok {
for _, unitList := range userUnitInfo.unitMap {
for _, unit := range unitList {
report := &proto.ST_UnitBattleReport_PB{}
report.UnitID = proto.SetUint32(unit.unit.GetUnitid())
report.Join = proto.SetUint32(uint32(unit.unit.GetUnitnum()))
report.Survival = proto.SetUint32(report.GetJoin())
if v, ok := unitBattleInfoMap[report.GetUnitID()]; ok {
report.Survival = proto.SetUint32(v.GetSurvival())
report.Injured = proto.SetUint32(v.GetInjured())
report.Death = proto.SetUint32(v.GetDeath())
report.Kill = proto.SetUint32(v.GetKill())
report.KillList = &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, len(v.KillList.Units)),
}
copy(report.KillList.Units, v.KillList.GetUnits())
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(report.GetUnitID()))
if nil != unitCSV {
powerlost += unitCSV.Power * int64(report.GetJoin()-report.GetSurvival())
}
}
battleReportDetail.UnitListReport = append(battleReportDetail.UnitListReport, report)
}
}
}
totalLossPower += powerlost
//城墙
battleReportDetail.WallReport = &proto.ST_WallReport_PB{
BeforeHp: proto.SetUint32(0),
AfterHp: proto.SetUint32(0),
Level: proto.SetUint32(0),
}
battleReportDetail.MutirMonReward = make([]*proto.ST_ItemEntry_PB, 0)
roundNum := len(battleInfo.RoundInfo)
if 0 != roundNum {
defRoundBaseInfo := battleInfo.RoundInfo[roundNum-1].DefRoundInfo
if nil != defRoundBaseInfo.WallHp {
battleReportDetail.WallReport.BeforeHp = proto.SetUint32(defRoundBaseInfo.WallHp.GetBeforeHp())
battleReportDetail.WallReport.AfterHp = proto.SetUint32(defRoundBaseInfo.WallHp.GetAfterHp())
battleReportDetail.WallReport.Level = proto.SetUint32(battleInfo.DefSimpleStartInfo.GetWallLevel())
}
}
reportDetailList = append(reportDetailList, battleReportDetail)
lossCount := uint32(0)
for _, v := range battleReportDetail.UnitListReport {
tmpCount := v.GetJoin() - v.GetSurvival()
lossCount += tmpCount
}
CheckAllGiftSaleCondition(userInfo, proto.GiftConditionType_GCT_LOSS_COUNT, int64(lossCount))
CheckAllGiftSaleCondition(userInfo, proto.GiftConditionType_GCT_POWER_LOSE, int64(powerlost))
}
powerReport.LossValue = proto.SetInt64(totalLossPower)
powerReport.LossRatio = proto.SetFloat32(float32(totalLossPower) / float32(totalStartPower))
powerReport.AllPower = proto.SetInt64(totalStartPower)
return reportDetailList, powerReport
}
/**
@brief 生成集结怪/单人小怪/集结召唤怪的战斗报告详细数据
*/
func createMutiMonsterReportDetail(monsterBaseData *stBattleActionBaseData, worldAssetData *cache.WorldDataEntry, battleInfo *proto.ST_BattleInfo_PB,
orgiUnitAssetMap map[uint64]*stUserUnitInfo, unitBattleInfoMap map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB) ([]*proto.ST_BattleReportDetail_PB, *proto.ST_PowerReport_PB) {
if nil == monsterBaseData || nil == battleInfo || nil == orgiUnitAssetMap {
return nil, nil
}
totalLossPower := int64(0)
totalStartPower := int64(0)
reportDetailList := make([]*proto.ST_BattleReportDetail_PB, 0)
powerReport := &proto.ST_PowerReport_PB{}
for actionID, userUnitInfo := range orgiUnitAssetMap {
battleReportDetail := &proto.ST_BattleReportDetail_PB{
IsBigBrother: proto.SetBool(true),
ActionID: proto.SetUint64(0),
}
battleReportDetail.CommanderReport = &proto.ST_BattleCommanderSimpleInfo_PB{}
if 0 == len(monsterBaseData.heroList) {
report := &proto.ST_HeroBattleReport_PB{
SkillList: make([]*proto.ST_HeroSkill_PB, 0),
BranchValue: make([]uint32, 0),
KillList: make([]*proto.ST_Unit_PB, 0),
}
battleReportDetail.HeroListReport = append(battleReportDetail.HeroListReport, report)
} else {
for _, k := range monsterBaseData.heroList {
heroID := k.heroID
report := &proto.ST_HeroBattleReport_PB{}
report.Id = proto.SetUint32(heroID)
report.Level = proto.SetUint32(k.level)
for _, v := range battleInfo.RoundInfo {
var roundInfo *proto.ST_RoundBaseInfo_PB
roundInfo = v.DefRoundInfo
for _, heroBattleInfo := range roundInfo.HeroList {
if heroBattleInfo.GetHeroID() != heroID {
continue
}
//计算技能释放次数
if heroBattleInfo.GetUseOrder() != 0 {
report.UseSkillTimes = proto.SetUint32(report.GetUseSkillTimes() + 1)
}
//击杀单位数量
report.DestoryUnitCount = proto.SetUint64(report.GetDestoryUnitCount() + countUnitsNumFromList(heroBattleInfo.KillList))
//治疗单位数量
report.RecoveryUnitCount = proto.SetUint64(report.GetRecoveryUnitCount() + countUnitsNumFromList(heroBattleInfo.RecoveryList))
for _, killUnit := range heroBattleInfo.KillList {
tmpUnit := proto.Clone(killUnit).(*proto.ST_Unit_PB)
report.KillList = append(report.KillList, tmpUnit)
}
}
}
battleReportDetail.HeroListReport = append(battleReportDetail.HeroListReport, report)
}
}
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(worldAssetData.GetWorldDataTileID()))
//战斗力
battleReportDetail.TotalPower = proto.SetInt64(userUnitInfo.totalPower)
totalStartPower += userUnitInfo.totalPower
//战斗单位
if unitBattleInfoMap, ok := unitBattleInfoMap[actionID]; ok {
for _, unitList := range userUnitInfo.unitMap {
for _, unit := range unitList {
report := &proto.ST_UnitBattleReport_PB{}
report.UnitID = proto.SetUint32(unit.unit.GetUnitid())
report.Join = proto.SetUint32(uint32(unit.unit.GetUnitnum()))
report.Survival = proto.SetUint32(report.GetJoin())
if v, ok := unitBattleInfoMap[report.GetUnitID()]; ok {
report.Survival = proto.SetUint32(v.GetSurvival())
report.Injured = proto.SetUint32(v.GetInjured())
report.Death = proto.SetUint32(v.GetDeath())
report.Kill = proto.SetUint32(v.GetKill())
report.KillList = &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, len(v.KillList.Units)),
}
copy(report.KillList.Units, v.KillList.GetUnits())
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(report.GetUnitID()))
if nil != unitCSV {
totalLossPower += unitCSV.Power * int64(report.GetJoin()-report.GetSurvival())
}
}
battleReportDetail.UnitListReport = append(battleReportDetail.UnitListReport, report)
}
}
}
//城墙
battleReportDetail.WallReport = &proto.ST_WallReport_PB{
BeforeHp: proto.SetUint32(0),
AfterHp: proto.SetUint32(0),
Level: proto.SetUint32(0),
}
battleReportDetail.MutirMonReward = make([]*proto.ST_ItemEntry_PB, 0)
roundNum := len(battleInfo.RoundInfo)
if 0 != roundNum {
defRoundBaseInfo := battleInfo.RoundInfo[roundNum-1].DefRoundInfo
if nil != defRoundBaseInfo.WallHp {
battleReportDetail.WallReport.BeforeHp = proto.SetUint32(defRoundBaseInfo.WallHp.GetBeforeHp())
battleReportDetail.WallReport.AfterHp = proto.SetUint32(defRoundBaseInfo.WallHp.GetAfterHp())
battleReportDetail.WallReport.Level = proto.SetUint32(1)
}
}
reportDetailList = append(reportDetailList, battleReportDetail)
lossCount := uint32(0)
for _, v := range battleReportDetail.UnitListReport {
tmpCount := v.GetJoin() - v.GetSurvival()
lossCount += tmpCount
}
}
powerReport.LossValue = proto.SetInt64(totalLossPower)
powerReport.LossRatio = proto.SetFloat32(float32(totalLossPower) / float32(totalStartPower))
powerReport.AllPower = proto.SetInt64(totalStartPower)
//wlog.Error("LossValue...AllPower...LossRatio", totalLossPower, totalStartPower, powerReport.GetLossRatio())
return reportDetailList, powerReport
}
/**
@brief 生成单人野怪战斗报告详细数据
*/
func createMonsterReportDetail(worldAssetData *cache.WorldDataEntry, orgiAtkUnitAssetMap, orgidefUnitAssetMap map[uint64]*stUserUnitInfo,
unitDefBattleInfoMap map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, reportDetail *proto.ST_MonsterKill_PB) {
if nil == worldAssetData || orgiAtkUnitAssetMap == nil || unitDefBattleInfoMap == nil || orgidefUnitAssetMap == nil {
return
}
conf := worldAssetData.GetWorldEntryConfig()
if conf == nil {
return
}
if len(orgiAtkUnitAssetMap) != 1 || len(orgidefUnitAssetMap) != 1 || len(unitDefBattleInfoMap) != 1 {
return
}
for actionID, userUnitInfo := range orgiAtkUnitAssetMap {
actionAsset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionID)
if actionAsset == nil || actionAsset.Actiondata == nil {
return
}
reportDetail.Uints = &proto.ST_UnitAsset_PB{Units: make([]*proto.ST_Unit_PB, 0)}
for _, v1 := range userUnitInfo.unitMap {
for _, v2 := range v1 {
reportDetail.Uints.Units = common.CombineUnit(reportDetail.Uints.Units, v2.unit)
}
}
}
reportDetail.MonsterInf = &proto.ST_MonsterInfo_PB{}
reportDetail.MonsterInf.TileID = proto.SetUint64(uint64(worldAssetData.GetWorldDataTileID()))
//totalPower := int64(0)
totalLossPower := int64(0)
for _, userUnitInfo := range orgidefUnitAssetMap {
//totalPower = userUnitInfo.totalPower
if unitBattleInfoMap, ok := unitDefBattleInfoMap[0]; ok {
for _, unitList := range userUnitInfo.unitMap {
for _, unit := range unitList {
if v, ok := unitBattleInfoMap[unit.unit.GetUnitid()]; ok {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.unit.GetUnitid()))
if nil != unitCSV {
totalLossPower += unitCSV.Power * int64(unit.unit.GetUnitnum()-uint64(v.GetSurvival()))
}
}
}
}
}
}
//战斗单位
if conf.MonsterFighting == 0 {
reportDetail.MonsterInf.DropHP = proto.SetUint32(0)
} else {
reportDetail.MonsterInf.DropHP = proto.SetUint32(uint32(totalLossPower * 10000 / conf.MonsterFighting))
if reportDetail.MonsterInf.GetDropHP() > 10000 {
reportDetail.MonsterInf.DropHP = proto.SetUint32(10000)
}
}
}
/*
@brief 获取兵力返还比例
*/
func getReturnUnitPara(targetType uint32, isAtk, mstAtk bool) uint32 {
if mstAtk {
return CSV.GetGameConfigValueUint32("Pirate_RETURN")
}
parm := uint32(0)
if false == isAtk {
return parm
}
switch targetType {
case targetMutiMonster: //集结怪
parm = CSV.GetGameConfigValueUint32("MUTI_MONSTER_RETURN_UNITS")
case targetMonsterEx: //单人怪
parm = CSV.GetGameConfigValueUint32("MONSTEREX_RETURN")
case targetSummonMutiMonster: //多人召唤怪
parm = CSV.GetGameConfigValueUint32("SUMMON_MUTI_MONSTER_RETURN")
default:
parm = 0
}
return parm
}
/*
@brief 获取伤兵比例
*/
func getLostUnitPara(userdata *cache.Info, targetType uint32, isAtk, mstAtk bool) float32 {
var list []uint64
var param uint64
switch targetType {
case targetMainCity: //玩家主城
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("PLAYER_BASE_LOST"))
case targetWarCity, targetLeagueCenter: //城市争霸,攻打联盟城市(小奇迹)
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("CITY_LOST"))
case targetRayolCity: //大奇迹
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("WONDER_LOST"))
case targetBestationed, targetMine, targetMineGem: //营地,矿点
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("RESOURCE_LOST"))
case targetMutiMonster: //集结怪
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("MUTI_MONSTER_LOST"))
case targetMonsterEx: //单人怪targetSummonMutiMonster
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("MONSTEREX_LOST"))
case targetSummonMutiMonster: //多人召唤怪
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("SUMMON_MUTI_MONSTER_LOST"))
case targetBlockUnlock: //目前用于地块解锁
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("BLOCK_UNLOCK_LOST"))
default:
param = 10000
}
if mstAtk {
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("Pirate_LOST"))
}
if len(list) < 2 {
return float32(1)
}
if isAtk {
param = list[0]
} else {
param = list[1]
}
if nil != userdata {
addValue, _, _ := userdata.GetAttriValue(nil, proto.AtttibuteType_ToWounded)
param += uint64(addValue)
if param > 10000 {
param = 10000
}
}
return float32(param) / 10000
}
/*
@brief 处理医院存放受伤战斗单位逻辑
*/
func processBattleHospital(userdata *cache.Info, injuredUnitList map[uint32]uint32) (*proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB) {
hurtUnits := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
//维修站放不下的的伤兵
DeathUnits := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
capacity := uint32(getHospitalCapacity(userdata))
if capacity <= 0 {
for k, v := range injuredUnitList {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k),
Unitnum: proto.SetUint64(uint64(v)),
}
DeathUnits.Units = append(hurtUnits.Units, unit)
}
return hurtUnits, DeathUnits
}
unitLevel := make(map[int64]int64)
levelNum := make(map[int64]uint32)
for k, v := range injuredUnitList {
if unitIsPitfall(k) || v == 0 {
continue
}
if res := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(k)); res != nil {
unitlevel := res.UnitLevel
unitLevel[unitlevel] = unitlevel
if v1, ok := levelNum[unitlevel]; ok {
levelNum[unitlevel] = v1 + v
} else {
levelNum[unitlevel] = v
}
}
}
tmpLevelList := make([]int64, 0)
for _, v := range unitLevel {
tmpLevelList = append(tmpLevelList, v)
}
sort.Sort(sort.Reverse(wsort.Int64Slice(tmpLevelList)))
needBreak := false
for _, level := range tmpLevelList {
if injuredNum, ok := levelNum[int64(level)]; ok {
if injuredNum == 0 {
continue
}
if injuredNum > capacity {
injuredNum = capacity
needBreak = true
}
for k1, v1 := range injuredUnitList {
if unitIsPitfall(k1) {
continue
}
if v1 == 0 {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k1),
Unitnum: proto.SetUint64(0),
}
hurtUnits.Units = append(hurtUnits.Units, unit)
DeathUnits.Units = append(DeathUnits.Units, unit)
continue
}
if CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(k1)).UnitLevel == int64(level) {
selfNum := v1
if selfNum > capacity {
tmp := selfNum - capacity
selfNum = capacity
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k1),
Unitnum: proto.SetUint64(uint64(tmp)),
}
DeathUnits.Units = append(DeathUnits.Units, unit)
}
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k1),
Unitnum: proto.SetUint64(uint64(selfNum)),
}
hurtUnits.Units = append(hurtUnits.Units, unit)
capacity -= selfNum
}
}
if needBreak {
break
}
}
}
return hurtUnits, DeathUnits
}
/**
@brief 统计军团击杀及其损失
*/
func genCorpsKillAndLoss(battleInfo *proto.ST_BattleInfo_PB, baseData *stBattleActionBaseData, isAtk bool) (map[proto.UnitBattleType][]*proto.ST_Unit_PB, map[uint32]*proto.ST_Unit_PB, map[uint32]*proto.ST_Unit_PB) {
unitKillMap := make(map[proto.UnitBattleType][]*proto.ST_Unit_PB) //key:造成击杀的军团类型 value:被击杀的战斗单位list
unitLossMap := make(map[uint32]*proto.ST_Unit_PB, 0) //单位损失
trapLossMap := make(map[uint32]*proto.ST_Unit_PB, 0) //陷阱损失
var roundBaseInfo *proto.ST_RoundBaseInfo_PB
for _, roundInfo := range battleInfo.RoundInfo {
roundBaseInfo = roundInfo.AtkRoundInfo
if false == isAtk {
roundBaseInfo = roundInfo.DefRoundInfo
}
for _, corp := range roundBaseInfo.CorpList {
killUnitList := make([]*proto.ST_Unit_PB, 0)
if nil == corp {
continue
}
for _, unit := range corp.UnitKill {
unit := proto.Clone(unit).(*proto.ST_Unit_PB)
killUnitList = append(killUnitList, unit)
}
//军团击杀
if _, ok := unitKillMap[proto.UnitBattleType(corp.GetUnitType())]; ok {
unitKillMap[proto.UnitBattleType(corp.GetUnitType())] = addUnits(unitKillMap[proto.UnitBattleType(corp.GetUnitType())], killUnitList)
} else {
unitKillMap[proto.UnitBattleType(corp.GetUnitType())] = killUnitList
}
}
}
//军团损失
for _, v := range baseData.formation.unitData {
for _, corps := range v {
if corps == nil {
continue
}
num := len(corps.startUnits)
if 0 == num {
continue
}
for index := 0; index < num; index++ {
lostUnit := &proto.ST_Unit_PB{}
startNum := corps.startUnits[index].GetUnitnum()
CurNum := corps.curUnits[index].GetUnitnum()
if CurNum > startNum {
CurNum = startNum
}
lossNum := startNum - CurNum
lossID := corps.startUnits[index].GetUnitid()
lostUnit.Unitid = proto.SetUint32(lossID)
lostUnit.Unitnum = proto.SetUint64(lossNum)
unitLossMap[lossID] = lostUnit
}
}
}
//陷阱损失
for _, v := range baseData.formation.trapsData {
for _, corps := range v {
if corps == nil {
continue
}
num := len(corps.startUnits)
if 0 == num {
continue
}
for index := 0; index < num; index++ {
lostUnit := &proto.ST_Unit_PB{}
lossNum := corps.startUnits[index].GetUnitnum() - corps.curUnits[index].GetUnitnum()
lossID := corps.startUnits[index].GetUnitid()
lostUnit.Unitid = proto.SetUint32(lossID)
lostUnit.Unitnum = proto.SetUint64(lossNum)
trapLossMap[lossID] = lostUnit
}
}
}
return unitKillMap, unitLossMap, trapLossMap
}
/**
@brief 统计军团以及英雄击杀
*/
func genBattleAllKill(battleInfo *proto.ST_BattleInfo_PB, isAtk bool) (map[uint32]*proto.ST_Unit_PB, map[proto.UnitBattleType][]*proto.ST_Unit_PB, map[uint32]*proto.ST_Unit_PB) {
unitKillMap := make(map[proto.UnitBattleType][]*proto.ST_Unit_PB) //key:造成击杀的军团类型 value:被击杀的战斗单位list
heroKillMap := make(map[uint32]*proto.ST_Unit_PB, 0) //英雄总击杀
trapLossMap := make(map[uint32]*proto.ST_Unit_PB, 0) //陷阱损失
var roundBaseInfo *proto.ST_RoundBaseInfo_PB
for _, roundInfo := range battleInfo.RoundInfo {
roundBaseInfo = roundInfo.AtkRoundInfo
if false == isAtk {
roundBaseInfo = roundInfo.DefRoundInfo
}
//军团击杀
for _, corp := range roundBaseInfo.CorpList {
killUnitList := make([]*proto.ST_Unit_PB, 0)
if nil == corp {
continue
}
for _, unit := range corp.UnitKill {
unit := proto.Clone(unit).(*proto.ST_Unit_PB)
killUnitList = append(killUnitList, unit)
}
if _, ok := unitKillMap[proto.UnitBattleType(corp.GetUnitType())]; ok {
unitKillMap[proto.UnitBattleType(corp.GetUnitType())] = addUnits(unitKillMap[proto.UnitBattleType(corp.GetUnitType())], killUnitList)
} else {
unitKillMap[proto.UnitBattleType(corp.GetUnitType())] = killUnitList
}
//陷阱自损
if corp.GetUnitType() >= uint32(proto.UnitBattleType_UBT_NOMAL_TRAP1) &&
corp.GetUnitType() <= uint32(proto.UnitBattleType_UBT_NOMAL_TRAP4) {
for _, unit := range corp.UnitLost {
unit := proto.Clone(unit).(*proto.ST_Unit_PB)
if k, ok := trapLossMap[unit.GetUnitid()]; ok {
k.Unitnum = proto.SetUint64(k.GetUnitnum() + unit.GetUnitnum())
} else {
trapLossMap[unit.GetUnitid()] = unit
}
}
}
}
//英雄击杀
for _, hero := range roundBaseInfo.HeroList {
for _, unit := range hero.KillList {
unit := proto.Clone(unit).(*proto.ST_Unit_PB)
if k, ok := heroKillMap[unit.GetUnitid()]; ok {
k.Unitnum = proto.SetUint64(k.GetUnitnum() + unit.GetUnitnum())
} else {
heroKillMap[unit.GetUnitid()] = unit
}
}
}
}
return heroKillMap, unitKillMap, trapLossMap
}
func getPassiveAfterFightSkillEffect(userData *cache.Info, heroList []uint32, effectName string) uint32 {
if userData == nil || len(heroList) == 0 {
return 0
}
value := uint32(0)
for _, id := range heroList {
userData.WithHeroAsset(true, id, func(heroAsset *proto.ST_HeroEntry_PB) bool {
for _, skill := range heroAsset.GetSkillList() {
skillCSV := CSV.Mgr.CSV_HeroNewSkills.GetEntryPtr(int64(skill.GetSkillID()))
if skillCSV != nil && skillCSV.SkillType == int64(proto.SkillMainType_ST_PASSIVE) {
effectMap := common.ParseParameterStringToMap(skillCSV.SkillEffect)
effectMap1 := common.ParseParameterStringToMap(skillCSV.SkillSubType)
subType, ok := effectMap1[effectName]
if !ok || common.StringToUint32(subType) != uint32(proto.SkillSubType_ST_PASSIVE_AFTERFIGHT) {
continue
}
if effect, ok := effectMap[effectName]; ok {
value += common.StringToUint32(effect)
}
}
}
return true
})
}
return value
}
/**
@brief 根据玩家初始兵力及其战后兵力来计算击杀,存活,伤兵,死亡信息
*/
func genUserBattleUnitInfo(targetType uint32, orgiUnitAssetMap map[uint64]*stUserUnitInfo, unitKillMap map[proto.UnitBattleType][]*proto.ST_Unit_PB,
unitLossMap, trapLossMap map[uint32]*proto.ST_Unit_PB, isAtk bool, atkBaseData, defBaseData *stBattleActionBaseData) (map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, uint64, map[uint64]*proto.ST_UnitAsset_PB) {
atkUnitBattleInfoMap := make(map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB) //key1:action key2:unitid
returnUnitMap := make(map[uint64]*proto.ST_UnitAsset_PB, 0) //返回兵力详细信息key:actionID
//兵力死亡返还系数,百分比
returnUnitsParm := getReturnUnitPara(targetType, isAtk, atkBaseData.monsterAtk)
returnUnitsTotal := uint64(0) //返还兵力的总量
// 被动技能降低地方伤兵转化率
defHeroList := make([]uint32, 0)
for _, v := range defBaseData.heroList {
defHeroList = append(defHeroList, v.heroID)
}
decLostRatio := getPassiveAfterFightSkillEffect(defBaseData.userData, defHeroList, "KillWounded")
if decLostRatio > 10000 {
decLostRatio = 10000
}
resWourd := uint32(0)
if targetType == targetMine || targetType == targetMineGem {
atkHeroList := make([]uint32, 0)
for _, v := range atkBaseData.heroList {
atkHeroList = append(atkHeroList, v.heroID)
}
resWourd = getPassiveAfterFightSkillEffect(atkBaseData.userData, atkHeroList, "ResWounded")
if resWourd > 10000 {
resWourd = 10000
}
}
for actionID, userUnitInfo := range orgiUnitAssetMap {
UnitBattleInfoMap := make(map[uint32]*proto.ST_UnitBattleReport_PB)
//根据己方击杀统计击杀(填充ST_UnitBattleReport_PB中的Join、kill信息)
tmpUnitBattleReportMap := make(map[uint32]*proto.ST_UnitBattleReport_PB)
for k, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
var unitBattleReport *proto.ST_UnitBattleReport_PB
if tmp, ok := tmpUnitBattleReportMap[startUnit.unit.GetUnitid()]; ok {
unitBattleReport = tmp
} else {
unitBattleReport = &proto.ST_UnitBattleReport_PB{
UnitID: proto.SetUint32(startUnit.unit.GetUnitid()),
Join: proto.SetUint32(uint32(startUnit.unit.GetUnitnum())),
Survival: proto.SetUint32(uint32(startUnit.unit.GetUnitnum())),
KillList: &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
},
}
}
if killList, ok := unitKillMap[k]; ok {
for _, killUnit := range killList {
var killNum uint64
//做个四舍五入
killNum = uint64(math.Floor(float64(float32(killUnit.GetUnitnum())*userUnitInfo.corpRatioMap[k]*startUnit.powerRatio + 0.5)))
unitBattleReport.Kill = proto.SetUint32(unitBattleReport.GetKill() + uint32(killNum))
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(killUnit.GetUnitid()),
Unitnum: proto.SetUint64(killNum),
}
unitBattleReport.KillList.Units = append(unitBattleReport.KillList.Units, unit)
}
}
tmpUnitBattleReportMap[unitBattleReport.GetUnitID()] = unitBattleReport
}
}
//军团死亡、受伤(填充ST_UnitBattleReport_PB中的Survival、Injured信息)
tmpUserData := cache.GetCharinfo(userUnitInfo.charUID)
injuredUnitList := make(map[uint32]uint32) //key:id value:数量
lostRatio := float64(getLostUnitPara(tmpUserData, targetType, isAtk, atkBaseData.monsterAtk))
lostRatio = lostRatio * float64(10000-decLostRatio) / float64(10000)
for _, lossUnit := range unitLossMap {
tmpReport := tmpUnitBattleReportMap[lossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == lossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(lossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[lossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
//战损*系数=受伤娄;战损-受伤=死亡数
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Injured = proto.SetUint32(tmpReport.GetInjured() + uint32(tmpLost*lostRatio))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost) - uint32(tmpLost*lostRatio))
if targetType == targetMine || targetType == targetMineGem {
injured := tmpReport.GetInjured() * resWourd / 10000
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() + injured)
tmpReport.Injured = proto.SetUint32(tmpReport.GetInjured() - injured)
}
tmpUnitBattleReportMap[lossUnit.GetUnitid()] = tmpReport
injuredUnitList[tmpReport.GetUnitID()] = tmpReport.GetInjured()
isFind = true
break
}
}
if isFind {
break
}
}
}
//陷阱自损
for _, trapLossUnit := range trapLossMap {
tmpReport := tmpUnitBattleReportMap[trapLossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == trapLossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(trapLossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[trapLossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost))
tmpUnitBattleReportMap[trapLossUnit.GetUnitid()] = tmpReport
isFind = true
break
}
}
if isFind {
break
}
}
}
for k, v := range tmpUnitBattleReportMap {
UnitBattleInfoMap[k] = v
}
atkUnitBattleInfoMap[actionID] = UnitBattleInfoMap
if tmpUserData != nil {
hurtUnit, deathUnit := processBattleHospital(tmpUserData, injuredUnitList)
if targetType != targetMonster {
tmpUserData.AddHospitalUnitAsset(hurtUnit)
}
returnUnits := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
//集结怪、单人小怪、多人召唤怪有返回兵力
//根据死亡兵力+未放入维修战的兵力,得出进攻方的返还兵力
if (targetType == targetMutiMonster || targetType == targetMonsterEx || targetType == targetSummonMutiMonster) && isAtk {
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionID)
if actionData == nil {
continue
}
for unitID, report := range tmpUnitBattleReportMap {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(unitID),
Unitnum: proto.SetUint64(uint64(report.GetDeath() * returnUnitsParm / 100)),
}
returnUnits.Units = append(returnUnits.Units, unit)
}
for _, unit := range deathUnit.Units {
unit.Unitnum = proto.SetUint64(uint64(uint32(unit.GetUnitnum()) * returnUnitsParm / 100))
}
common.CombineUnitAsset(returnUnits, deathUnit)
actionData.UpdateUnitAsset(returnUnits)
returnUnitMap[actionID] = returnUnits
returnUnitsTotal += countUnitNum(returnUnits)
} else if atkBaseData.monsterAtk && !isAtk {
for unitID, report := range tmpUnitBattleReportMap {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(unitID),
Unitnum: proto.SetUint64(uint64(report.GetDeath() * returnUnitsParm / 100)),
}
//report.Death = proto.SetUint32(report.GetDeath() - uint32(unit.GetUnitnum()))
returnUnits.Units = append(returnUnits.Units, unit)
}
tmpUserData.AddUnitAssets(returnUnits)
tmpUserData.CalcPower()
}
}
}
return atkUnitBattleInfoMap, returnUnitsTotal, returnUnitMap
}
/**
@brief 根据玩家出兵战力比分计算击杀,存活,伤兵,死亡信息
*/
func genBattleUserUnitInfo(targetType uint32, orgiUnitAssetMap map[uint64]*stUserUnitInfo, selfUnitKill, enemyUnitKill map[proto.UnitBattleType][]*proto.ST_Unit_PB,
enemyHeroKill map[uint32]*proto.ST_Unit_PB, trapLossTrap map[uint32]*proto.ST_Unit_PB, isAtk bool) map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB {
atkUnitBattleInfoMap := make(map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB) //key1:action key2:unitid
for actionID, userUnitInfo := range orgiUnitAssetMap {
UnitBattleInfoMap := make(map[uint32]*proto.ST_UnitBattleReport_PB)
//根据己方击杀统计击杀
tmpUnitBattleReportMap := make(map[uint32]*proto.ST_UnitBattleReport_PB)
for k, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
var unitBattleReport *proto.ST_UnitBattleReport_PB
if tmp, ok := tmpUnitBattleReportMap[startUnit.unit.GetUnitid()]; ok {
unitBattleReport = tmp
} else {
unitBattleReport = &proto.ST_UnitBattleReport_PB{
UnitID: proto.SetUint32(startUnit.unit.GetUnitid()),
Join: proto.SetUint32(uint32(startUnit.unit.GetUnitnum())),
Survival: proto.SetUint32(uint32(startUnit.unit.GetUnitnum())),
KillList: &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
},
}
}
if killList, ok := selfUnitKill[k]; ok {
for _, killUnit := range killList {
var killNum uint64
//做个四舍五入
killNum = uint64(math.Floor(float64(float32(killUnit.GetUnitnum())*userUnitInfo.corpRatioMap[k]*startUnit.powerRatio + 0.5)))
unitBattleReport.Kill = proto.SetUint32(unitBattleReport.GetKill() + uint32(killNum))
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(killUnit.GetUnitid()),
Unitnum: proto.SetUint64(killNum),
}
unitBattleReport.KillList.Units = append(unitBattleReport.KillList.Units, unit)
}
}
tmpUnitBattleReportMap[unitBattleReport.GetUnitID()] = unitBattleReport
}
}
//根据敌方击杀来统计己方损失
tmpUserData := cache.GetCharinfo(userUnitInfo.charUID)
injuredUnitList := make(map[uint32]uint32) //key:id value:数量
lostRatio := float64(getLostUnitPara(tmpUserData, targetType, isAtk, false))
//敌方军团击杀
for _, lossUnitList := range enemyUnitKill {
for _, lossUnit := range lossUnitList {
tmpReport := tmpUnitBattleReportMap[lossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == lossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(lossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[lossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Injured = proto.SetUint32(tmpReport.GetInjured() + uint32(tmpLost*lostRatio))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost) - uint32(tmpLost*lostRatio))
tmpUnitBattleReportMap[lossUnit.GetUnitid()] = tmpReport
injuredUnitList[tmpReport.GetUnitID()] = tmpReport.GetInjured()
isFind = true
break
}
}
if isFind {
break
}
}
}
}
//敌方英雄击杀
for _, lossUnit := range enemyHeroKill {
tmpReport := tmpUnitBattleReportMap[lossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == lossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(lossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[lossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Injured = proto.SetUint32(tmpReport.GetInjured() + uint32(tmpLost*lostRatio))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost) - uint32(tmpLost*lostRatio))
tmpUnitBattleReportMap[lossUnit.GetUnitid()] = tmpReport
injuredUnitList[tmpReport.GetUnitID()] = tmpReport.GetInjured()
isFind = true
break
}
}
if isFind {
break
}
}
}
//陷阱自损
for _, trapLossUnit := range trapLossTrap {
tmpReport := tmpUnitBattleReportMap[trapLossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == trapLossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(trapLossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[trapLossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost))
tmpUnitBattleReportMap[trapLossUnit.GetUnitid()] = tmpReport
isFind = true
break
}
}
if isFind {
break
}
}
}
for k, v := range tmpUnitBattleReportMap {
UnitBattleInfoMap[k] = v
}
atkUnitBattleInfoMap[actionID] = UnitBattleInfoMap
//医院逻辑
/*
if 0 != actionID{
gActionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionID)
if gActionData != nil {
tmpUserData := cache.GetCharinfo(gActionData.Actiondata.GetUid())
if tmpUserData != nil {
hurtUnit := processBattleHospital(tmpUserData, injuredUnitList)
tmpUserData.AddHospitalUnitAsset(hurtUnit)
}
}
}*/
if tmpUserData != nil {
/*
hurtUnit := processBattleHospital(tmpUserData, injuredUnitList)
tmpUserData.AddHospitalUnitAsset(hurtUnit)
*/
}
}
return atkUnitBattleInfoMap
}
/**
@brief 处理战斗后玩家兵力信息
*/
func processUnitBattleInfo(targetType uint32, battleInfo *proto.ST_BattleInfo_PB,
atkBaseData, defBaseData *stBattleActionBaseData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap map[uint64]*stUserUnitInfo) (
map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, uint64, map[uint64]*proto.ST_UnitAsset_PB) {
if nil == battleInfo || nil == atkBaseData || nil == defBaseData {
return nil, nil, 0, nil
}
atkUnitKillMap, atkUnitLoss, _ := genCorpsKillAndLoss(battleInfo, atkBaseData, true)
defUnitKillMap, defUnitLoss, defTrapLoss := genCorpsKillAndLoss(battleInfo, defBaseData, false)
atkUnitBattleInfoMap, atkReturnUnitsTotal, returnUnitMap := genUserBattleUnitInfo(targetType, atkOrgiUnitAssetMap, atkUnitKillMap, atkUnitLoss, nil, true, atkBaseData, defBaseData)
defUnitBattleInfoMap, _, _ := genUserBattleUnitInfo(targetType, defOrgiUnitAssetMap, defUnitKillMap, defUnitLoss, defTrapLoss, false, defBaseData, atkBaseData)
return atkUnitBattleInfoMap, defUnitBattleInfoMap, atkReturnUnitsTotal, returnUnitMap
}
/**@brief 大地图上的战斗
@return 行为发起方是否获胜,是否经过战斗,目标类型
*/
func worldRealBattle(battleKey *stBattleKey) (uint32, bool, uint32, *proto.ST_BattleInfo_PB, *proto.ST_BattleReport_PB, *proto.ST_MonsterKill_PB) {
if nil == battleKey {
return battleRlt_Error, false, targetUnUse, nil, nil, nil
}
//战斗数据准备,先把在战斗中不会改变的属性计算好
ok, targetType, atkBaseData, defBaseData, commonBattleParm,
worldAssetData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap := prepareBattlePara(battleKey)
if false == ok {
return battleRlt_Error, false, targetType, nil, nil, nil
}
//开始战斗
battleRlt, battleInfo := startBattle(targetType, atkBaseData, defBaseData, commonBattleParm)
if battleRlt_Error == battleRlt {
return battleRlt, true, targetType, nil, nil, nil
}
//wlog.Error("battleInfo:", battleInfo)
//处理战斗后的伤兵,伤兵,击杀等信息
tmpTargetType := targetType
if targetType == targetMonster && battleKey.targetType != 0 {
tmpTargetType = targetType
}
atkUnitBattleInfoMap, defUnitBattleInfoMap, atkReturnUnitsTotal, atkReturnUnitMap := processUnitBattleInfo(tmpTargetType, battleInfo, atkBaseData, defBaseData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap)
//根据战斗信息生产战斗邮件
//并发送战报(战斗回放+战斗邮件)
var battleReport *proto.ST_BattleReport_PB
var monsterKillReport *proto.ST_MonsterKill_PB
if targetMonster != targetType {
//PVP战报
battleReport = &proto.ST_BattleReport_PB{}
var defReportDetailList []*proto.ST_BattleReportDetail_PB
var defPowerReport *proto.ST_PowerReport_PB
atkReportDetailList, atkPowerReport := createReportDetail(targetType, worldAssetData, battleInfo, atkOrgiUnitAssetMap, atkUnitBattleInfoMap, true)
//记录战斗全局加成
//battleReport.AtkAllBattleAttri = &proto.ST_AttributeList_PB{}
battleReport.AtkAllBattleAttri = recordBattleAllAttri(atkBaseData)
if targetMutiMonster == targetType || targetMonsterEx == targetType || targetSummonMutiMonster == targetType { //集结怪/单人小怪/集结召唤怪战报
defReportDetailList, defPowerReport = createMutiMonsterReportDetail(defBaseData, worldAssetData, battleInfo, defOrgiUnitAssetMap, defUnitBattleInfoMap)
battleReport.DefAllBattleAttri = &proto.ST_AttributeList_PB{
List: make([]*proto.ST_Attribute_PB, 0),
}
} else { //通用战报
defReportDetailList, defPowerReport = createReportDetail(targetType, worldAssetData, battleInfo, defOrgiUnitAssetMap, defUnitBattleInfoMap, false)
//记录战斗全局加成
//battleReport.defAllBattleAttri = &proto.ST_AttributeList_PB{}
battleReport.DefAllBattleAttri = recordBattleAllAttri(defBaseData)
}
battleReport.AtkInfo = atkReportDetailList
battleReport.DefInfo = defReportDetailList
battleReport.AtkPowerReport = atkPowerReport
battleReport.DefPowerReport = defPowerReport
battleReport.TargetType = proto.SetUint32(targetType)
battleReport.ReturnUnitsTotal = proto.SetInt64(int64(atkReturnUnitsTotal))
//记录下多人怪进攻方的返回兵力信息
battleReport.ReturnUnitsList = make([]*proto.ST_ReturnUnits_PB, 0)
for k, v := range atkReturnUnitMap {
returnUnit := &proto.ST_ReturnUnits_PB{
ActionID: proto.SetUint64(k),
}
returnUnit.ReturnUnitInfo = proto.Clone(v).(*proto.ST_UnitAsset_PB)
battleReport.ReturnUnitsList = append(battleReport.ReturnUnitsList, returnUnit)
}
if nil != worldAssetData && nil != worldAssetData.GetWorldEntryConfig() {
battleReport.WorldEntryConfigID = proto.SetInt64(worldAssetData.GetWorldEntryConfig().ID)
}
newOssPVPRecord(battleReport, worldAssetData)
} else {
//杀怪战报
monsterKillReport = &proto.ST_MonsterKill_PB{}
createMonsterReportDetail(worldAssetData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap, defUnitBattleInfoMap, monsterKillReport)
}
return battleRlt, true, targetType, battleInfo, battleReport, monsterKillReport
}
/**
@brief 处理英雄战斗流程
*/
func processHeroFight(targetType uint32, atkBaseData, defBaseData *stBattleActionBaseData, commonBattleParm *stCommonBattleParm) uint32 {
if nil == atkBaseData || nil == defBaseData || nil == commonBattleParm {
return battleRlt_Error
}
type stInfo struct {
hero *stHeroBattleInfo
self *stBattleActionBaseData
Enemy *stBattleActionBaseData
}
useSkillOrder := uint32(1) //每个技能的释放顺序
//统计所有英雄的主属性,并记录所对应的攻击/防守玩家的数据
mainValueList := make([]uint32, 0)
heroMap := make(map[uint32]*stInfo)
for _, k := range atkBaseData.heroList {
info := &stInfo{}
info.hero = k
info.self = atkBaseData
info.Enemy = defBaseData
mainValue := uint32(float64(getHeroAtk(targetType, atkBaseData, commonBattleParm)) * float64(commonBattleParm.battleDamageParm[4]) / 10000)
//当出现英雄战斗力值相同的情况,其值自动+1,直到不重复
for {
if _, ok := heroMap[mainValue]; ok {
mainValue += 1
} else {
break
}
}
heroMap[mainValue] = info
mainValueList = append(mainValueList, mainValue)
}
for _, k := range defBaseData.heroList {
info := &stInfo{}
info.hero = k
info.self = defBaseData
info.Enemy = atkBaseData
mainValue := uint32(float64(getHeroAtk(targetType, defBaseData, commonBattleParm)) * float64(commonBattleParm.battleDamageParm[4]) / 10000)
//当出现英雄战斗力值相同的情况,其值自动+1,直到不重复
for {
if _, ok := heroMap[mainValue]; ok {
mainValue += 1
} else {
break
}
}
heroMap[mainValue] = info
mainValueList = append(mainValueList, mainValue)
}
//排序
sort.Sort(sort.Reverse(wsort.Uint32Slice(mainValueList)))
for _, k := range mainValueList {
if v, ok := heroMap[k]; ok {
hero := v.hero
self := v.self
enemy := v.Enemy
//眩晕
if _, ok := hero.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; ok {
continue
}
//获取技能(根据技能的优先级和概率选择一个技能)
skill := heroUserSelectSkill(hero)
if nil == skill {
continue
}
//使用技能
if ok, unitType := heroSkillFightUnit(targetType, hero, skill, k, self, enemy, commonBattleParm); ok {
//-------------记录英雄战斗信息--------------
heroBattleInfo := &proto.ST_HeroBattleInfo_PB{
HeroID: proto.SetUint32(hero.heroID),
BuffList: make([]*proto.ST_BuffBattleInfo_PB, 0),
KillList: make([]*proto.ST_Unit_PB, 0),
RecoveryList: make([]*proto.ST_Unit_PB, 0),
}
for k, v := range hero.fightBuff {
buff := &proto.ST_BuffBattleInfo_PB{}
buff.BuffID = proto.SetUint32(k)
buff.BuffType = proto.SetUint32(v.effectType)
heroBattleInfo.BuffList = append(heroBattleInfo.BuffList, buff)
}
heroBattleInfo.UseSkill = &proto.ST_HeroSkillInfo_PB{
SkillID: proto.SetUint32(uint32(skill.ID)),
TargetType: proto.SetUint32(uint32(unitType)),
}
//不记录普通攻击顺序。
//目前所有普攻都是存放在第一位,skillList不可能为nil
heroBattleInfo.UseOrder = proto.SetUint32(useSkillOrder)
useSkillOrder += 1
self.roundBaseInfo.HeroList = append(self.roundBaseInfo.HeroList, heroBattleInfo)
//-------------记录英雄战斗信息--------------
//立即更新一次双方buff,触发立即生效的buff
processFightBuff(atkBaseData, defBaseData, 1)
processFightBuff(defBaseData, atkBaseData, 1)
rlt := checkBattleRlt(atkBaseData, defBaseData)
if battleRlt_Continue != rlt {
return rlt
}
}
}
}
return battleRlt_Continue
}
/**
@brief 处理战斗BUFF
*/
func processFightBuff(selfBaseData *stBattleActionBaseData, EnemyBaseData *stBattleActionBaseData, triggerTime uint32) {
if nil == selfBaseData || nil == EnemyBaseData {
return
}
//依次处理城墙-英雄-战斗单位的buff效果
if (selfBaseData.actionBaseType == actionBase_Def || selfBaseData.actionBaseType == actionBase_Monster) &&
nil != selfBaseData.wall && 0 != selfBaseData.wall.curWallHp {
for k, v := range selfBaseData.wall.fightBuff {
if uint32(0) >= v.effectRound {
delete(selfBaseData.wall.fightBuff, k)
continue
}
if v.csvIndex == int32(proto.FightBuffAttibute_DamageShield) && v.effectValue <= 0 {
delete(selfBaseData.wall.fightBuff, k)
continue
}
if triggerTime == v.triggerTime {
//触发效果
triggerWallFightBuff(selfBaseData, selfBaseData.wall, k, v)
v.triggerTime = 0
v.effectRound -= 1
}
}
}
for _, heroV := range selfBaseData.heroList {
for buffK, buffV := range heroV.fightBuff {
if triggerTime == buffV.triggerTime {
if uint32(0) >= buffV.effectRound {
delete(heroV.fightBuff, buffK)
continue
}
//触发效果
triggerHeroFightBuff(heroV, buffK, buffV)
buffV.triggerTime = 0
buffV.effectRound -= 1
}
}
}
for _, v := range selfBaseData.formation.unitData {
for _, unitV := range v {
if unitV == nil {
continue
}
for buffK, buffV := range unitV.fightBuff {
if triggerTime == buffV.triggerTime {
if uint32(0) >= buffV.effectRound {
if buffV.csvIndex == int32(proto.FightBuffAttibute_SummonTroops) {
unitV.summonUnits = make([]*proto.ST_Unit_PB, 0)
}
delete(unitV.fightBuff, buffK)
continue
}
if buffV.csvIndex == int32(proto.FightBuffAttibute_DamageShield) && buffV.effectValue <= 0 {
delete(unitV.fightBuff, buffK)
continue
}
//触发效果
triggerUnitFightBuff(selfBaseData, EnemyBaseData, unitV, buffK, buffV)
buffV.triggerTime = 0
buffV.effectRound -= 1
}
}
}
}
}
/**
@brief 获取英雄攻击力
*/
func getHeroAtk(targetType uint32, baseData *stBattleActionBaseData, commonBattleParm *stCommonBattleParm) uint64 {
if nil == baseData {
return 0
}
totalAtkValue := uint64(0)
for _, lst := range baseData.formation.unitData {
for _, corps := range lst {
if corps == nil {
continue
}
totalCorpValue := uint64(0)
tmpUnits := make([]*proto.ST_Unit_PB, 0)
tmpUnits = common.CombineUnitMap(tmpUnits, corps.curUnits)
tmpUnits = common.CombineUnitMap(tmpUnits, corps.summonUnits)
for _, unit := range tmpUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if unitCSV == nil {
continue
}
if nil != commonBattleParm {
tmpValue := uint64(float64(unitCSV.Attack) * math.Pow(float64(unit.GetUnitnum()), float64(commonBattleParm.atkParm[0])/10000))
totalCorpValue += tmpValue
}
}
totalCorpValue = getAtkAdditional(totalCorpValue, targetType, corps.unitType, baseData.globalAttribute, corps.fightBuff, corps.specialBuff, baseData.actionBaseType == actionBase_Def)
totalAtkValue += totalCorpValue
}
}
return totalAtkValue
}
/**
@brief 检查是否存在技能释放对象
*/
func CheckSkillUnitTarget(skillCSV *CSV.CF_HeroNewSkills_DataEntry, defBaseData *stBattleActionBaseData) proto.UnitBattleType {
if nil == skillCSV || nil == defBaseData {
return proto.UnitBattleType_UBT_NOMAL_NONE
}
unitType := proto.UnitBattleType_UBT_NOMAL_NONE
//是否有指定兵种
DestineUnit := proto.UnitBattleType(skillCSV.DestineUnit)
if proto.UnitBattleType_UBT_NOMAL_NONE != DestineUnit {
if DestineUnit == proto.UnitBattleType_UBT_NOMAL_WALL { //城墙
if nil != defBaseData.wall && uint64(0) != defBaseData.wall.curWallHp {
unitType = proto.UnitBattleType_UBT_NOMAL_WALL
}
} else if DestineUnit == proto.UnitBattleType_UBT_SPECIAL_ALL_UNIT { //所有兵种
for _, lst := range defBaseData.formation.unitData {
bFind := false
for _, v := range lst {
if v != nil && v.curAllUnitNum != uint32(0) { //直接选取第一个数量不为0的军团
unitType = v.unitType
bFind = true
break
}
}
if bFind {
break
}
}
} else if DestineUnit == proto.UnitBattleType_UBT_NOMAL_HERO { //英雄
unitType = proto.UnitBattleType_UBT_NOMAL_HERO
} else if DestineUnit == proto.UnitBattleType_UBT_NOMAL_TRAP1 { //陷阱
for _, lst := range defBaseData.formation.trapsData {
bFind := false
for _, v := range lst { //步兵,坦克,火炮,飞机
if v != nil && v.unitType == DestineUnit && v.curAllUnitNum != uint32(0) { //直接选取第一个数量不为0的陷阱
unitType = v.unitType
bFind = true
break
}
}
if bFind {
break
}
}
} else {
for _, lst := range defBaseData.formation.unitData {
bFind := false
for _, v := range lst { //步兵,坦克,火炮,飞机
if v != nil && v.unitType == DestineUnit && v.curAllUnitNum != uint32(0) {
unitType = v.unitType
bFind = true
break
}
}
if !bFind {
break
}
}
}
}
if unitType != proto.UnitBattleType_UBT_NOMAL_NONE {
return unitType
}
//攻击位置上是否还存在战斗单位
if 0 != len(skillCSV.AttPos) {
posList := common.ParseStringToUint32List(skillCSV.AttPos)
for _, v := range posList {
bFind := false
lst := defBaseData.formation.unitData[proto.CorpsPos(v)]
for _, corp := range lst {
if corp != nil && uint32(0) != corp.curAllUnitNum {
unitType = corp.unitType
bFind = true
break
}
}
if bFind {
break
}
}
}
return unitType
}
/**
@brief 英雄使用技能
*/
func heroSkillFightUnit(targetType uint32, hero *stHeroBattleInfo, skillCSV *CSV.CF_HeroNewSkills_DataEntry, mainValue uint32, atkBaseData, defBaseData *stBattleActionBaseData, commonBattleParm *stCommonBattleParm) (bool, proto.UnitBattleType) {
if nil == skillCSV || nil == atkBaseData || nil == defBaseData || nil == commonBattleParm {
return false, proto.UnitBattleType_UBT_NOMAL_NONE
}
//判定是否存在释放目标
unitType := CheckSkillUnitTarget(skillCSV, defBaseData)
if unitType == proto.UnitBattleType_UBT_NOMAL_NONE {
return false, unitType
}
//攻击方英雄攻击力
atkHeroAtk := uint64(0)
skillEffectMap := strings.Split(skillCSV.SkillEffect, ";")
extraParamMap := common.ParseParameterStringToMap(skillCSV.ExtraParam)
for _, v := range skillEffectMap {
skillEffect := strings.Split(v, "=")
if len(skillEffect) < int(1) {
continue
}
index := proto.FightBuffAttibute_value[skillEffect[0]]
fightBuffInfo := CSV.Mgr.CSV_FightBuff.GetEntryPtr(int64(index))
if nil == fightBuffInfo {
continue
}
extraParamStr, ok := extraParamMap[skillEffect[0]]
extraParam := make([]uint32, 0)
if ok {
extraParam = common.ParseStringToUint32List(extraParamStr)
}
effectParm := common.ParseStringToUint32List(skillEffect[1]) // 作用对象|回合|固定值
tmpEffectValue := uint64(0)
specialRate := float64(1) //特殊行为系数
specialParm := commonBattleParm.skillSpecialParm //P|Q
var actionBase *stBattleActionBaseData
calcDamage := false
calcRecovery := false
switch proto.FightBuffAttibute(index) {
case proto.FightBuffAttibute_NomalDamage:
fallthrough
case proto.FightBuffAttibute_EnemyHDefDamage:
fallthrough
case proto.FightBuffAttibute_EnemyHHpDamage:
fallthrough
case proto.FightBuffAttibute_SelfLHpDamage:
actionBase = defBaseData
calcDamage = true
case proto.FightBuffAttibute_RecoveryCurHp:
tmpEffectValue = uint64(effectParm[2])
actionBase = atkBaseData
//calcRecovery = true
case proto.FightBuffAttibute_HotTreatment:
actionBase = atkBaseData
calcRecovery = true
case proto.FightBuffAttibute_ReduceHpRound:
actionBase = defBaseData
tmpEffectValue = uint64(effectParm[2])
//calcDamage = true
case proto.FightBuffAttibute_Dotdamage:
actionBase = defBaseData
//tmpEffectValue = uint64(effectParm[2])
calcDamage = true
case proto.FightBuffAttibute_ReduceDef:
fallthrough
case proto.FightBuffAttibute_ReduceAtt:
tmpEffectValue = uint64(effectParm[2])
actionBase = defBaseData
case proto.FightBuffAttibute_IncreaseFightAtt:
fallthrough
case proto.FightBuffAttibute_IncreaseFightDef:
tmpEffectValue = uint64(effectParm[2])
actionBase = atkBaseData
case proto.FightBuffAttibute_Dizzy:
fallthrough
case proto.FightBuffAttibute_Clearbuff:
actionBase = defBaseData
case proto.FightBuffAttibute_ClearDebuff:
actionBase = atkBaseData
case proto.FightBuffAttibute_IncreaseDamge:
actionBase = atkBaseData
tmpEffectValue = uint64(effectParm[2])
case proto.FightBuffAttibute_ReduceDamge:
actionBase = defBaseData
tmpEffectValue = uint64(effectParm[2])
case proto.FightBuffAttibute_SummonTroops:
actionBase = atkBaseData
case proto.FightBuffAttibute_NumDamage:
actionBase = atkBaseData
case proto.FightBuffAttibute_DamageShield:
actionBase = atkBaseData
tmpEffectValue = uint64(effectParm[2])
case proto.FightBuffAttibute_ExtraDamage:
actionBase = atkBaseData
case proto.FightBuffAttibute_NumCompare:
actionBase = atkBaseData
}
if calcDamage || calcRecovery {
atkHeroAtk = uint64(float64(getHeroAtk(targetType, atkBaseData, commonBattleParm)) * float64(commonBattleParm.battleDamageParm[4]) / 10000)
}
//英雄技能伤害系数=(基础系数+英雄主属性值/100×技能系数)×特殊行为系数/10000
//最终伤害=加成减免后伤害×英雄技能伤害系数
wall, heroList, corps, traps := getEffectTarget(unitType, effectParm[0], actionBase, hero)
//城墙
if nil != wall {
fightBuff := &stFightBuff{}
fightBuff.csvIndex = index
fightBuff.effectValue = tmpEffectValue
fightBuff.effectType = uint32(fightBuffInfo.BuffType)
fightBuff.effectRound = effectParm[1]
fightBuff.triggerTime = uint32(fightBuffInfo.Now)
fightBuff.heroID = hero.heroID
fightBuff.orgiSkillID = skillCSV.ID
fightBuff.params = extraParam
wall.fightBuff[uint32(index)] = fightBuff
if calcDamage {
//特殊行为系数
switch proto.FightBuffAttibute(index) {
case proto.FightBuffAttibute_EnemyHDefDamage:
//规划中...
case proto.FightBuffAttibute_EnemyHHpDamage:
//血量越高伤害越高,则 特殊行为系数= (血量百分比+P)/Q
specialRate = (float64(specialParm[0])/10000 + float64(wall.curWallHp)/float64(wall.startWallHp)) / float64(specialParm[1]) / 10000
case proto.FightBuffAttibute_SelfLHpDamage:
//血量越低伤害越高,则 特殊行为系数=Q/(P+血量百分比)
specialRate = (float64(specialParm[1]) / 10000) / (float64(specialParm[0])/10000 + float64(wall.curWallHp)/float64(wall.startWallHp))
}
skillDamageRate := (float64(effectParm[2])/10000 +
float64(mainValue)/100*float64(skillCSV.SkillRatio)/10000) * specialRate
damage := calcSkillDamageWithOutSpecialRate(atkHeroAtk, uint64(wall.wallDef), atkBaseData, defBaseData, hero.fightBuff, wall.fightBuff, hero.specialBuff, commonBattleParm, targetType)
fightBuff.effectValue = uint64(damage * (skillDamageRate * 10000))
}
if proto.FightBuffAttibute(index) == proto.FightBuffAttibute_HotTreatment {
if wall.curWallHp != 0 {
fightBuff.effectValue = atkHeroAtk * uint64(effectParm[2]) / (10000 * wall.curWallHp)
} else {
fightBuff.effectValue = 0
}
}
}
if nil != heroList && 1 == len(heroList) {
for _, v := range heroList {
fightBuff := &stFightBuff{}
fightBuff.csvIndex = index
fightBuff.effectValue = tmpEffectValue
fightBuff.effectType = uint32(fightBuffInfo.BuffType)
fightBuff.effectRound = effectParm[1]
fightBuff.triggerTime = uint32(fightBuffInfo.Now)
fightBuff.heroID = hero.heroID
fightBuff.orgiSkillID = skillCSV.ID
fightBuff.params = extraParam
v.fightBuff[uint32(index)] = fightBuff
}
}
//军团
if nil != corps && 0 != len(corps) {
for _, v := range corps {
if uint32(0) != v.curAllUnitNum {
fightBuff := &stFightBuff{}
fightBuff.csvIndex = index
fightBuff.effectValue = tmpEffectValue
fightBuff.effectType = uint32(fightBuffInfo.BuffType)
fightBuff.effectRound = effectParm[1]
fightBuff.triggerTime = uint32(fightBuffInfo.Now)
fightBuff.heroID = hero.heroID
fightBuff.orgiSkillID = skillCSV.ID
fightBuff.params = extraParam
v.fightBuff[uint32(index)] = fightBuff
if calcDamage {
//先重新统计下战斗单位属性
ProcessUnitAttribute(targetType, v, defBaseData.globalAttribute, commonBattleParm, defBaseData.actionBaseType == actionBase_Def, true)
curHp, MaxHp := getCorpCurTotalHp(v)
//特殊行为系数
if uint32(0) == uint32(specialRate) {
switch proto.FightBuffAttibute(index) {
case proto.FightBuffAttibute_EnemyHDefDamage:
//规划中...
case proto.FightBuffAttibute_EnemyHHpDamage:
//血量越高伤害越高,则 特殊行为系数= (血量百分比+P)/Q
specialRate = (float64(specialParm[0])/10000 + float64(curHp)/float64(MaxHp)) / float64(specialParm[1]) / 10000
case proto.FightBuffAttibute_SelfLHpDamage:
//血量越低伤害越高,则 特殊行为系数=Q/(P+血量百分比)
specialRate = (float64(specialParm[1]) / 10000) / (float64(specialParm[0])/10000 + float64(curHp)/float64(MaxHp))
}
}
skillDamageRate := (float64(effectParm[2])/10000 +
float64(mainValue)/100*float64(skillCSV.SkillRatio)/10000) * specialRate
damage := calcSkillDamageWithOutSpecialRate(atkHeroAtk, uint64(v.attributeMap[attribute_Def]), atkBaseData, defBaseData, hero.fightBuff, v.fightBuff, hero.specialBuff, commonBattleParm, targetType)
//技能伤害系数
//fightBuff.effectValue = uint64(math.Ceil(damage * skillDamageRate))
fightBuff.effectValue = uint64(damage * (skillDamageRate * 10000))
}
// 召唤 影子部队
if proto.FightBuffAttibute(index) == proto.FightBuffAttibute_SummonTroops {
v.summonUnits = make([]*proto.ST_Unit_PB, 0)
for _, unit := range v.curUnits {
v.summonUnits = append(v.summonUnits, &proto.ST_Unit_PB{
Unitid: proto.SetUint32(unit.GetUnitid()),
Unitnum: proto.SetUint64(unit.GetUnitnum() * uint64(effectParm[2]) / 10000),
})
}
} else if proto.FightBuffAttibute(index) == proto.FightBuffAttibute_HotTreatment {
fightBuff.effectValue = atkHeroAtk * uint64(effectParm[2]) * uint64(commonBattleParm.battleDamageParm[0]) / 10000
}
}
}
}
//陷阱
if nil != traps && 0 != len(traps) {
for _, v := range traps {
if uint32(0) != v.curAllUnitNum {
fightBuff := &stFightBuff{}
fightBuff.csvIndex = index
fightBuff.effectValue = tmpEffectValue
fightBuff.effectType = uint32(fightBuffInfo.BuffType)
fightBuff.effectRound = effectParm[1]
fightBuff.triggerTime = uint32(fightBuffInfo.Now)
fightBuff.heroID = hero.heroID
fightBuff.orgiSkillID = skillCSV.ID
fightBuff.params = extraParam
v.fightBuff[uint32(index)] = fightBuff
if calcDamage {
ProcessUnitAttribute(targetType, v, defBaseData.globalAttribute, commonBattleParm, defBaseData.actionBaseType == actionBase_Def, true)
curHp, MaxHp := getCorpCurTotalHp(v)
//特殊行为系数
if uint32(0) == uint32(specialRate) {
switch proto.FightBuffAttibute(index) {
case proto.FightBuffAttibute_EnemyHDefDamage:
//规划中...
case proto.FightBuffAttibute_EnemyHHpDamage:
//血量越高伤害越高,则 特殊行为系数= (血量百分比+P)/Q
specialRate = (float64(specialParm[0])/10000 + float64(curHp)/float64(MaxHp)) / float64(specialParm[1]) / 10000
case proto.FightBuffAttibute_SelfLHpDamage:
//血量越低伤害越高,则 特殊行为系数=Q/(P+血量百分比)
specialRate = (float64(specialParm[1]) / 10000) / (float64(specialParm[0])/10000 + float64(curHp)/float64(MaxHp))
}
}
//技能伤害系数
skillDamageRate := (float64(effectParm[2])/10000 +
float64(mainValue)/100*float64(skillCSV.SkillRatio)/10000) * specialRate
if proto.FightBuffAttibute_Dotdamage == proto.FightBuffAttibute(index) {
skillDamageRate = float64(effectParm[2]) / 10000
}
damage := calcSkillDamageWithOutSpecialRate(atkHeroAtk, uint64(uint64(v.attributeMap[attribute_Def])), atkBaseData, defBaseData, hero.fightBuff, v.fightBuff, hero.specialBuff, commonBattleParm, targetType)
fightBuff.effectValue = uint64(damage * (skillDamageRate * 10000))
}
if proto.FightBuffAttibute(index) == proto.FightBuffAttibute_HotTreatment {
fightBuff.effectValue = atkHeroAtk * uint64(effectParm[2]) * uint64(commonBattleParm.battleDamageParm[0]) / 10000
}
}
}
}
}
return true, unitType
}
/**
@brief 检查攻守军团剩余兵力
@return 0继续战斗 1攻击方无兵力 2防守方无兵力 3都没有
*/
func checkBattleRlt(atkBaseData, defBaseData *stBattleActionBaseData) uint32 {
if nil == atkBaseData {
return battleRlt_AtkEmpty
}
if nil == defBaseData {
return battleRlt_DefEmpty
}
atkOver := true
defOver := true
wallOver := true
for _, lst := range atkBaseData.formation.unitData {
for _, v := range lst {
if v == nil || v.curAllUnitNum == uint32(0) {
continue
}
atkOver = false
}
}
if nil != defBaseData.wall && defBaseData.wall.curWallHp != uint64(0) {
wallOver = false
}
for _, lst := range defBaseData.formation.unitData {
for _, v := range lst {
if v == nil || v.curAllUnitNum == uint32(0) {
continue
}
defOver = false
}
}
//双方全灭
if atkOver && defOver && wallOver {
return battleRlt_AllEmpty
}
//进攻方全灭,
if atkOver && (defOver != true || wallOver != true) {
return battleRlt_AtkEmpty
}
//防守放全灭
if atkOver != true && defOver && wallOver {
return battleRlt_DefEmpty
}
return battleRlt_Continue
}
/**
@brief 选择敌方被攻击对象
*/
func getEnemyCorps(unitBattleType proto.UnitBattleType, unitSpecialBuff []*stFightBuff, enemyFormation *stFormation) *stCorps {
//飞机有50%的几率随机攻击
if unitBattleType == proto.UnitBattleType_UBT_NOMAL_FEIJI {
if 0 == rand.Int31n(2) {
//先取出还有兵力的军团,再从中随机一个
tmpCorpList := []*stCorps{}
for _, lst := range enemyFormation.unitData {
for _, v := range lst {
if v != nil && v.curAllUnitNum != uint32(0) {
tmpCorpList = append(tmpCorpList, v)
}
}
}
tmpCount := int32(len(tmpCorpList))
if 0 != tmpCount {
return tmpCorpList[rand.Int31n(tmpCount)]
} else {
return nil
}
}
}
// 特殊被动技能会改变兵种的攻击顺序
fromBack := isRear(unitSpecialBuff)
if !fromBack {
for m := proto.CorpsPos_CP_FRONT; m <= proto.CorpsPos_CP_SKY; m++ {
lst := enemyFormation.unitData[m]
for _, tmp := range lst {
if nil != tmp && tmp.curAllUnitNum != uint32(0) {
return tmp
}
}
}
} else {
for m := proto.CorpsPos_CP_SKY; m >= proto.CorpsPos_CP_FRONT; m-- {
lst := enemyFormation.unitData[m]
for _, tmp := range lst {
if nil != tmp && tmp.curAllUnitNum != uint32(0) {
return tmp
}
}
}
}
return nil
}
/**
@brief 记录军团战斗流程
*/
func recordCropsBattleInfo(corp *stCorps, loss, kill []*proto.ST_Unit_PB) *proto.ST_CorpBattleInfo_PB {
corpBattleInfo := &proto.ST_CorpBattleInfo_PB{}
if nil == corp {
return corpBattleInfo
}
corpBattleInfo.UnitType = proto.SetUint32(uint32(corp.unitType))
corpBattleInfo.UnitNum = proto.SetUint32(corp.curAllUnitNum)
corpBattleInfo.UnitLost = make([]*proto.ST_Unit_PB, len(loss))
copy(corpBattleInfo.UnitLost, loss)
corpBattleInfo.UnitKill = make([]*proto.ST_Unit_PB, len(kill))
copy(corpBattleInfo.UnitKill, kill)
//buff信息
for k, v := range corp.fightBuff {
buff := &proto.ST_BuffBattleInfo_PB{}
buff.BuffID = proto.SetUint32(k)
buff.BuffType = proto.SetUint32(v.effectType)
corpBattleInfo.BuffList = append(corpBattleInfo.BuffList, buff)
}
//小军团详细信息
if len(corp.curUnits) > 0 {
corpBattleInfo.UnitId = proto.SetUint32(corp.curUnits[0].GetUnitid())
}
return corpBattleInfo
}
/**
@brief 处理军团战斗流程
*/
func processCorpsFight(targetType uint32, atkBaseData, defBaseData *stBattleActionBaseData, commonBattleParm *stCommonBattleParm) uint32 {
if nil == atkBaseData || nil == defBaseData || nil == commonBattleParm {
return 0
}
//有城墙时防守方的陷阱先攻击
if nil != defBaseData.wall && defBaseData.wall.curWallHp != 0 {
for _, v := range defBaseData.formation.trapsData {
for _, atkTrap := range v {
if nil == atkTrap || atkTrap.curAllUnitNum == uint32(0) {
continue
}
rlt := checkBattleRlt(atkBaseData, defBaseData)
if battleRlt_Continue != rlt {
return rlt
}
var beAtkCorps *stCorps
//获取被攻击的对象
//先选取被陷阱克制的单位
//如果没有,则顺序选取攻击对象
beAtkCorpType := proto.UnitBattleType(commonBattleParm.corpAtkOrder[int64(atkTrap.unitType)])
for _, v := range atkBaseData.formation.unitData {
for _, tmpCorp := range v {
if tmpCorp == nil || tmpCorp.unitType != beAtkCorpType {
continue
}
if tmpCorp.curAllUnitNum != uint32(0) {
beAtkCorps = tmpCorp
}
break
}
}
if nil == beAtkCorps {
for n := proto.CorpsPos_CP_FRONT; n <= proto.CorpsPos_CP_SKY; n++ {
lst := atkBaseData.formation.unitData[n]
for _, v := range lst {
beAtkCorps = v
if nil == beAtkCorps || beAtkCorps.curAllUnitNum == uint32(0) {
continue
}
break
}
}
}
if nil == beAtkCorps {
return battleRlt_AtkEmpty
}
isOnly := isOnlyCorp(atkBaseData, beAtkCorps)
//开始计算伤害及其损失
ProcessUnitAttribute(targetType, beAtkCorps, atkBaseData.globalAttribute, commonBattleParm, false, true)
ProcessUnitAttribute(targetType, atkTrap, defBaseData.globalAttribute, commonBattleParm, true, true)
_, trapDamage := unitFightUnitDamage(atkBaseData, defBaseData, atkTrap, beAtkCorps,
commonBattleParm, nil, true, targetType, atkTrap.specialBuff, isOnly, 0)
//根据伤害扣除战斗单位
atkLost, atkLossHp := reduceCorpUnitsByHp(beAtkCorps, trapDamage)
//陷阱自己的损失
trapLossDamage := math.Ceil(float64(atkLossHp) * float64(commonBattleParm.trapLossParm) / 10000)
trapLost, _ := reduceCorpUnitsByHp(atkTrap, trapLossDamage)
if nil != atkLost {
//进攻方损失
BeAtkCorpBattleInfo := recordCropsBattleInfo(beAtkCorps, atkLost, nil)
atkBaseData.roundBaseInfo.CorpList = append(atkBaseData.roundBaseInfo.CorpList, BeAtkCorpBattleInfo)
trapKillBattleInfo := recordCropsBattleInfo(atkTrap, nil, atkLost) //陷阱击杀
defBaseData.roundBaseInfo.CorpList = append(defBaseData.roundBaseInfo.CorpList, trapKillBattleInfo)
//陷阱损失
trapLossBattleInfo := recordCropsBattleInfo(atkTrap, trapLost, nil)
defBaseData.roundBaseInfo.CorpList = append(defBaseData.roundBaseInfo.CorpList, trapLossBattleInfo)
}
}
}
}
//拷贝一份进攻时的兵力信息
//存放单回合内未进攻的军团
cloneAtkUnitData := make(map[proto.CorpsPos][]*stCorps)
for k, v := range atkBaseData.formation.unitData {
cops := []*stCorps{}
for _, vv := range v {
cops = append(cops, vv)
}
cloneAtkUnitData[k] = cops
}
cloneDefUnitData := make(map[proto.CorpsPos][]*stCorps)
for k, v := range defBaseData.formation.unitData {
cops := []*stCorps{}
for _, vv := range v {
cops = append(cops, vv)
}
cloneDefUnitData[k] = cops
}
//接着双方兵团依次攻击
//在4种军团都存活的情况下,最多持续4*5小回合
for index := 1; index <= 4; index++ {
for tn := 0; tn < 5; tn++ {
rlt := checkBattleRlt(atkBaseData, defBaseData)
if battleRlt_Continue != rlt {
return rlt
}
var atkCorp *stCorps //攻击方战斗的军团
var defCorp *stCorps //防守方战斗的军团
var atkEnemyCorp *stCorps //攻击方攻击的敌方军团
var defEnemyCorp *stCorps //防守方攻击的敌方军团
//攻击方选择己方攻击军团及敌方被攻击军团
for atkIndex := proto.CorpsPos(index); atkIndex <= proto.CorpsPos_CP_SKY; atkIndex++ {
if lst, ok := cloneAtkUnitData[atkIndex]; ok {
bFind := false
for tnIdx := tn; tnIdx < 5; tnIdx++ {
if lst[tnIdx] != nil && lst[tnIdx].curAllUnitNum != uint32(0) {
atkCorp = lst[tnIdx]
atkEnemyCorp = getEnemyCorps(atkCorp.unitType, atkCorp.specialBuff, defBaseData.formation)
cloneAtkUnitData[atkIndex][tnIdx] = nil
bFind = true
break
}
}
if bFind {
break
}
}
}
//防守方选择己方攻击军团及敌方被攻击军团
for defIndex := proto.CorpsPos(index); defIndex <= proto.CorpsPos_CP_SKY; defIndex++ {
if lst, ok := cloneDefUnitData[defIndex]; ok {
bFind := false
for tnIdx := tn; tnIdx < 5; tnIdx++ {
if lst[tnIdx] != nil && lst[tnIdx].curAllUnitNum != uint32(0) {
defCorp = lst[tnIdx]
defEnemyCorp = getEnemyCorps(defCorp.unitType, defCorp.specialBuff, atkBaseData.formation)
cloneDefUnitData[defIndex][tnIdx] = nil
bFind = true
break
}
}
if bFind {
break
}
}
}
//进攻方进攻
var atkDamage float64 //进攻方造成的伤害
//更新参战军团的属性
ProcessUnitAttribute(targetType, atkCorp, atkBaseData.globalAttribute, commonBattleParm, false, true)
ProcessUnitAttribute(0, atkEnemyCorp, defBaseData.globalAttribute, commonBattleParm, true, true)
ProcessUnitAttribute(0, defCorp, defBaseData.globalAttribute, commonBattleParm, defBaseData.actionBaseType == actionBase_Def, true)
ProcessUnitAttribute(targetType, defEnemyCorp, atkBaseData.globalAttribute, commonBattleParm, atkBaseData.actionBaseType == actionBase_Def, true)
if (nil != atkEnemyCorp) && (nil == defCorp || defCorp.unitType != atkEnemyCorp.unitType) {
ProcessUnitAttribute(targetType, atkEnemyCorp, atkBaseData.globalAttribute, commonBattleParm, false, true)
}
isOnly := isOnlyCorp(defBaseData, atkEnemyCorp)
atkCorpPer := getAtkCorpPer(atkBaseData, atkCorp)
//如果城墙还有血,战斗单位必须打城墙
if nil != defBaseData.wall && defBaseData.wall.curWallHp != 0 && nil != atkCorp {
if _, ok := atkCorp.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; !ok {
isRear := isRear(atkCorp.specialBuff)
if !isRear {
_, atkDamage = unitFightUnitDamage(atkBaseData, defBaseData, atkCorp, nil,
commonBattleParm, defBaseData.wall, false, targetType, atkCorp.specialBuff, false, atkCorpPer)
if defBaseData.wall.curWallHp <= uint64(atkDamage) {
defBaseData.wall.curWallHp = 0
} else {
defBaseData.wall.curWallHp -= uint64(atkDamage)
}
atkDamage = 0
} else {
//进攻军团产生的伤害
_, atkDamage = unitFightUnitDamage(atkBaseData, defBaseData, atkCorp, atkEnemyCorp,
commonBattleParm, nil, false, targetType, atkCorp.specialBuff, isOnly, atkCorpPer)
}
}
} else if nil != atkCorp {
//进攻军团产生的伤害
if _, ok := atkCorp.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; !ok {
_, atkDamage = unitFightUnitDamage(atkBaseData, defBaseData, atkCorp, atkEnemyCorp,
commonBattleParm, nil, false, targetType, atkCorp.specialBuff, isOnly, atkCorpPer)
}
}
//防御方攻击
var defDamage float64 //防守方造成的伤害
if (nil != defEnemyCorp) && (nil == atkCorp || atkCorp.unitType != defEnemyCorp.unitType) {
ProcessUnitAttribute(0, defEnemyCorp, defBaseData.globalAttribute, commonBattleParm, defBaseData.actionBaseType == actionBase_Def, true)
}
isOnly = isOnlyCorp(atkBaseData, defEnemyCorp)
atkCorpPer = getAtkCorpPer(defBaseData, defCorp)
//如果城墙还有血,防御方只有飞机和坦火炮可以攻击
if nil != defBaseData.wall && defBaseData.wall.curWallHp != 0 {
if nil != defCorp &&
(defCorp.unitType == proto.UnitBattleType_UBT_NOMAL_HUOPAO || (defCorp.unitType == proto.UnitBattleType_UBT_NOMAL_FEIJI)) {
if _, ok := defCorp.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; !ok {
//防守军团产生的伤害
_, defDamage = unitFightUnitDamage(defBaseData, atkBaseData, defCorp, defEnemyCorp,
commonBattleParm, nil, false, targetType, defCorp.specialBuff, isOnly, atkCorpPer)
}
}
} else {
if nil != defCorp {
if _, ok := defCorp.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; !ok {
//防守军团产生的伤害
_, defDamage = unitFightUnitDamage(defBaseData, atkBaseData, defCorp, defEnemyCorp,
commonBattleParm, nil, false, targetType, defCorp.specialBuff, isOnly, atkCorpPer)
}
}
}
//根据伤害扣除战斗单位
atkLost, _ := reduceCorpUnitsByHp(defEnemyCorp, defDamage) //进攻方损失
defLost, _ := reduceCorpUnitsByHp(atkEnemyCorp, atkDamage) //防守方损失
//进攻方军团记录战斗信息
if nil != atkCorp && nil != defLost {
atkCorpBattleInfo := recordCropsBattleInfo(atkCorp, nil, defLost) //进攻方击杀
atkBaseData.roundBaseInfo.CorpList = append(atkBaseData.roundBaseInfo.CorpList, atkCorpBattleInfo)
}
if nil != defEnemyCorp && nil != atkLost {
atkCorpBattleInfo := recordCropsBattleInfo(defEnemyCorp, atkLost, nil) //进攻方损失
atkBaseData.roundBaseInfo.CorpList = append(atkBaseData.roundBaseInfo.CorpList, atkCorpBattleInfo)
}
//防守方军团记录战斗信息
if nil != defCorp && nil != atkLost {
defCorpBattleInfo := recordCropsBattleInfo(defCorp, nil, atkLost) //防守方击杀
defBaseData.roundBaseInfo.CorpList = append(defBaseData.roundBaseInfo.CorpList, defCorpBattleInfo)
}
if nil != atkEnemyCorp && nil != defLost {
defCorpBattleInfo := recordCropsBattleInfo(atkEnemyCorp, defLost, nil) //防守方损失
defBaseData.roundBaseInfo.CorpList = append(defBaseData.roundBaseInfo.CorpList, defCorpBattleInfo)
}
atkCorp = nil
atkEnemyCorp = nil
defCorp = nil
defEnemyCorp = nil
}
}
return battleRlt_Continue
}
// 判断特殊技能 是否改变攻击对象顺序
func isRear(specialBuff []*stFightBuff) bool {
isRear := false
for _, buff := range specialBuff {
if buff.csvIndex == int32(proto.FightBuffAttibute_AttRear) {
rand := common.GetRandomNum(10000)
if rand <= int32(buff.params[0]) {
isRear = true
}
}
}
return isRear
}
// 是否攻击对象是防御方里存活唯一的部队
func isOnlyCorp(defBaseData *stBattleActionBaseData, atkEnemyCorp *stCorps) bool {
tmp := make([]*stCorps, 0)
for _, v := range defBaseData.formation.unitData {
for _, tmpCorp := range v {
if tmpCorp != nil && tmpCorp.curAllUnitNum > 0 {
tmp = append(tmp, tmpCorp)
}
}
}
isOnly := false
if len(tmp) == 1 && atkEnemyCorp != nil && tmp[0].unitType == atkEnemyCorp.unitType {
isOnly = true
}
return isOnly
}
// 获取当前攻击部队在整个所有部队中的占比
func getAtkCorpPer(atkBaseData *stBattleActionBaseData, atkCorp *stCorps) uint32 {
if atkCorp == nil || atkBaseData == nil {
return 0
}
totalNum := uint32(0)
for _, v := range atkBaseData.formation.unitData {
for _, tmpCorp := range v {
if tmpCorp != nil {
totalNum += tmpCorp.curAllUnitNum
}
}
}
if totalNum > 0 {
return atkCorp.curAllUnitNum * 10000 / totalNum
}
return 0
}
/**
@brief 军团攻击是否命中
*/
func isHit(atkCorps *stCorps, defCorps *stCorps, commonBattleParm *stCommonBattleParm, atkGlobalAttribute map[uint64]uint64) bool {
/*公式
f(攻击方命中等级,受击方命中抵抗)= 攻击方命中等级÷(A×攻击方命中等级+B×受击方命中抵抗)×C;
攻击方兵团命中率 = max(Σ各途径命中率加值 + f(攻击方命中等级,受击方命中抵抗),命中率下限)
0 ≤ f(攻击方命中等级,受击方命中抵抗)≤ 100%
*/
if nil == atkCorps || nil == defCorps || nil == commonBattleParm {
return false
}
//陷阱百分百命中
if atkCorps.unitType >= proto.UnitBattleType_UBT_NOMAL_TRAP1 &&
atkCorps.unitType <= proto.UnitBattleType_UBT_NOMAL_TRAP2 {
return true
}
atkHitLevel := atkCorps.attributeMap[attribute_Hit]
defDodgeLevel := defCorps.attributeMap[attribute_Dodge]
parm := commonBattleParm.hitParm
baseHitRate := float64(atkHitLevel) /
(float64(parm[0])*float64(atkHitLevel)/10000 + float64(parm[1])*float64(defDodgeLevel)/10000) * float64(parm[3]) / 10000
addHitRate := float64(getHitRateAdditional(atkCorps.unitType, atkGlobalAttribute)) / 10000
finalHitRate := math.Max(baseHitRate+addHitRate, float64(parm[3])/10000)
randomRate := rand.Float64()
if finalHitRate < randomRate {
return false
}
return true
}
/**
@brief 军团攻击是否暴击
*/
func isBaoJi(atkCorps *stCorps, defCorps *stCorps, commonBattleParm *stCommonBattleParm, atkGlobalAttribute map[uint64]uint64) bool {
/*公式
f(攻击方暴击等级,受击方暴击抵抗)= 攻击方暴击等级÷(A×攻击方暴击等级+B×受击方暴击抵抗)×C
攻击方兵团暴击率 = min(Σ各途径暴击率加值 + f(攻击方暴击等级,受击方暴击抵抗),暴击率上限)
0 ≤ f(攻击方暴击等级,受击方暴击抵抗)≤ 100%
*/
if nil == atkCorps || nil == defCorps || nil == commonBattleParm {
return false
}
atkBaojiLevel := atkCorps.attributeMap[attribute_Crit]
defKangBaoLevel := defCorps.attributeMap[attribute_OpposeCrit]
parm := commonBattleParm.baoJiParm
baseCritRate := float64(atkBaojiLevel) /
(float64(parm[0])*float64(atkBaojiLevel)/10000 + float64(parm[1])*float64(defKangBaoLevel)/10000) * float64(parm[2]) / 10000
addCritRate := float64(getCritRateAdditional(atkCorps.unitType, atkGlobalAttribute)) / 10000
finalCritRate := math.Min(baseCritRate+addCritRate, float64(parm[3])/10000)
randomRate := rand.Float64()
if finalCritRate < randomRate {
return false
}
return true
}
/**
@brief 战斗单位之间的战斗流程
isOnly 防守方部队是否是唯一部队
atkCorpPer 进攻方部队人数,在所有部队中的占比
*/
func unitFightUnitDamage(atkBaseData, defBaseData *stBattleActionBaseData, atkCorps, defCorps *stCorps,
commonBattleParm *stCommonBattleParm, wall *stWall, calcBaseDamage bool, targetType uint32, specailBuff []*stFightBuff, isOnly bool, atkCorpPer uint32) (uint32, float64) {
//defCorps为nil ,则意味着打的是城墙
if nil == atkCorps || nil == commonBattleParm || nil == atkBaseData || nil == defBaseData {
return fightRlt_None, 0
}
if uint32(0) == atkCorps.curAllUnitNum {
return fightRlt_None, 0
}
//是否命中
if nil != defCorps && false == isHit(atkCorps, defCorps, commonBattleParm, atkBaseData.globalAttribute) {
return fightRlt_Miss, 0
}
parm := commonBattleParm.battleDamageParm
damageRateLimit := commonBattleParm.attriDamageLimit
atk := float64(atkCorps.attributeMap[attribute_Atk])
def := float64(0)
if nil != defCorps {
def = float64(defCorps.attributeMap[attribute_Def])
} else if nil != wall {
def = float64(wall.wallDef)
}
/*
基础伤害 = k*(攻击方攻击+m)^2/(攻击方攻击*P+防守方防御*Q)
*/
reduceDef := uint64(0)
addDamageParam := uint32(0)
for _, buff := range specailBuff {
if buff.csvIndex == int32(proto.FightBuffAttibute_IgnoreDef) {
reduceDef += uint64(buff.params[0])
} else if buff.csvIndex == int32(proto.FightBuffAttibute_EneNum) {
if isOnly {
addDamageParam += buff.params[0]
}
} else if buff.csvIndex == int32(proto.FightBuffAttibute_UnitnumDamage) && atkCorpPer > 0 {
if atkCorpPer >= buff.params[0] {
addDamageParam += buff.params[1]
}
}
}
if reduceDef > 10000 {
reduceDef = 10000
}
damage := float64(parm[0]) / 10000 * math.Pow(atk+float64(parm[1])/10000, 2) / ((atk*float64(parm[2]) + def*float64(parm[3])*float64(10000-reduceDef)/10000) / 10000)
if false == calcBaseDamage {
//是否暴击
if isBaoJi(atkCorps, defCorps, commonBattleParm, atkBaseData.globalAttribute) {
damage = damage * float64(commonBattleParm.critDamageParm) / 100
}
/*
伤害加减
加成减免后伤害=暴击后伤害×(1+伤害加成-伤害减免)
*/
add := getDamageAdd(defBaseData.actionBaseType, commonBattleParm, atkBaseData, defBaseData, atkCorps.fightBuff, targetType)
add += uint64(addDamageParam)
reduce := uint64(0)
if nil != defCorps {
reduce = getDamageReduce(atkBaseData.actionBaseType, commonBattleParm, defBaseData.globalAttribute, defCorps.fightBuff, targetType)
}
damageRate := float64(10000 + int64(add) - int64(reduce))
damageRate = math.Max(float64(damageRateLimit[0]), damageRate)
damageRate = math.Min(float64(damageRateLimit[1]), damageRate)
damage = damage * damageRate / 10000
/*
克制
【最终伤害】=【加成减免后伤害】× 克制系数
*/
if nil != defCorps {
if atkV, atkOk := commonBattleParm.unitRestrainParm[int64(atkCorps.unitType)]; atkOk {
if defV, defOk := atkV.damageParm[uint32(defCorps.unitType)]; defOk {
//向上取整,避免出现无法击杀最后一个单位的情况
damage = damage * float64(defV) / 100
}
}
}
}
return fightRlt_Hit, damage
}
/**
@brief 处理技能CD事件
*/
func processSkillCD(baseData *stBattleActionBaseData) {
if nil == baseData {
return
}
for _, hero := range baseData.heroList {
for k, v := range hero.skillCDList {
if v == uint32(0) {
delete(hero.skillCDList, k)
} else if v > 0 {
hero.skillCDList[k] -= 1
}
}
}
}
/**
@brief 获取当前类型最高等级的兵种ID
*/
func getMaxUnitInfo(corps []*stCorps) *proto.ST_ShowUnit_PB {
tmpShowUnit := &proto.ST_ShowUnit_PB{
ShowUnitType: proto.SetUint32(0),
ShowUnitID: proto.SetInt64(0),
}
for i := len(corps) - 1; i >= 0; i-- {
corp := corps[i]
if nil == corp {
continue
}
tmpShowUnit.ShowUnitType = proto.SetUint32(uint32(corp.unitType))
maxLevel := int64(1)
for _, unit := range corp.startUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if nil == unitCSV {
continue
}
if maxLevel <= unitCSV.Quality {
maxLevel = unitCSV.Quality
tmpShowUnit.ShowUnitID = proto.SetInt64(unitCSV.ID)
}
if int64(4) == maxLevel {
return tmpShowUnit
}
}
}
return tmpShowUnit
}
/**
@brief 开始战斗
*/
func startBattle(targetType uint32, atkBaseData, defBaseData *stBattleActionBaseData,
commonBattleParm *stCommonBattleParm) (uint32, *proto.ST_BattleInfo_PB) {
var (
//返回值
battleRlt uint32 //进攻方是否获胜,0:逻辑错误 1:胜利 2:失败
battleInfo *proto.ST_BattleInfo_PB //战斗回放信息
)
battleRlt = battleRlt_Error
battleInfo = &proto.ST_BattleInfo_PB{}
if uint32(0) == targetType || nil == atkBaseData || nil == defBaseData ||
nil == commonBattleParm || nil == atkBaseData.formation || nil == defBaseData.formation {
return battleRlt, nil
}
battleInfo.TargetType = proto.SetUint32(targetType)
//阵型
battleInfo.AtkFormation = proto.SetUint32(atkBaseData.formation.id)
battleInfo.DefFormation = proto.SetUint32(defBaseData.formation.id)
//攻击方战斗起始的简单信息
atkSimpleStartInfo := &proto.ST_SimpleStartInfo_PB{
AllStartPower: proto.SetUint64(getAllPower(atkBaseData)),
StartHeroList: make([]uint32, 0),
StartUnitList: make([]*proto.ST_UnitCount_PB, 0),
ShowUnit: make([]*proto.ST_ShowUnit_PB, 0),
}
for _, hero := range atkBaseData.heroList {
atkSimpleStartInfo.StartHeroList = append(atkSimpleStartInfo.StartHeroList, hero.heroID)
if atkBaseData.userData != nil {
atkBaseData.userData.WithHeroAsset(true, hero.heroID, func(heroAsset *proto.ST_HeroEntry_PB) bool {
atkSimpleStartInfo.HeroPower = proto.SetUint64(atkSimpleStartInfo.GetHeroPower() + heroAsset.GetPower())
return false
})
}
}
for _, v := range atkBaseData.formation.unitData {
total := uint32(0)
var unitType proto.UnitBattleType
for _, corp := range v {
if nil != corp {
total += corp.curAllUnitNum
unitType = corp.unitType
}
}
if total > 0 {
unitCount := &proto.ST_UnitCount_PB{
UnitType: proto.SetUint32(uint32(unitType)),
UnitCount: proto.SetUint32(total),
}
atkSimpleStartInfo.StartUnitList = append(atkSimpleStartInfo.StartUnitList, unitCount)
}
tmpShowUnit := getMaxUnitInfo(v)
atkSimpleStartInfo.ShowUnit = append(atkSimpleStartInfo.ShowUnit, tmpShowUnit)
}
for _, v := range atkBaseData.formation.trapsData {
for _, trap := range v {
if nil != trap {
unitCount := &proto.ST_UnitCount_PB{
UnitType: proto.SetUint32(uint32(trap.unitType)),
UnitCount: proto.SetUint32(trap.curAllUnitNum),
}
atkSimpleStartInfo.StartUnitList = append(atkSimpleStartInfo.StartUnitList, unitCount)
}
}
}
battleInfo.AtkSimpleStartInfo = atkSimpleStartInfo
//防御方战斗起始的简单信息
defSimpleStartInfo := &proto.ST_SimpleStartInfo_PB{
AllStartPower: proto.SetUint64(getAllPower(defBaseData)),
StartHeroList: make([]uint32, 0),
StartUnitList: make([]*proto.ST_UnitCount_PB, 0),
ShowUnit: make([]*proto.ST_ShowUnit_PB, 0),
}
if defBaseData.wall != nil {
defSimpleStartInfo.WallLevel = proto.SetUint32(defBaseData.wall.wallLevel)
}
//城墙
if nil != defBaseData.wall {
defSimpleStartInfo.StartWallHp = proto.SetUint64(defBaseData.wall.startWallHp)
}
for _, hero := range defBaseData.heroList {
defSimpleStartInfo.StartHeroList = append(defSimpleStartInfo.StartHeroList, hero.heroID)
if defBaseData.userData != nil {
defBaseData.userData.WithHeroAsset(true, hero.heroID, func(heroAsset *proto.ST_HeroEntry_PB) bool {
defSimpleStartInfo.HeroPower = proto.SetUint64(defSimpleStartInfo.GetHeroPower() + heroAsset.GetPower())
return false
})
}
}
for _, v := range defBaseData.formation.unitData {
total := uint32(0)
var unitType proto.UnitBattleType
for _, corp := range v {
if nil != corp {
total += corp.curAllUnitNum
unitType = corp.unitType
}
}
if total > 0 {
unitCount := &proto.ST_UnitCount_PB{
UnitType: proto.SetUint32(uint32(unitType)),
UnitCount: proto.SetUint32(total),
}
defSimpleStartInfo.StartUnitList = append(defSimpleStartInfo.StartUnitList, unitCount)
}
tmpShowUnit := getMaxUnitInfo(v)
defSimpleStartInfo.ShowUnit = append(defSimpleStartInfo.ShowUnit, tmpShowUnit)
}
for _, v := range defBaseData.formation.trapsData {
total := uint32(0)
var unitType proto.UnitBattleType
for _, corp := range v {
if nil != corp {
total += corp.curAllUnitNum
unitType = corp.unitType
}
}
if total > 0 {
unitCount := &proto.ST_UnitCount_PB{
UnitType: proto.SetUint32(uint32(unitType)),
UnitCount: proto.SetUint32(total),
}
defSimpleStartInfo.StartUnitList = append(defSimpleStartInfo.StartUnitList, unitCount)
}
tmpShowUnit := getMaxUnitInfo(v)
defSimpleStartInfo.ShowUnit = append(defSimpleStartInfo.ShowUnit, tmpShowUnit)
}
battleInfo.DefSimpleStartInfo = defSimpleStartInfo
isEnd := false
for round := uint32(0); round < commonBattleParm.maxbattleRound; round++ {
atkBaseData.roundBaseInfo = &proto.ST_RoundBaseInfo_PB{
HeroList: make([]*proto.ST_HeroBattleInfo_PB, 0),
CorpList: make([]*proto.ST_CorpBattleInfo_PB, 0),
}
defBaseData.roundBaseInfo = &proto.ST_RoundBaseInfo_PB{
HeroList: make([]*proto.ST_HeroBattleInfo_PB, 0),
CorpList: make([]*proto.ST_CorpBattleInfo_PB, 0),
}
//---------记录回合开始前的信息-------
//战斗力
atkBaseData.roundBaseInfo.CurPower = proto.SetUint64(getAllPower(atkBaseData))
defBaseData.roundBaseInfo.CurPower = proto.SetUint64(getAllPower(defBaseData))
//城墙
if nil != defBaseData.wall {
defBaseData.roundBaseInfo.WallHp = &proto.ST_WallReport_PB{
BeforeHp: proto.SetUint32(uint32(defBaseData.wall.startWallHp)),
AfterHp: proto.SetUint32(uint32(defBaseData.wall.curWallHp)),
}
}
//---------记录回合开始前的信息-------
//处理技能CD
processSkillCD(atkBaseData)
processSkillCD(defBaseData)
//处理战斗buff
processFightBuff(atkBaseData, defBaseData, 0)
processFightBuff(defBaseData, atkBaseData, 0)
battleRlt = checkBattleRlt(atkBaseData, defBaseData)
if battleRlt_Continue != battleRlt {
isEnd = true
goto end
}
//处理英雄战斗
battleRlt = processHeroFight(targetType, atkBaseData, defBaseData, commonBattleParm)
if battleRlt_Continue != battleRlt {
isEnd = true
goto end
}
//处理军团战斗
battleRlt = processCorpsFight(targetType, atkBaseData, defBaseData, commonBattleParm)
if battleRlt_Continue != battleRlt {
isEnd = true
goto end
}
end:
//---------记录回合结束后的信息----------
//战斗力
atkBaseData.roundBaseInfo.CurPower = proto.SetUint64(getAllPower(atkBaseData))
defBaseData.roundBaseInfo.CurPower = proto.SetUint64(getAllPower(defBaseData))
//城墙血量
if nil != defBaseData.wall {
defBaseData.roundBaseInfo.WallHp.AfterHp = proto.SetUint32(uint32(defBaseData.wall.curWallHp))
}
battleRoundInfo := &proto.ST_BattleRoundInfo_PB{
Round: proto.SetUint32(round),
AtkRoundInfo: atkBaseData.roundBaseInfo,
DefRoundInfo: defBaseData.roundBaseInfo,
}
//---------记录回合结束后的信息----------
battleInfo.RoundInfo = append(battleInfo.RoundInfo, battleRoundInfo)
if isEnd {
break
}
}
if false == isEnd {
battleRlt = battleRlt_Over
}
return battleRlt, battleInfo
}
/**
@brief 准备英雄数据
*/
func prepareHeros(outBaseData *stBattleActionBaseData, uid uint64, heroIDList []uint32) bool {
if nil == outBaseData || 0 == uid {
return false
}
outBaseData.userData = cache.GetCharinfo(uid)
if nil == outBaseData.userData {
return false
}
//防守方城墙信息
if outBaseData.actionBaseType == actionBase_Def {
//需要从城墙资源获取
outBaseData.wall = &stWall{
startWallHp: uint64(GetCurDurable(outBaseData.userData)),
curWallHp: uint64(GetCurDurable(outBaseData.userData)),
wallDef: outBaseData.userData.GetWallDefValue(),
fightBuff: make(map[uint32]*stFightBuff),
}
level := outBaseData.userData.GetWallLevel()
outBaseData.wall.wallLevel = level
}
//拷贝全局属性,此属性会持续整个战斗过程
outBaseData.globalAttribute = outBaseData.userData.CopyAllAttribute()
//英雄信息
outBaseData.heroList = make([]*stHeroBattleInfo, 0)
if 0 == len(heroIDList) {
return true
}
for _, heroID := range heroIDList {
outBaseData.userData.WithHeroAsset(true, heroID, func(heroAsset *proto.ST_HeroEntry_PB) bool {
heroBattleInfo := &stHeroBattleInfo{}
heroBattleInfo.heroID = heroID
//heroBattleInfo.mainType = heroAsset.GetMaintype()
heroBattleInfo.level = heroAsset.GetLevel()
heroBattleInfo.star = heroAsset.GetStar()
//heroBattleInfo.rank = heroAsset.GetRank()
heroBattleInfo.fightBuff = make(map[uint32]*stFightBuff)
heroBattleInfo.skillCDList = make(map[uint32]uint32)
//英雄技能,只放(主动技能和被动特殊技能,后面处理完会删除被动特殊技能)
heroBattleInfo.skillList = make([]*proto.ST_HeroSkill_PB, 0)
for _, v := range heroAsset.GetSkillList() {
skillcsv := CSV.Mgr.CSV_HeroNewSkills.GetEntryPtr(int64(v.GetSkillID()))
if nil == skillcsv {
continue
}
// 初始化技能CD
heroBattleInfo.skillCDList[uint32(skillcsv.ID)] = uint32(skillcsv.CD)
heroBattleInfo.skillList = append(heroBattleInfo.skillList, proto.Clone(v).(*proto.ST_HeroSkill_PB))
}
heroBattleInfo.branceValue = make([]uint32, len(heroAsset.GetBranchValue()))
copy(heroBattleInfo.branceValue, heroAsset.GetBranchValue())
//把战斗被动技能加入全局属性中
MarchAtt := outBaseData.userData.CalcHeroSkillAttribute(heroAsset, proto.SkillSubType_ST_PASSIVE_FIGHT)
for k, v1 := range MarchAtt {
id := uint64(k)<<32 | uint64(proto.AttributeSource_Hero)
if v2, ok := outBaseData.globalAttribute[id]; ok {
outBaseData.globalAttribute[id] = v1 + v2
} else {
outBaseData.globalAttribute[id] = v1
}
}
// 把英雄4属性加入全局属性中
MarchAtt = outBaseData.userData.GetHeroBranchAttribute(heroAsset)
for k, v1 := range MarchAtt {
id := uint64(k)<<32 | uint64(proto.AttributeSource_Hero)
if v2, ok := outBaseData.globalAttribute[id]; ok {
outBaseData.globalAttribute[id] = v1 + v2
} else {
outBaseData.globalAttribute[id] = v1
}
}
outBaseData.heroList = append(outBaseData.heroList, heroBattleInfo)
return false
})
}
outBaseData.roundBaseInfo = &proto.ST_RoundBaseInfo_PB{}
return true
}
/**
@brief 准备军团数据
@parm:
actionid:主行为id 非大地图行为时,地块拥有者的行为ID都是0
childrenActionID:子行为id
units:当前行为军团信息
formationID:阵型
*/
func prepareUnits(mainActionID uint64, childrenActionID []uint64, units *proto.ST_UnitAsset_PB, formationID uint32) (bool,
*stFormation, map[uint64]*stUserUnitInfo) {
var (
//全部都为返回值
ok = true //结果
formation *stFormation //阵型兵力
orgiUnitAssetMap map[uint64]*stUserUnitInfo //记录多人攻击玩家的原始兵力资产 key:acitonid value:相关兵力资产
//以下不返回
formationRlt = false
analysisRlt = false
allUnits = &proto.ST_UnitAsset_PB{}
corpsMap = &stCorpsMap{}
tmpTotalPower = int64(0)
userUnitInfo *stUserUnitInfo //玩家兵力信息
tmpCorpPower = make(map[proto.UnitBattleType]int64) //各个军团合计的总战力(每个兵种一个军团)
tmpUnitPower = make(map[uint32]int64) //记录不同等级兵种各自的总战力
mainAsset *cache.GlobalActionEntry
tmpMainActionID uint64
)
if nil == units {
ok = false
goto endPrepareUnits
}
//把带头大哥和小弟的兵力加起来(allUnits),并分别记录(orgiUnitAssetMap)
common.CombineUnitAsset(allUnits, units)
orgiUnitAssetMap = make(map[uint64]*stUserUnitInfo)
userUnitInfo = analysisUnitAssetToUserUnitInfo(units)
userUnitInfo.isBigBrother = true
tmpTotalPower += userUnitInfo.totalPower
tmpMainActionID = mainActionID
//当为玩家主城防守方时,actionID为玩家ID
//其余时候为全局行为id
mainAsset = cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(mainActionID)
if mainAsset != nil {
userUnitInfo.charUID = mainAsset.Actiondata.GetUid()
} else {
userData := cache.GetCharinfo(mainActionID)
if nil != userData {
tmpMainActionID = 0
userUnitInfo.charUID = userData.GetUid()
}
}
orgiUnitAssetMap[tmpMainActionID] = userUnitInfo
if 0 != len(childrenActionID) {
for _, v := range childrenActionID {
if mainActionID == v {
continue
}
tmpAsset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpAsset == nil {
continue
}
common.CombineUnitAsset(allUnits, tmpAsset.Actiondata.GetUnits())
userUnitInfo = analysisUnitAssetToUserUnitInfo(tmpAsset.Actiondata.GetUnits())
userUnitInfo.isBigBrother = false
userUnitInfo.charUID = tmpAsset.Actiondata.GetUid()
tmpTotalPower += userUnitInfo.totalPower
orgiUnitAssetMap[v] = userUnitInfo
}
}
//开始计算玩家各个军团在整体军团中的战力比
for _, userUnitInfo := range orgiUnitAssetMap {
for corpType, corp := range userUnitInfo.unitMap {
if _, ok := tmpCorpPower[corpType]; !ok {
tmpCorpPower[corpType] = 0
}
for _, unitInfo := range corp {
tmpCorpPower[corpType] = tmpCorpPower[corpType] + unitInfo.power
if v, ok := tmpUnitPower[unitInfo.unit.GetUnitid()]; !ok {
tmpUnitPower[unitInfo.unit.GetUnitid()] = unitInfo.power
} else {
tmpUnitPower[unitInfo.unit.GetUnitid()] = v + unitInfo.power
}
}
}
}
for _, userUnitInfo := range orgiUnitAssetMap {
userUnitInfo.corpRatioMap = make(map[proto.UnitBattleType]float32, len(tmpCorpPower))
userUnitInfo.unitRatioMap = make(map[uint32]float32, len(tmpUnitPower))
for corpType, unitList := range userUnitInfo.unitMap {
selfCorpPower := int64(0) //一个军团的总战力
if corpTotalPower, ok := tmpCorpPower[corpType]; ok && int64(0) != corpTotalPower {
for _, unitInfo := range unitList {
selfCorpPower += unitInfo.power
}
userUnitInfo.corpRatioMap[corpType] = float32(selfCorpPower) / float32(corpTotalPower)
} else {
userUnitInfo.corpRatioMap[corpType] = 0
}
for _, unitInfo := range unitList {
if unitTotalPower, ok := tmpUnitPower[unitInfo.unit.GetUnitid()]; ok && int64(0) != unitTotalPower {
userUnitInfo.unitRatioMap[unitInfo.unit.GetUnitid()] = float32(unitInfo.power) / float32(unitTotalPower)
} else {
userUnitInfo.unitRatioMap[unitInfo.unit.GetUnitid()] = 0
}
}
}
}
//按类型解析兵力
analysisRlt = analysisUnitAssetToCorpsMap(corpsMap, allUnits)
if false == analysisRlt {
ok = false
goto endPrepareUnits
}
//再根据阵型设置军团位置
formationRlt, formation = setFormation(formationID, corpsMap)
if false == formationRlt {
ok = false
goto endPrepareUnits
}
//战斗单位单个战斗力
for _, v := range formation.unitData {
for _, corps := range v {
if corps == nil {
continue
}
corps.unitPower = make(map[uint32]uint64, len(corps.startUnits))
for _, unit := range corps.startUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if nil == unitCSV {
continue
}
corps.unitPower[unit.GetUnitid()] = uint64(unitCSV.Power)
}
}
}
for _, v := range formation.trapsData {
for _, corps := range v {
if corps == nil {
continue
}
corps.unitPower = make(map[uint32]uint64, len(corps.startUnits))
for _, unit := range corps.startUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if nil == unitCSV {
continue
}
corps.unitPower[unit.GetUnitid()] = uint64(unitCSV.Power)
}
}
}
endPrepareUnits:
return ok, formation, orgiUnitAssetMap
}
/**
@brief 准备战斗时的全局参数
*/
func perpareCommonBattleParm() *stCommonBattleParm {
if nil == CommonBattleParm {
commonBattleParm := &stCommonBattleParm{}
//最大战斗回合数
commonBattleParm.maxbattleRound = CSV.GetGameConfigValueUint32("MAX_BATTLE_ROUND")
//兵种克制
commonBattleParm.unitRestrainParm = make(map[int64]*stRestrainParm)
commonBattleParm.corpAtkOrder = make(map[int64]int64)
for _, k := range CSV.Mgr.CSV_UnitRestrain.GetIDList() {
csvRestrain := CSV.Mgr.CSV_UnitRestrain.GetEntryPtr(k)
if nil == csvRestrain {
continue
}
if _, ok := commonBattleParm.unitRestrainParm[csvRestrain.ID]; ok {
continue
}
restrainParm := &stRestrainParm{}
//先初始化一次,避免配置表少配
restrainParm.damageParm = map[uint32]uint32{1: 100, 2: 100, 3: 100, 4: 100, 5: 100, 6: 100, 7: 100, 8: 100, 9: 0, 10: 100}
commonBattleParm.unitRestrainParm[csvRestrain.ID] = restrainParm
parmList := common.ParseStringToUint32List(csvRestrain.RestraionParm)
for parmK, parmV := range parmList {
restrainParm.damageParm[uint32(parmK)+1] = parmV
}
commonBattleParm.corpAtkOrder[csvRestrain.ID] = csvRestrain.AtkOrder
}
//命中参数
commonBattleParm.hitParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_HIT_PARM"))
//暴击参数
commonBattleParm.baoJiParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_CRIT_PARM"))
//战斗伤害参数
commonBattleParm.battleDamageParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_DAMAGE_PARM"))
//暴击额外伤害
commonBattleParm.critDamageParm = CSV.GetGameConfigValueUint32("CRIT_DAMAGE_PARM")
//伤害加减范围
commonBattleParm.attriDamageLimit = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("ATTRI_DAMAGE_LIMIT"))
//特殊行为系数里的参数
commonBattleParm.skillSpecialParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("SKILL_SPECIAL_PARM"))
//攻击参数
commonBattleParm.atkParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_ATK_PARM"))
//防御参数
commonBattleParm.defParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_DEF_PARM"))
//陷阱自毁系数
commonBattleParm.trapLossParm = CSV.GetGameConfigValueUint32("BATTLE_TRAP_LOSS_PARM")
//血量衰减系数
commonBattleParm.hpParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_HP_PARM"))
CommonBattleParm = commonBattleParm
}
return CommonBattleParm
}
/**
@brief 战斗准备
*/
func prepareBattlePara( /*dataEntry *proto.ST_GlobalActionEntry_PB*/ battleKey *stBattleKey) (bool,
uint32, *stBattleActionBaseData, *stBattleActionBaseData, *stCommonBattleParm,
*cache.WorldDataEntry, map[uint64]*stUserUnitInfo, map[uint64]*stUserUnitInfo) {
var (
//需要返回的变量
ok bool //结果
targetType uint32 //目标类型
atkBaseData *stBattleActionBaseData //攻击方战斗基本数据
defBaseData *stBattleActionBaseData //防守方战斗基本数据
commonBattleParm *stCommonBattleParm //用于各种公式计算的参数,攻守方通用
worldAssetData *cache.WorldDataEntry //目的地大地图信息
atkOrgiUnitAssetMap map[uint64]*stUserUnitInfo //记录多人攻击玩家的原始兵力资产 key:acitonid value:兵力资产
defOrgiUnitAssetMap map[uint64]*stUserUnitInfo //记录多人防御玩家的原始兵力资产
//无需返回的变量
herosRlt bool
wdata *proto.ST_WorldDataEntry_PB
csvWorldConfig *CSV.CF_WorldEntryConfig_DataEntry
entryType int64
monsterGroupID int64
mainAsset *cache.GlobalActionEntry
monsterAtk bool
)
ok = true
if nil == battleKey {
ok = false
goto endPrepareBattlePara
}
//准备进攻方数据
//进攻方玩家信息
atkBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Atk,
}
mainAsset = cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(battleKey.actionID)
if mainAsset != nil && mainAsset.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MACATTCK) {
//怪物攻城
ocfg := CSV.Mgr.CSV_WorldEntryConfig.GetEntryPtr(mainAsset.Actiondata.GetMacMonsterId())
if ocfg == nil {
wlog.Error("CSV_WorldEntryConfig.GetEntryPtr return nil, id:", mainAsset.Actiondata.GetMacMonsterId())
goto endPrepareBattlePara
}
ok, base, def := getMacAtkInfo(battleKey, ocfg.MonsterID)
if !ok {
goto endPrepareBattlePara
}
base.monsterAtk = true
atkBaseData = base
atkOrgiUnitAssetMap = def
monsterAtk = true
} else {
//准备英雄及其技能信息
herosRlt = prepareHeros(atkBaseData, battleKey.UID, battleKey.heroIDList)
if false == herosRlt {
ok = false
goto endPrepareBattlePara
}
//进攻方阵型信息
ok, atkBaseData.formation, atkOrgiUnitAssetMap = prepareUnits(battleKey.actionID,
battleKey.childrenID, battleKey.units, battleKey.formation)
if false == ok {
goto endPrepareBattlePara
}
}
if int32(0) != battleKey.endTileID {
worldAssetData = cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(battleKey.endTileID)
if worldAssetData == nil {
ok = false
goto endPrepareBattlePara
}
//不允许目的地是自己或者公会的地块
if atkBaseData.userData != nil && isOurForce(atkBaseData.userData.GetUid(), atkBaseData.userData.GetLeagueID(), worldAssetData.GetWorldDataOwner(), worldAssetData.GetLeagueOwner()) {
ok = false
goto endPrepareBattlePara
}
wdata = worldAssetData.GetWorldData()
csvWorldConfig = worldAssetData.GetWorldEntryConfig()
if csvWorldConfig == nil {
ok = false
goto endPrepareBattlePara
}
entryType = csvWorldConfig.EntryType
if (entryType > int64(proto.WorldEntryType_WET_MINE_START) && entryType < int64(proto.WorldEntryType_WET_MINE_END)) ||
entryType == int64(proto.WorldEntryType_WET_BESTATIONED) {
if len(wdata.SimpleEntry.GetGActionList()) == 0 {
ok = false
goto endPrepareBattlePara
}
}
} else {
entryType = int64(proto.WorldEntryType_WET_WILDMONSTER)
monsterGroupID = battleKey.monsterGroupID
targetType = battleKey.targetType
}
//根据地块类型设置目标类型,
//根据不同的地块(即战斗场景)准备防御方的数据
//无论目标类型,进入这里都是要战斗的
switch entryType {
case int64(proto.WorldEntryType_WET_CITY):
fallthrough
case int64(proto.WorldEntryType_WET_CAPITAL_CITY):
fallthrough
case int64(proto.WorldEntryType_WET_SMALL_MIRACLE):
fallthrough
case int64(proto.WorldEntryType_WET_LEAGUE_Center):
fallthrough
case int64(proto.WorldEntryType_WET_BIG_MIRACLE):
{
var npcUnitAsset *proto.ST_UnitAsset_PB = nil
targetType = getWorldDataTargetType(worldAssetData)
npcUnitAsset = wdata.DetailEntry.Detail_City.GetNpcUnits()
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Def,
}
if nil != npcUnitAsset && 0 != len(npcUnitAsset.Units) {
defBaseData.actionBaseType = actionBase_Monster
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(0, nil, npcUnitAsset, 0)
if false == ok {
goto endPrepareBattlePara
}
} else {
var mainGlobalActionEntry *proto.ST_GlobalActionEntry_PB = nil
actionIDList := make([]uint64, 0) //子行为id
for k, v := range wdata.SimpleEntry.GetGActionList() {
tmpasset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpasset == nil {
continue
}
if k == 0 {
mainGlobalActionEntry = tmpasset.Actiondata
ok = prepareHeros(defBaseData, mainGlobalActionEntry.GetUid(), mainGlobalActionEntry.GetHeroIDList())
defBaseData.wall = nil
if false == ok {
goto endPrepareBattlePara
}
}
if tmpasset.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_GARRISON) &&
tmpasset.Actiondata.GetStage() == uint32(proto.MapStageType_MST_WORKING) {
actionIDList = append(actionIDList, tmpasset.Actiondata.GetActionid())
}
}
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(mainGlobalActionEntry.GetActionid(),
actionIDList, mainGlobalActionEntry.GetUnits(), mainGlobalActionEntry.GetFormation())
if false == ok {
goto endPrepareBattlePara
}
}
}
case int64(proto.WorldEntryType_WET_MAINCITY):
{
targetType = targetMainCity
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Def,
}
defBaseData.userData = cache.GetCharinfo(wdata.SimpleEntry.GetUid())
//获取守城英雄ID
var defCityHeroList []uint32
defBaseData.userData.ForeachHero(true, func(heroAsset *proto.ST_HeroEntry_PB) bool {
if heroAsset == nil {
return false
}
if heroAsset.GetHeroStatus() == uint32(proto.HeroStatus_HS_DEFENSE) {
defCityHeroList = append(defCityHeroList, heroAsset.GetId())
}
return true
})
herosRlt := prepareHeros(defBaseData, wdata.SimpleEntry.GetUid(), defCityHeroList)
if false == herosRlt {
ok = false
goto endPrepareBattlePara
}
//防守方阵型信息
for _, v := range defBaseData.userData.CopyGarrisonList() {
//获取援助行为id
tmpGlobalAction := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpGlobalAction == nil || tmpGlobalAction.Actiondata.GetStage() != uint32(proto.MapStageType_MST_WORKING) {
continue
}
}
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(wdata.SimpleEntry.GetUid(),
defBaseData.userData.CopyGarrisonList(), defBaseData.userData.GetUnitAsset(), 0) //需要从玩家身上获取阵型
if monsterAtk {
defBaseData.monsterAtk = true
}
if false == ok {
goto endPrepareBattlePara
}
}
case int64(proto.WorldEntryType_WET_MUTIWILDMONSTER):
fallthrough
case int64(proto.WorldEntryType_WET_WILDMONSTER):
fallthrough
case int64(proto.WorldEntryType_WET_SUMMON_MUTIWILDMONSTER):
fallthrough
case int64(proto.WorldEntryType_WET_WILDMONSTEREX):
{
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Monster,
}
if targetType == uint32(targetUnUse) {
targetType = getWorldDataTargetType(worldAssetData)
monsterGroupID = csvWorldConfig.MonsterID
}
//获取怪物的城墙,英雄,战斗单位信息
ok, wall, heroList, unitAsset, formationId, globalAttribute, _, _ := getMonsterBattleUnitInfo(monsterGroupID)
if false == ok {
ok = false
goto endPrepareBattlePara
}
defBaseData.monsterGroupID = monsterGroupID
defBaseData.heroList = heroList
defBaseData.wall = wall
defBaseData.globalAttribute = globalAttribute
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(0, nil, unitAsset, formationId)
}
case int64(proto.WorldEntryType_WET_BESTATIONED):
{
targetType = targetBestationed
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Def,
}
defBaseData.userData = cache.GetCharinfo(wdata.SimpleEntry.GetUid())
herosRlt := prepareHeros(defBaseData, wdata.SimpleEntry.GetUid(), worldAssetData.GetBeStationedHero())
defBaseData.wall = nil
if false == herosRlt {
ok = false
goto endPrepareBattlePara
}
//防守方阵型信息
for _, k := range worldAssetData.GetGActionList() {
if k == battleKey.actionID {
continue
}
//获取驻扎行为的actionid
tmpGlobalAction := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(k)
if tmpGlobalAction == nil || tmpGlobalAction.Actiondata.GetActiontype() != uint32(proto.ActionType_AT_WORLDMAP_BESTATIONED) {
continue
}
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(k,
nil, tmpGlobalAction.Actiondata.GetUnits(), worldAssetData.GetBeStationedFormation())
break
}
if false == ok {
goto endPrepareBattlePara
}
}
case int64(proto.WorldEntryType_WET_MINE_COKE):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_CRYSTAL):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_DEUTERIUM):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_GAS):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_METAL):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_GEM):
{
//targetType = targetMine
targetType = getWorldDataTargetType(worldAssetData)
if len(wdata.SimpleEntry.GetGActionList()) == 0 {
ok = false
goto endPrepareBattlePara
}
var mainGlobalActionEntry *proto.ST_GlobalActionEntry_PB = nil
targetSubActionIDList := make([]uint64, 0) //目标子行为id
for _, v := range wdata.SimpleEntry.GetGActionList() {
tmpasset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpasset == nil {
continue
}
//不管地块上非采集的行为
if tmpasset.Actiondata.GetActiontype() != uint32(proto.ActionType_AT_WORLDMAP_COLLECT) {
continue
}
//排除掉自己在此地块上的行为
if tmpasset.Actiondata.GetActionid() == battleKey.actionID {
continue
}
tmpUser := cache.GetCharinfo(tmpasset.Actiondata.GetUid())
if nil == tmpUser {
continue
}
//采集点上不是自己人,则开战
var needBattle bool = false
if atkBaseData.userData.GetLeagueID() != tmpasset.Actiondata.GetLeagueID() {
needBattle = true
}
if atkBaseData.userData.GetLeagueID() == 0 || tmpasset.Actiondata.GetLeagueID() == 0 {
needBattle = true
}
if nil == mainGlobalActionEntry {
//准备防御方的英雄及其技能信息
//只取第一个玩家的信息
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Def,
}
mainGlobalActionEntry = tmpasset.Actiondata
herosRlt := prepareHeros(defBaseData, mainGlobalActionEntry.GetUid(), mainGlobalActionEntry.GetHeroIDList())
defBaseData.wall = nil
if false == herosRlt {
ok = false
goto endPrepareBattlePara
}
} else if needBattle && nil != mainGlobalActionEntry {
targetSubActionIDList = append(targetSubActionIDList, tmpasset.Actiondata.GetActionid())
}
}
if mainGlobalActionEntry != nil {
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(mainGlobalActionEntry.GetActionid(),
targetSubActionIDList, mainGlobalActionEntry.GetUnits(), mainGlobalActionEntry.GetFormation())
}
if false == ok {
goto endPrepareBattlePara
}
}
default:
ok = false
}
// 处理英雄特殊被动技能
if ok {
prepareHeroSpecialPassiveSkill(atkBaseData)
prepareHeroSpecialPassiveSkill(defBaseData)
}
//准备战斗全局的固定参数
commonBattleParm = perpareCommonBattleParm()
endPrepareBattlePara:
return ok, targetType, atkBaseData, defBaseData, commonBattleParm,
worldAssetData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap
}
func prepareHeroSpecialPassiveSkill(atkBaseData *stBattleActionBaseData) {
if nil == atkBaseData || atkBaseData.heroList == nil {
return
}
for _, hero := range atkBaseData.heroList {
tmpSkill := make([]*proto.ST_HeroSkill_PB, 0)
for _, skill := range hero.skillList {
skillCsv := CSV.Mgr.CSV_HeroNewSkills.GetEntryPtr(int64(skill.GetSkillID()))
if skillCsv != nil && skillCsv.SkillType == int64(proto.SkillMainType_ST_PASSIVE) {
tmpMap := common.ParseParameterStringToMap(skillCsv.SkillEffect)
tmpMap1 := common.ParseParameterStringToMap(skillCsv.SkillSubType)
extraMap := common.ParseParameterStringToMap(skillCsv.ExtraParam)
for k, v := range tmpMap {
subType, ok := tmpMap1[k]
if !ok || common.StringToUint32(subType) != uint32(proto.SkillSubType_ST_PASSIVE_BUFF) {
continue
}
if buffType, ok := proto.FightBuffAttibute_value[k]; ok {
// 单位攻击顺序buff
params := common.ParseStringToUint32List(v) //
if len(params) != 3 {
wlog.Error("skill skillEffect err", skillCsv.ID)
continue
}
value, ok := extraMap[k]
if !ok {
wlog.Error("skill skillEffect err", skillCsv.ID)
continue
}
extraParam := common.ParseStringToUint32List(value)
_, heros, corps, traps := getEffectTarget(proto.UnitBattleType_UBT_NOMAL_NONE, params[0], atkBaseData, hero)
for _, corp := range corps {
corp.specialBuff = addSpecialBuff(hero, buffType, skillCsv, extraParam, corp.specialBuff)
}
for _, trap := range traps {
trap.specialBuff = addSpecialBuff(hero, buffType, skillCsv, extraParam, trap.specialBuff)
}
for _, heroInfo := range heros {
heroInfo.specialBuff = addSpecialBuff(hero, buffType, skillCsv, extraParam, heroInfo.specialBuff)
}
}
}
} else {
tmpSkill = append(tmpSkill, skill)
}
}
hero.skillList = tmpSkill
}
}
func addSpecialBuff(hero *stHeroBattleInfo, buffType int32, skillCsv *CSV.CF_HeroNewSkills_DataEntry, params []uint32, buffs []*stFightBuff) []*stFightBuff {
var buff *stFightBuff
for _, v := range buffs {
if v.csvIndex == buffType {
buff = v
break
}
}
if buff != nil {
replace := false
switch buffType {
case int32(proto.FightBuffAttibute_AttConversion), int32(proto.FightBuffAttibute_UnitnumDamage):
buff = nil
case int32(proto.FightBuffAttibute_AttRear), int32(proto.FightBuffAttibute_IgnoreDef):
if buff.params[0] < params[0] {
replace = true
}
case int32(proto.FightBuffAttibute_EneNum):
if buff.params[0] < params[0] {
replace = true
}
}
if replace {
buff.heroID = hero.heroID
buff.csvIndex = buffType
buff.orgiSkillID = skillCsv.ID
//buff.effectValue = uint64(params[2])
buff.params = params
}
}
if buff == nil {
buff = &stFightBuff{}
buff.heroID = hero.heroID
buff.csvIndex = buffType
buff.orgiSkillID = skillCsv.ID
//buff.effectValue = uint64(params[2])
buff.params = params
buffs = append(buffs, buff)
}
return buffs
}
/**
@brief 获取行为的目的地类型
*/
func getBattleTargetType(dataEntry *proto.ST_GlobalActionEntry_PB) uint32 {
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(dataEntry.GetEndTileID())
if worldAssetData == nil {
return targetUnUse
}
return getWorldDataTargetType(worldAssetData)
}
/**
@brief 计算战后大奇迹援军的兵力(老逻辑,未完成)
*/
func calcBigMiracleGarrsonCapAfterBattle(cityData *cache.WorldDataEntry) {
if nil == cityData {
return
}
actionIds := cityData.CopyGActionList()
if len(actionIds) <= 0 {
return
}
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionIds[0])
if actionData == nil || actionData.Actiondata == nil {
return
}
userData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if nil == userData {
return
}
details := make([]uint64, 0)
function := userData.GetBuildingFuctionByConfigType(int64(proto.BuildingType_BT_COMMAND))
capability := common.StringToUint64(function["capability"])
capability = countAdditional(capability, userData, proto.AtttibuteType_MaxAggregation) // 1003;//联盟集结上限(百分比)
var totalCount uint64
for _, v := range actionIds {
tmpAction := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpAction == nil || tmpAction.Actiondata == nil {
continue
}
totalCount += countUnitNum(tmpAction.Actiondata.GetUnits())
}
details = append(details, capability)
details = append(details, totalCount)
actionData.Actiondata.Details = details
actionData.Dirty()
}
/**
@brief 战斗后处理主城监狱资产
*/
func processPrisonAfterBattle(atkInfos []*proto.ST_BattleReportDetail_PB, attUserData, defUserData *cache.Info) {
if attUserData == nil || defUserData == nil {
return
}
// 释放领主
tmpList := make(map[uint64]uint32, 0)
totalAttAttack := int64(0)
defUserData.ForeachPrison(true, func(prison *proto.ST_Prison_PB) bool {
if ok, _, bounty := releaseCommanderInPrison(defUserData, prison, 1, attUserData); ok {
tmpList[prison.GetOwner()] = 0
//瓜分赏金
if totalAttAttack == 0 {
for _, v := range atkInfos {
totalAttAttack += v.GetTotalPower()
}
}
if 0 == totalAttAttack {
return true
}
for _, v := range atkInfos {
tmpUser := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil != tmpUser {
hijacker := &oss.PrisonHijacker{
Publisher: defUserData.GetUid(),
Recipient: uint64(prison.GetHeroId()),
}
if nil != bounty && bounty.GetW() > 0 {
reward := proto.Clone(bounty).(*proto.ST_Vector4Int_PB)
value := int64(bounty.GetW()) * v.GetTotalPower() / totalAttAttack
if value == 0 {
value = 1
}
reward.W = proto.SetInt32(int32(value))
hijacker.ItemNum = uint32(value)
hijacker.ItemID = uint32(reward.GetY())
statistAsset := tmpUser.GetStatisticsAsset()
statistAsset.UpdateGetRewardNumber(uint64(value))
tmpUser.AddVec4ResourceList([]*proto.ST_Vector4Int_PB{reward}, 1, oss.AddCashSrcBounty)
wlog.Info("分赏金 ", tmpUser.GetUid(), reward)
}
newOssPrison(tmpUser, nil, "", uint32(oss.PAT_Hijack), nil, hijacker)
}
}
}
return true
})
for k := range tmpList {
defUserData.DeletePrisonAsset(k)
}
}
/**
@brief 战斗后处理指挥官抓捕逻辑
*/
func captureCommander(attUserData, defUserData *cache.Info, result bool, targetType uint32) (map[uint64][]*proto.ST_Vector4Int_PB, map[uint64]uint32) {
var (
ret map[uint64][]*proto.ST_Vector4Int_PB
)
beCaptureheroMap := make(map[uint64]uint32, 0)
ret = make(map[uint64][]*proto.ST_Vector4Int_PB)
// 只有进攻主城胜利才抓领主
if !result || targetType != targetMainCity || defUserData == nil || attUserData == nil {
return ret, beCaptureheroMap
}
// 防守方主城等级限制
if defUserData.GetMainCityLevel() < CSV.GetGameConfigValueUint32("PrisonMainCityLevelLimit") {
fmt.Println("防守方主城等级不够", defUserData.GetMainCityLevel())
return ret, beCaptureheroMap
}
// 防守方指挥官状态
if defUserData.GetCommanderStatus() != uint32(proto.HeroStatus_HS_NORMAL) {
fmt.Println("已经被抓或者死亡")
return ret, beCaptureheroMap
}
// 进攻方没有监狱
bid, _ := attUserData.GetMaxBuildingInfoByBuildingConfigType(int64(proto.BuildingType_BT_PRISON))
if bid == 0 {
fmt.Println("进攻方没有监狱")
return ret, beCaptureheroMap
}
// 进攻方监狱已满
buildingfuntion := attUserData.GetBuildingFuctionByConfigType(int64(proto.BuildingType_BT_PRISON))
capability := common.StringToInt(buildingfuntion["capability"])
if attUserData.GetPrisonCount() >= capability {
fmt.Println("监狱已满")
return ret, beCaptureheroMap
}
randomNum := common.GetRandomNum(10000)
if getHeroPercent(targetMainCity) < uint32(randomNum) {
fmt.Println("运气不好,抓不到英雄")
return ret, beCaptureheroMap
}
commanderLevelCfg := CSV.GetCommanderLevelUpCfgByLevel(defUserData.GetLevel())
if commanderLevelCfg == nil {
fmt.Println("配置表错误,抓不到英雄")
return ret, beCaptureheroMap
}
heldtime := uint64(commanderLevelCfg.PrisonHoldTime)
var resourceSpeed = uint32(commanderLevelCfg.ResourceSpeed)
var resourceType uint32
if common.GetRandomNum(2) == 1 {
resourceType = 3
} else {
resourceType = 1
}
prison := &proto.ST_Prison_PB{
Owner: proto.SetUint64(defUserData.GetUid()),
StepStartTime: proto.SetUint64(wtime.GetNow()),
StepRemainTime: proto.SetUint64(heldtime),
ResourceType: proto.SetUint32(resourceType),
ResourceSpeed: proto.SetUint32(resourceSpeed),
}
captureInfo := &proto.ST_Vector4Int_PB{X: proto.SetInt32(int32(proto.VectorType_VT_HERO)),
Y: proto.SetInt32(int32(prison.GetHeroId())),
Z: proto.SetInt32(int32(prison.GetHeroQuality())),
W: proto.SetInt32(int32(prison.GetHeroLevel())),
}
ret[0] = append(ret[0], captureInfo)
attUserData.AddPrisonAsset(prison)
attStatisticeAsset := attUserData.GetStatisticsAsset()
attStatisticeAsset.UpdateArrestHeroNumber(1)
defUserData.SetCommanderStatus(uint32(proto.HeroStatus_HS_IMPRISONED), attUserData.GetUid(), prison.GetStepStartTime(), prison.GetStepRemainTime())
defStatisticeAsset := defUserData.GetStatisticsAsset()
defStatisticeAsset.UpdateCaptiveTimes()
title := common.CreateTips(90000171)
content := common.CreateTips(90000075, uint32(0), attUserData.GetUserName())
defUserData.AddLanguageIDMailAsset(uint32(proto.MailType_MT_SYSTEM), 0, -1, int32(proto.MailSourceType_MST_Hero),
title, content, "", "")
newOssPrison(attUserData, defUserData, "", uint32(oss.PAT_Catch), nil, nil)
newOssPrison(defUserData, attUserData, "", uint32(oss.PAT_BeCatch), nil, nil)
beCaptureheroMap[defUserData.GetUid()] = 1
PushMsg(proto.PushMsgType_PMT_HeroImprison, []interface{}{defUserData, attUserData})
return ret, beCaptureheroMap
}
/**
@brief 获取指挥官抓捕概率
*/
func getHeroPercent(targetType uint32) uint32 {
str := CSV.GetGameConfigValueString("hero_arrest")
percentList := common.ParseStringToUint32List(str)
if len(percentList) < 5 {
return 0
}
var percent uint32
switch targetType {
case targetMainCity:
percent = percentList[0]
case targetWarCity:
fallthrough
case targetLeagueCenter:
fallthrough
case targetRayolCity:
percent = percentList[1]
case targetMonster:
fallthrough
case targetMutiMonster:
percent = percentList[2]
case targetMine, targetMineGem:
percent = percentList[3]
case targetBestationed:
percent = percentList[4]
default:
percent = 0
}
return percent
}
func processMacWorldBattleResult(battleRlt uint32, targetType uint32, actionDataAsset *cache.GlobalActionEntry, battleReport *proto.ST_BattleReport_PB, battleInfo *proto.ST_BattleInfo_PB) {
if battleReport == nil || actionDataAsset == nil {
wlog.Error("processMacWorldBattleResult:", targetType)
return
}
if len(battleReport.GetAtkInfo()) <= 0 || len(battleReport.GetDefInfo()) <= 0 {
wlog.Error("processMacWorldBattleResult < 0 ")
return
}
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(actionDataAsset.Actiondata.GetEndTileID())
if worldAssetData == nil {
return
}
csvWorldConfig := worldAssetData.GetWorldEntryConfig()
if csvWorldConfig == nil {
return
}
actionDataEntry := actionDataAsset.Actiondata
unitChannel := oss.UnitChangeTypePVP
//var attInfo = getBigBrother(battleReport.AtkInfo) //攻击方首回合信息
var defInfo = getBigBrother(battleReport.DefInfo) //防守方首回合信息
if defInfo == nil {
return
}
isMultiuserDef := false //援助
if 1 < len(battleReport.GetDefInfo()) {
isMultiuserDef = true
}
// defUser 可能为nil
var defUser *cache.Info
if defInfo.CommanderReport != nil {
defUser = cache.GetCharinfo(defInfo.GetCommanderReport().GetUid())
}
//failedMax := CSV.GetGameConfigValueUint32("Pirate_Lose")
//if defUser == nil || GetMacMgrInstance().GetFailTms(defUser.GetUid()) >= int32(failedMax) {
// wlog.Info("processMacWorldBattleResult fail times:")
// return
//}
killNum := uint64(0)
defkillInfo := make(map[uint64]*proto.ST_UnitAsset_PB, 2)
for _, v := range battleReport.GetDefInfo() {
_, totalKillUnits, _, _, _, _ := processUnitListReport(v.GetUnitListReport(), v.GetHeroListReport())
for _, v := range totalKillUnits.GetUnits() {
killNum += v.GetUnitnum()
}
defkillInfo[v.GetActionID()] = totalKillUnits
}
origNum := uint64(0)
for _, v := range battleInfo.GetAtkSimpleStartInfo().GetStartUnitList() {
origNum += uint64(v.GetUnitCount())
}
isWin := true //win为false代表防守成功,win为false代表防守失败
coef := float64(CSV.GetGameConfigValueUint32("Pirate_Result")) / 100
if killNum >= uint64(math.Floor(float64(origNum)*coef)) {
isWin = false
}
defInfoLen := len(battleReport.GetDefInfo())
lastRoundDefInfo := battleReport.GetDefInfo()[defInfoLen-1] //防守方最后一回合信息
battleInfo.IsAtkWin = proto.SetBool(isWin)
_, defActionUnitMap, _ := getActionUnitMapByBattleReport(battleReport)
//delete(defActionUnitMap, 0)
//处理战斗后兵种资产
processGlobalActionAfterBattle(defActionUnitMap, worldAssetData, targetType, defUser, actionDataEntry.GetActiontype(), nil, isWin, false)
//处理玩家统计信息
startunits := battleInfo.GetAtkSimpleStartInfo().GetStartUnitList()
kvScore := GetMacMgrInstance().battleEnd(defUser, battleReport, defkillInfo, defInfo, startunits, isWin)
targetBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //被进攻方的战斗结果通知
targetSubBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //援助方的战斗结果通知
defTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())} //防守方主要对象收到的信息
defSubTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())} //防守方支援对象收到的信息
if isWin {
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 90000092)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 90000092)
targetBattleNotice.BattleRlt = proto.SetBool(false)
targetSubBattleNotice.BattleRlt = proto.SetBool(false)
} else {
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 90000091)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 90000091)
targetBattleNotice.BattleRlt = proto.SetBool(true)
targetSubBattleNotice.BattleRlt = proto.SetBool(true)
}
switch targetType {
case targetMainCity:
battleReport.DefFailInfo = &proto.ST_DefFailInfo_PB{}
if nil != lastRoundDefInfo.GetWallReport() {
Speed := uint64(CSV.GetGameConfigValueUint32("WALL_BURN_SPEED"))
ProcessMainCityDefenseLogic_MonsterAtk(worldAssetData.GetWorldDataOwner(), isWin, lastRoundDefInfo.WallReport.GetAfterHp(), Speed)
}
defTitleTips.LanguageID = proto.SetUint32(90000011)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 20000125)
defSubTitleTips.LanguageID = proto.SetUint32(90000011)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 71026)
//右下角战斗提示
targetBattleNotice.LanguageID = proto.SetUint32(75550) //$0$攻击了您
strAtkName := ""
ocfg := CSV.Mgr.CSV_WorldEntryConfig.GetEntryPtr(actionDataEntry.GetMacMonsterId())
if ocfg != nil {
strAtkName = CSV.GetLanguageStringByID(ocfg.Name, defUser.GetLanguage())
} else {
wlog.Error("CSV_WorldEntryConfig.GetEntryPtr return nil:", actionDataEntry.GetMacMonsterId())
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, strAtkName)
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, strAtkName)
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
}
ossBattleType := oss.OBT_Monster
ossFiledType := uint32(1)
if len(battleReport.AtkInfo) > 1 || len(battleReport.DefInfo) > 1 {
ossFiledType = 2
}
mailType := uint32(proto.MailType_MT_MONSTER_ATK_CITY)
//}
//发送防守方的邮件
defBattleReport := proto.Clone(battleReport).(*proto.ST_BattleReport_PB)
defBattleReport.IsWin = proto.SetBool(!isWin)
defBattleReport.WorldEntryConfigID = proto.SetInt64(actionDataAsset.Actiondata.GetMacMonsterId())
//defBattleReport.MacTid = proto.SetInt32(actionDataAsset.Actiondata.GetEndTileID())
strInfo := string(proto.Marshal(battleInfo))
SFUID := common.GetSFUID()
strSFUID := strconv.FormatInt(SFUID, 10)
for k, v := range battleReport.DefInfo {
tmpUserInfo := cache.GetCharinfo(v.CommanderReport.GetUid())
if tmpUserInfo == nil {
continue
}
score, _ := kvScore[tmpUserInfo.GetUid()]
defBattleReport.DefInfo[k].MacScore = proto.SetUint32(score)
ossBattleType = oss.OBT_PVP
//攻打玩家城市,对发送给主城玩家和支援玩家的邮件标题做区分
//带头大哥和小弟的战斗提示框不同
if v.GetIsBigBrother() {
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), defTitleTips, defTitleTips,
string(proto.Marshal(defBattleReport)), strSFUID)
if v.GetIsBigBrother() {
targetBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetBattleNotice)
}
} else {
targetSubBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetSubBattleNotice)
}
}
} else {
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), defSubTitleTips, defSubTitleTips,
string(proto.Marshal(defBattleReport)), strSFUID)
targetSubBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetSubBattleNotice)
}
}
newOssBattleRecord(tmpUserInfo, ossBattleType, !isWin, 0, ossFiledType, targetType,
actionDataAsset.Actiondata.GetEndTileID(), v.GetHeroListReport(), v.GetUnitListReport())
for _, u := range v.GetUnitListReport() {
newOssUnitChange(tmpUserInfo, uint32(unitChannel), u.GetUnitID(), int32(u.GetDeath()), int32(u.GetInjured()))
}
}
if defUser != nil {
defUser.CalcPower()
}
/*
if defUser != nil && defUser.GetLeagueID() != 0 {
//logEntry := createLeagueMacBattleLog(defUser, isWin, false)
//if cache.InstanceGlobalAssetLeagueBattleLog.AddLeagueBattleLog(defUser.GetLeagueID(), logEntry) {
// NotifyLeagueBattleLog(defUser.GetLeagueID())
//}
//logEntry.Attacker.MacMonsterId = proto.SetInt64(actionDataAsset.Actiondata.GetMacMonsterId())
}*/
}
func getMacAtkInfo(battleKey *stBattleKey, monsterid int64) (bool, *stBattleActionBaseData, map[uint64]*stUserUnitInfo) {
var defOrgiUnitAssetMap map[uint64]*stUserUnitInfo //记录多人防御玩家的原始兵力资产
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(battleKey.endTileID)
if worldAssetData == nil {
return false, nil, nil
}
atkBaseData := &stBattleActionBaseData{
actionBaseType: actionBase_Atk,
}
//获取怪物的城墙,英雄,战斗单位信息
ok, wall, heroList, unitAsset, formationId, globalAttribute, _, _ := getMonsterBattleUnitInfo(monsterid)
if false == ok {
return false, nil, nil
}
//atkBaseData.monsterGroupID = monsterGroupID
atkBaseData.heroList = heroList
atkBaseData.wall = wall
atkBaseData.globalAttribute = globalAttribute
ok, atkBaseData.formation, defOrgiUnitAssetMap = prepareUnits(battleKey.actionID, nil, unitAsset, formationId)
return true, atkBaseData, defOrgiUnitAssetMap
}
func createLeagueMacBattleLog(defUser *cache.Info, isWid, isMulti bool) *proto.ST_LeagueBattle_Log_Entry {
atkInfo := &proto.ST_LeagueBattle_User{
Lid: proto.SetUint64(uint64(0)),
UserName: proto.SetString(""),
Avatar: proto.SetString(""),
AvatarBoxID: proto.SetUint32(0),
AvatarID: proto.SetString(""),
LeagueShortName: proto.SetString(""),
Uid: proto.SetUint64(0),
}
defInfo := &proto.ST_LeagueBattle_User{
Lid: proto.SetUint64(defUser.GetLeagueID()),
UserName: proto.SetString(defUser.GetUserName()),
Avatar: proto.SetString(defUser.GetAvatar()),
AvatarBoxID: proto.SetUint32(defUser.GetAvatarBoxId()),
AvatarID: proto.SetString(defUser.GetLordIcon()),
LeagueShortName: proto.SetString(defUser.GetLeagueShortName()),
Uid: proto.SetUint64(defUser.GetUid()),
}
logEntry := &proto.ST_LeagueBattle_Log_Entry{
Attacker: atkInfo,
Defer: defInfo,
IsMulti: proto.SetBool(isMulti),
IsWin: proto.SetBool(isWid),
Times: proto.SetInt32(1),
Timestamp: proto.SetUint64(wtime.GetNow()),
}
return logEntry
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/liuxuezhan/mylib.git
git@gitee.com:liuxuezhan/mylib.git
liuxuezhan
mylib
mylib
v1.1.0

搜索帮助

344bd9b3 5694891 D2dac590 5694891