battle.c 277 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/cbasetypes.h"
  4. #include "../common/timer.h"
  5. #include "../common/nullpo.h"
  6. #include "../common/malloc.h"
  7. #include "../common/showmsg.h"
  8. #include "../common/ers.h"
  9. #include "../common/random.h"
  10. #include "../common/socket.h"
  11. #include "../common/strlib.h"
  12. #include "../common/utils.h"
  13. #include "map.h"
  14. #include "path.h"
  15. #include "pc.h"
  16. #include "status.h"
  17. #include "skill.h"
  18. #include "homunculus.h"
  19. #include "mercenary.h"
  20. #include "elemental.h"
  21. #include "mob.h"
  22. #include "itemdb.h"
  23. #include "clif.h"
  24. #include "pet.h"
  25. #include "guild.h"
  26. #include "party.h"
  27. #include "battle.h"
  28. #include "battleground.h"
  29. #include "chrif.h"
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <math.h>
  34. int attr_fix_table[4][ELE_MAX][ELE_MAX];
  35. struct Battle_Config battle_config;
  36. static struct eri *delay_damage_ers; //For battle delay damage structures.
  37. #define DAMAGE_RATE(a){damage = (int64)damage * (a)/100;}
  38. #define DAMAGE_SUBRATE(a){damage -= (int64)damage * (a)/100;}
  39. #define DAMAGE_ADDRATE(a){damage += (int64)damage * (a)/100;}
  40. int battle_getcurrentskill(struct block_list *bl) { //Returns the current/last skill in use by this bl.
  41. struct unit_data *ud;
  42. if( bl->type == BL_SKILL ) {
  43. struct skill_unit * su = (struct skill_unit*)bl;
  44. return su->group?su->group->skill_id:0;
  45. }
  46. ud = unit_bl2ud(bl);
  47. return ud?ud->skill_id:0;
  48. }
  49. /*==========================================
  50. * Get random targetting enemy
  51. *------------------------------------------*/
  52. static int battle_gettargeted_sub(struct block_list *bl, va_list ap) {
  53. struct block_list **bl_list;
  54. struct unit_data *ud;
  55. int target_id;
  56. int *c;
  57. bl_list = va_arg(ap, struct block_list **);
  58. c = va_arg(ap, int *);
  59. target_id = va_arg(ap, int);
  60. if (bl->id == target_id)
  61. return 0;
  62. if (*c >= 24)
  63. return 0;
  64. if ( !(ud = unit_bl2ud(bl)) )
  65. return 0;
  66. if (ud->target == target_id || ud->skilltarget == target_id) {
  67. bl_list[(*c)++] = bl;
  68. return 1;
  69. }
  70. return 0;
  71. }
  72. struct block_list* battle_gettargeted(struct block_list *target) {
  73. struct block_list *bl_list[24];
  74. int c = 0;
  75. nullpo_retr(NULL, target);
  76. memset(bl_list, 0, sizeof(bl_list));
  77. map_foreachinrange(battle_gettargeted_sub, target, AREA_SIZE, BL_CHAR, bl_list, &c, target->id);
  78. if ( c == 0 )
  79. return NULL;
  80. if( c > 24 )
  81. c = 24;
  82. return bl_list[rnd()%c];
  83. }
  84. //Returns the id of the current targetted character of the passed bl. [Skotlex]
  85. int battle_gettarget(struct block_list* bl) {
  86. switch (bl->type) {
  87. case BL_PC: return ((struct map_session_data*)bl)->ud.target;
  88. case BL_MOB: return ((struct mob_data*)bl)->target_id;
  89. case BL_PET: return ((struct pet_data*)bl)->target_id;
  90. case BL_HOM: return ((struct homun_data*)bl)->ud.target;
  91. case BL_MER: return ((struct mercenary_data*)bl)->ud.target;
  92. case BL_ELEM: return ((struct elemental_data*)bl)->ud.target;
  93. }
  94. return 0;
  95. }
  96. static int battle_getenemy_sub(struct block_list *bl, va_list ap) {
  97. struct block_list **bl_list;
  98. struct block_list *target;
  99. int *c;
  100. bl_list = va_arg(ap, struct block_list **);
  101. c = va_arg(ap, int *);
  102. target = va_arg(ap, struct block_list *);
  103. if (bl->id == target->id)
  104. return 0;
  105. if (*c >= 24)
  106. return 0;
  107. if (status_isdead(bl))
  108. return 0;
  109. if (battle_check_target(target, bl, BCT_ENEMY) > 0) {
  110. bl_list[(*c)++] = bl;
  111. return 1;
  112. }
  113. return 0;
  114. }
  115. // Picks a random enemy of the given type (BL_PC, BL_CHAR, etc) within the range given. [Skotlex]
  116. struct block_list* battle_getenemy(struct block_list *target, int type, int range) {
  117. struct block_list *bl_list[24];
  118. int c = 0;
  119. memset(bl_list, 0, sizeof(bl_list));
  120. map_foreachinrange(battle_getenemy_sub, target, range, type, bl_list, &c, target);
  121. if ( c == 0 )
  122. return NULL;
  123. if( c > 24 )
  124. c = 24;
  125. return bl_list[rnd()%c];
  126. }
  127. static int battle_getenemyarea_sub(struct block_list *bl, va_list ap) {
  128. struct block_list **bl_list, *src;
  129. int *c, ignore_id;
  130. bl_list = va_arg(ap, struct block_list **);
  131. c = va_arg(ap, int *);
  132. src = va_arg(ap, struct block_list *);
  133. ignore_id = va_arg(ap, int);
  134. if( bl->id == src->id || bl->id == ignore_id )
  135. return 0; // Ignores Caster and a possible pre-target
  136. if( *c >= 23 )
  137. return 0;
  138. if( status_isdead(bl) )
  139. return 0;
  140. if( battle_check_target(src, bl, BCT_ENEMY) > 0 ) {// Is Enemy!...
  141. bl_list[(*c)++] = bl;
  142. return 1;
  143. }
  144. return 0;
  145. }
  146. // Pick a random enemy
  147. struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int range, int type, int ignore_id) {
  148. struct block_list *bl_list[24];
  149. int c = 0;
  150. memset(bl_list, 0, sizeof(bl_list));
  151. map_foreachinarea(battle_getenemyarea_sub, src->m, x - range, y - range, x + range, y + range, type, bl_list, &c, src, ignore_id);
  152. if( c == 0 )
  153. return NULL;
  154. if( c >= 24 )
  155. c = 23;
  156. return bl_list[rnd()%c];
  157. }
  158. // Dammage delayed info
  159. struct delay_damage {
  160. int src_id;
  161. int target_id;
  162. int64 damage;
  163. int delay;
  164. unsigned short distance;
  165. uint16 skill_lv;
  166. uint16 skill_id;
  167. enum damage_lv dmg_lv;
  168. unsigned short attack_type;
  169. bool additional_effects;
  170. };
  171. int battle_delay_damage_sub(int tid, unsigned int tick, int id, intptr_t data) {
  172. struct delay_damage *dat = (struct delay_damage *)data;
  173. if ( dat ) {
  174. struct block_list* src;
  175. struct block_list* target = map_id2bl(dat->target_id);
  176. if( !target || status_isdead(target) ) {/* nothing we can do */
  177. ers_free(delay_damage_ers, dat);
  178. return 0;
  179. }
  180. src = map_id2bl(dat->src_id);
  181. if( src && target->m == src->m &&
  182. (target->type != BL_PC || ((TBL_PC*)target)->invincible_timer == INVALID_TIMER) &&
  183. check_distance_bl(src, target, dat->distance) ) //Check to see if you haven't teleported. [Skotlex]
  184. {
  185. map_freeblock_lock();
  186. status_fix_damage(src, target, dat->damage, dat->delay);
  187. if( dat->attack_type && !status_isdead(target) && dat->additional_effects )
  188. skill_additional_effect(src,target,dat->skill_id,dat->skill_lv,dat->attack_type,dat->dmg_lv,tick);
  189. if( dat->dmg_lv > ATK_BLOCK && dat->attack_type )
  190. skill_counter_additional_effect(src,target,dat->skill_id,dat->skill_lv,dat->attack_type,tick);
  191. map_freeblock_unlock();
  192. } else if( !src && dat->skill_id == CR_REFLECTSHIELD ) {
  193. /**
  194. * it was monster reflected damage, and the monster died, we pass the damage to the character as expected
  195. **/
  196. map_freeblock_lock();
  197. status_fix_damage(target, target, dat->damage, dat->delay);
  198. map_freeblock_unlock();
  199. }
  200. }
  201. ers_free(delay_damage_ers, dat);
  202. return 0;
  203. }
  204. int battle_delay_damage (unsigned int tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, uint16 skill_id, uint16 skill_lv, int64 damage, enum damage_lv dmg_lv, int ddelay, bool additional_effects)
  205. {
  206. struct delay_damage *dat;
  207. struct status_change *sc;
  208. nullpo_ret(src);
  209. nullpo_ret(target);
  210. sc = status_get_sc(target);
  211. if( sc && sc->data[SC_DEVOTION] && damage > 0 && skill_id != PA_PRESSURE && skill_id != CR_REFLECTSHIELD )
  212. damage = 0;
  213. if ( !battle_config.delay_battle_damage || amotion <= 1 ) {
  214. map_freeblock_lock();
  215. status_fix_damage(src, target, damage, ddelay); // We have to seperate here between reflect damage and others [icescope]
  216. if( attack_type && !status_isdead(target) && additional_effects )
  217. skill_additional_effect(src, target, skill_id, skill_lv, attack_type, dmg_lv, gettick());
  218. if( dmg_lv > ATK_BLOCK && attack_type )
  219. skill_counter_additional_effect(src, target, skill_id, skill_lv, attack_type, gettick());
  220. map_freeblock_unlock();
  221. return 0;
  222. }
  223. dat = ers_alloc(delay_damage_ers, struct delay_damage);
  224. dat->src_id = src->id;
  225. dat->target_id = target->id;
  226. dat->skill_id = skill_id;
  227. dat->skill_lv = skill_lv;
  228. dat->attack_type = attack_type;
  229. dat->damage = damage;
  230. dat->dmg_lv = dmg_lv;
  231. dat->delay = ddelay;
  232. dat->distance = distance_bl(src, target)+10; //Attack should connect regardless unless you teleported.
  233. dat->additional_effects = additional_effects;
  234. if (src->type != BL_PC && amotion > 1000)
  235. amotion = 1000; //Aegis places a damage-delay cap of 1 sec to non player attacks. [Skotlex]
  236. add_timer(tick+amotion, battle_delay_damage_sub, 0, (intptr_t)dat);
  237. return 0;
  238. }
  239. int battle_attr_ratio(int atk_elem,int def_type, int def_lv)
  240. {
  241. if (atk_elem < 0 || atk_elem >= ELE_MAX)
  242. return 100;
  243. if (def_type < 0 || def_type > ELE_MAX || def_lv < 1 || def_lv > 4)
  244. return 100;
  245. return attr_fix_table[def_lv-1][atk_elem][def_type];
  246. }
  247. /*==========================================
  248. * Does attribute fix modifiers.
  249. * Added passing of the chars so that the status changes can affect it. [Skotlex]
  250. * Note: Passing src/target == NULL is perfectly valid, it skips SC_ checks.
  251. *------------------------------------------*/
  252. int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 damage,int atk_elem,int def_type, int def_lv)
  253. {
  254. struct status_change *sc=NULL, *tsc=NULL;
  255. int ratio;
  256. if (src) sc = status_get_sc(src);
  257. if (target) tsc = status_get_sc(target);
  258. if (atk_elem < 0 || atk_elem >= ELE_MAX)
  259. atk_elem = rnd()%ELE_MAX;
  260. if (def_type < 0 || def_type > ELE_MAX ||
  261. def_lv < 1 || def_lv > 4) {
  262. ShowError("battle_attr_fix: unknown attr type: atk=%d def_type=%d def_lv=%d\n",atk_elem,def_type,def_lv);
  263. return damage;
  264. }
  265. ratio = attr_fix_table[def_lv-1][atk_elem][def_type];
  266. if (sc && sc->count) {
  267. if(sc->data[SC_VOLCANO] && atk_elem == ELE_FIRE)
  268. ratio += enchant_eff[sc->data[SC_VOLCANO]->val1-1];
  269. if(sc->data[SC_VIOLENTGALE] && atk_elem == ELE_WIND)
  270. ratio += enchant_eff[sc->data[SC_VIOLENTGALE]->val1-1];
  271. if(sc->data[SC_DELUGE] && atk_elem == ELE_WATER)
  272. ratio += enchant_eff[sc->data[SC_DELUGE]->val1-1];
  273. }
  274. if( target && target->type == BL_SKILL ) {
  275. if( atk_elem == ELE_FIRE && battle_getcurrentskill(target) == GN_WALLOFTHORN ) {
  276. struct skill_unit *su = (struct skill_unit*)target;
  277. struct skill_unit_group *sg;
  278. struct block_list *src;
  279. if( !su || !su->alive || (sg = su->group) == NULL || !sg || sg->val3 == -1 ||
  280. (src = map_id2bl(sg->src_id)) == NULL || status_isdead(src) )
  281. return 0;
  282. if( sg->unit_id != UNT_FIREWALL ) {
  283. int x,y;
  284. x = sg->val3 >> 16;
  285. y = sg->val3 & 0xffff;
  286. skill_unitsetting(src,su->group->skill_id,su->group->skill_lv,x,y,1);
  287. sg->val3 = -1;
  288. sg->limit = DIFF_TICK(gettick(),sg->tick)+300;
  289. }
  290. }
  291. }
  292. if( tsc && tsc->count ) { //since an atk can only have one type let's optimise this a bit
  293. switch(atk_elem){
  294. case ELE_FIRE:
  295. if( tsc->data[SC_SPIDERWEB]) {
  296. tsc->data[SC_SPIDERWEB]->val1 = 0; // free to move now
  297. if( tsc->data[SC_SPIDERWEB]->val2-- > 0 )
  298. damage <<= 1; // double damage
  299. if( tsc->data[SC_SPIDERWEB]->val2 == 0 )
  300. status_change_end(target, SC_SPIDERWEB, INVALID_TIMER);
  301. }
  302. if( tsc->data[SC_THORNSTRAP])
  303. status_change_end(target, SC_THORNSTRAP, INVALID_TIMER);
  304. if( tsc->data[SC_FIRE_CLOAK_OPTION])
  305. DAMAGE_SUBRATE(tsc->data[SC_FIRE_CLOAK_OPTION]->val2)
  306. if( tsc->data[SC_CRYSTALIZE] && target->type != BL_MOB)
  307. status_change_end(target, SC_CRYSTALIZE, INVALID_TIMER);
  308. if( tsc->data[SC_EARTH_INSIGNIA]) damage += damage/2;
  309. if( tsc->data[SC_ASH]) damage += damage/2; //150%
  310. break;
  311. case ELE_HOLY:
  312. if( tsc->data[SC_ORATIO]) ratio += tsc->data[SC_ORATIO]->val1 * 2;
  313. break;
  314. case ELE_POISON:
  315. if( tsc->data[SC_VENOMIMPRESS]) ratio += tsc->data[SC_VENOMIMPRESS]->val2;
  316. break;
  317. case ELE_WIND:
  318. if( tsc->data[SC_CRYSTALIZE] && target->type != BL_MOB) damage += damage/2;
  319. if( tsc->data[SC_WATER_INSIGNIA]) damage += damage/2;
  320. break;
  321. case ELE_WATER:
  322. if( tsc->data[SC_FIRE_INSIGNIA]) damage += damage/2;
  323. break;
  324. case ELE_EARTH:
  325. if( tsc->data[SC_WIND_INSIGNIA]) damage += damage/2;
  326. break;
  327. }
  328. } //end tsc check
  329. if( src && src->type == BL_PC ){
  330. struct map_session_data *sd = BL_CAST(BL_PC, src);
  331. int s;
  332. ARR_FIND(1, 6, s, sd->talisman[s] > 0);
  333. if( s < 5 && atk_elem == s )
  334. ratio += sd->talisman[s] * 2; // +2% custom value
  335. }
  336. if( target && target->type == BL_PC ) {
  337. struct map_session_data *tsd = BL_CAST(BL_PC, target);
  338. int t;
  339. ARR_FIND(1, 6, t, tsd->talisman[t] > 0);
  340. if( t < 5 && atk_elem == t )
  341. DAMAGE_SUBRATE(tsd->talisman[t] * 3) // -3% custom value
  342. }
  343. return (int64)damage*ratio/100;
  344. }
  345. /*==========================================
  346. * Calculates card bonuses damage adjustments.
  347. *------------------------------------------*/
  348. int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int64 damage, int left, int flag){
  349. struct map_session_data *sd, *tsd;
  350. short cardfix = 1000, t_class, s_class, s_race2, t_race2;
  351. struct status_data *sstatus, *tstatus;
  352. int64 original_damage;
  353. int i, skill;
  354. if( !damage )
  355. return 0;
  356. original_damage = damage;
  357. sd = BL_CAST(BL_PC, src);
  358. tsd = BL_CAST(BL_PC, target);
  359. t_class = status_get_class(target);
  360. s_class = status_get_class(src);
  361. sstatus = status_get_status_data(src);
  362. tstatus = status_get_status_data(target);
  363. s_race2 = status_get_race2(src);
  364. #define bccDAMAGE_RATE(a){ damage = (int64)damage * (a)/1000;}
  365. switch(attack_type){
  366. case BF_MAGIC:
  367. if ( sd && !(nk&NK_NO_CARDFIX_ATK) ) {
  368. cardfix=cardfix*(100+sd->magic_addrace[tstatus->race])/100;
  369. if (!(nk&NK_NO_ELEFIX))
  370. cardfix=cardfix*(100+sd->magic_addele[tstatus->def_ele])/100;
  371. cardfix=cardfix*(100+sd->magic_addsize[tstatus->size])/100;
  372. cardfix=cardfix*(100+sd->magic_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100;
  373. cardfix=cardfix*(100+sd->magic_atk_ele[s_ele])/100;
  374. for(i=0; i< ARRAYLENGTH(sd->add_mdmg) && sd->add_mdmg[i].rate;i++) {
  375. if(sd->add_mdmg[i].class_ == t_class) {
  376. cardfix=cardfix*(100+sd->add_mdmg[i].rate)/100;
  377. break;
  378. }
  379. }
  380. if (cardfix != 1000)
  381. bccDAMAGE_RATE(cardfix)
  382. }
  383. if( tsd && !(nk&NK_NO_CARDFIX_DEF) )
  384. { // Target cards.
  385. if (!(nk&NK_NO_ELEFIX))
  386. {
  387. int ele_fix = tsd->subele[s_ele];
  388. for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++)
  389. {
  390. if(tsd->subele2[i].ele != s_ele) continue;
  391. if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK &&
  392. tsd->subele2[i].flag&flag&BF_RANGEMASK &&
  393. tsd->subele2[i].flag&flag&BF_SKILLMASK))
  394. continue;
  395. ele_fix += tsd->subele2[i].rate;
  396. }
  397. cardfix=cardfix*(100-ele_fix)/100;
  398. }
  399. cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100;
  400. cardfix=cardfix*(100-tsd->subrace2[s_race2])/100;
  401. cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100;
  402. cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100;
  403. if( sstatus->race != RC_DEMIHUMAN )
  404. cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100;
  405. for(i=0; i < ARRAYLENGTH(tsd->add_mdef) && tsd->add_mdef[i].rate;i++) {
  406. if(tsd->add_mdef[i].class_ == s_class) {
  407. cardfix=cardfix*(100-tsd->add_mdef[i].rate)/100;
  408. break;
  409. }
  410. }
  411. //It was discovered that ranged defense also counts vs magic! [Skotlex]
  412. if ( flag&BF_SHORT )
  413. cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100;
  414. else
  415. cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100;
  416. cardfix = cardfix * ( 100 - tsd->bonus.magic_def_rate ) / 100;
  417. if( tsd->sc.data[SC_MDEF_RATE] )
  418. cardfix = cardfix * ( 100 - tsd->sc.data[SC_MDEF_RATE]->val1 ) / 100;
  419. if (cardfix != 1000)
  420. bccDAMAGE_RATE(cardfix)
  421. }
  422. break;
  423. case BF_WEAPON:
  424. t_race2 = status_get_race2(target);
  425. if( sd && !(nk&NK_NO_CARDFIX_ATK) && (left&2) ) //Attacker cards should be checked
  426. {
  427. short cardfix_ = 1000;
  428. if(sd->state.arrow_atk)
  429. {
  430. cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->arrow_addrace[tstatus->race])/100;
  431. if (!(nk&NK_NO_ELEFIX))
  432. {
  433. int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->arrow_addele[tstatus->def_ele];
  434. for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) {
  435. if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue;
  436. if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK &&
  437. sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK &&
  438. sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK))
  439. continue;
  440. ele_fix += sd->right_weapon.addele2[i].rate;
  441. }
  442. cardfix=cardfix*(100+ele_fix)/100;
  443. }
  444. cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->arrow_addsize[tstatus->size])/100;
  445. cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100;
  446. cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->arrow_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100;
  447. if( tstatus->race != RC_DEMIHUMAN )
  448. cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->arrow_addrace[RC_NONDEMIHUMAN])/100;
  449. }
  450. else
  451. { // Melee attack
  452. if( !battle_config.left_cardfix_to_right )
  453. {
  454. cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race])/100;
  455. if (!(nk&NK_NO_ELEFIX)) {
  456. int ele_fix = sd->right_weapon.addele[tstatus->def_ele];
  457. for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) {
  458. if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue;
  459. if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK &&
  460. sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK &&
  461. sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK))
  462. continue;
  463. ele_fix += sd->right_weapon.addele2[i].rate;
  464. }
  465. cardfix=cardfix*(100+ele_fix)/100;
  466. }
  467. cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size])/100;
  468. cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100;
  469. cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100;
  470. if( tstatus->race != RC_DEMIHUMAN )
  471. cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN])/100;
  472. if( left&1 )
  473. {
  474. cardfix_=cardfix_*(100+sd->left_weapon.addrace[tstatus->race])/100;
  475. if (!(nk&NK_NO_ELEFIX)) {
  476. int ele_fix_lh = sd->left_weapon.addele[tstatus->def_ele];
  477. for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) {
  478. if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue;
  479. if(!(sd->left_weapon.addele2[i].flag&flag&BF_WEAPONMASK &&
  480. sd->left_weapon.addele2[i].flag&flag&BF_RANGEMASK &&
  481. sd->left_weapon.addele2[i].flag&flag&BF_SKILLMASK))
  482. continue;
  483. ele_fix_lh += sd->left_weapon.addele2[i].rate;
  484. }
  485. cardfix=cardfix*(100+ele_fix_lh)/100;
  486. }
  487. cardfix_=cardfix_*(100+sd->left_weapon.addsize[tstatus->size])/100;
  488. cardfix_=cardfix_*(100+sd->left_weapon.addrace2[t_race2])/100;
  489. cardfix_=cardfix_*(100+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100;
  490. if( tstatus->race != RC_DEMIHUMAN )
  491. cardfix_=cardfix_*(100+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100;
  492. }
  493. }
  494. else
  495. {
  496. int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->left_weapon.addele[tstatus->def_ele];
  497. for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) {
  498. if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue;
  499. if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK &&
  500. sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK &&
  501. sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK))
  502. continue;
  503. ele_fix += sd->right_weapon.addele2[i].rate;
  504. }
  505. for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) {
  506. if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue;
  507. if(!(sd->left_weapon.addele2[i].flag&flag&BF_WEAPONMASK &&
  508. sd->left_weapon.addele2[i].flag&flag&BF_RANGEMASK &&
  509. sd->left_weapon.addele2[i].flag&flag&BF_SKILLMASK))
  510. continue;
  511. ele_fix += sd->left_weapon.addele2[i].rate;
  512. }
  513. cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->left_weapon.addrace[tstatus->race])/100;
  514. cardfix=cardfix*(100+ele_fix)/100;
  515. cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->left_weapon.addsize[tstatus->size])/100;
  516. cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2]+sd->left_weapon.addrace2[t_race2])/100;
  517. cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100;
  518. if( tstatus->race != RC_DEMIHUMAN )
  519. cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100;
  520. }
  521. if (sd->status.weapon == W_KATAR && (skill=pc_checkskill(sd,ASC_KATAR)) > 0) { // Adv. Katar Mastery functions similar to a +%ATK card on official [helvetica]
  522. cardfix = cardfix * (100 + (10 + 2 * skill)) / 100;
  523. }
  524. }
  525. for( i = 0; i < ARRAYLENGTH(sd->right_weapon.add_dmg) && sd->right_weapon.add_dmg[i].rate; i++ )
  526. {
  527. if( sd->right_weapon.add_dmg[i].class_ == t_class )
  528. {
  529. cardfix=cardfix*(100+sd->right_weapon.add_dmg[i].rate)/100;
  530. break;
  531. }
  532. }
  533. if( left&1 )
  534. {
  535. for( i = 0; i < ARRAYLENGTH(sd->left_weapon.add_dmg) && sd->left_weapon.add_dmg[i].rate; i++ )
  536. {
  537. if( sd->left_weapon.add_dmg[i].class_ == t_class )
  538. {
  539. cardfix_=cardfix_*(100+sd->left_weapon.add_dmg[i].rate)/100;
  540. break;
  541. }
  542. }
  543. }
  544. if( flag&BF_LONG )
  545. cardfix = cardfix * ( 100 + sd->bonus.long_attack_atk_rate ) / 100;
  546. if( (left&1) && cardfix_ != 1000 )
  547. bccDAMAGE_RATE(cardfix_)
  548. else if( cardfix != 1000 )
  549. bccDAMAGE_RATE(cardfix)
  550. } else if( tsd && !(nk&NK_NO_CARDFIX_DEF) && !(left&2) ){ //Target cards should be checked
  551. if( !(nk&NK_NO_ELEFIX) )
  552. {
  553. int ele_fix = tsd->subele[s_ele];
  554. for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++)
  555. {
  556. if(tsd->subele2[i].ele != s_ele) continue;
  557. if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK &&
  558. tsd->subele2[i].flag&flag&BF_RANGEMASK &&
  559. tsd->subele2[i].flag&flag&BF_SKILLMASK))
  560. continue;
  561. ele_fix += tsd->subele2[i].rate;
  562. }
  563. cardfix=cardfix*(100-ele_fix)/100;
  564. if( left&1 && s_ele_ != s_ele )
  565. {
  566. int ele_fix_lh = tsd->subele[s_ele_];
  567. for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++)
  568. {
  569. if(tsd->subele2[i].ele != s_ele_) continue;
  570. if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK &&
  571. tsd->subele2[i].flag&flag&BF_RANGEMASK &&
  572. tsd->subele2[i].flag&flag&BF_SKILLMASK))
  573. continue;
  574. ele_fix_lh += tsd->subele2[i].rate;
  575. }
  576. cardfix=cardfix*(100-ele_fix_lh)/100;
  577. }
  578. }
  579. cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100;
  580. cardfix=cardfix*(100-tsd->subrace2[s_race2])/100;
  581. cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100;
  582. cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100;
  583. if( sstatus->race != RC_DEMIHUMAN )
  584. cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100;
  585. for( i = 0; i < ARRAYLENGTH(tsd->add_def) && tsd->add_def[i].rate;i++ ) {
  586. if( tsd->add_def[i].class_ == s_class ) {
  587. cardfix=cardfix*(100-tsd->add_def[i].rate)/100;
  588. break;
  589. }
  590. }
  591. if( flag&BF_SHORT )
  592. cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100;
  593. else // BF_LONG (there's no other choice)
  594. cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100;
  595. if( tsd->sc.data[SC_DEF_RATE] )
  596. cardfix = cardfix * ( 100 - tsd->sc.data[SC_DEF_RATE]->val1 ) / 100;
  597. if( cardfix != 1000 )
  598. bccDAMAGE_RATE(cardfix)
  599. }
  600. break;
  601. case BF_MISC:
  602. if( tsd && !(nk&NK_NO_CARDFIX_DEF) ){
  603. // misc damage reduction from equipment
  604. if (!(nk&NK_NO_ELEFIX))
  605. {
  606. int ele_fix = tsd->subele[s_ele];
  607. for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++)
  608. {
  609. if(tsd->subele2[i].ele != s_ele) continue;
  610. if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK &&
  611. tsd->subele2[i].flag&flag&BF_RANGEMASK &&
  612. tsd->subele2[i].flag&flag&BF_SKILLMASK))
  613. continue;
  614. ele_fix += tsd->subele2[i].rate;
  615. }
  616. cardfix=cardfix*(100-ele_fix)/100;
  617. }
  618. cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100;
  619. cardfix=cardfix*(100-tsd->subrace2[s_race2])/100;
  620. cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100;
  621. cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100;
  622. if( sstatus->race != RC_DEMIHUMAN )
  623. cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100;
  624. cardfix = cardfix * ( 100 - tsd->bonus.misc_def_rate ) / 100;
  625. if( flag&BF_SHORT )
  626. cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100;
  627. else // BF_LONG (there's no other choice)
  628. cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100;
  629. if (cardfix != 10000)
  630. bccDAMAGE_RATE(cardfix)
  631. }
  632. break;
  633. }
  634. return (int)(damage - original_damage);
  635. }
  636. /*==========================================
  637. * Check dammage trough status.
  638. * ATK may be MISS, BLOCKED FAIL, reduc, increase, end status...
  639. * After this we apply bg/gvg reduction
  640. *------------------------------------------*/
  641. int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damage *d,int64 damage,uint16 skill_id,uint16 skill_lv)
  642. {
  643. struct map_session_data *sd = NULL;
  644. struct status_change *sc;
  645. struct status_change_entry *sce;
  646. int div_ = d->div_, flag = d->flag;
  647. nullpo_ret(bl);
  648. if( !damage )
  649. return 0;
  650. if( battle_config.ksprotection && mob_ksprotected(src, bl) )
  651. return 0;
  652. if( map_getcell(bl->m, bl->x, bl->y, CELL_CHKMAELSTROM) && skill_get_type(skill_id) != BF_MISC
  653. && skill_get_casttype(skill_id) == CAST_GROUND )
  654. return 0;
  655. if (bl->type == BL_PC) {
  656. sd=(struct map_session_data *)bl;
  657. //Special no damage states
  658. if(flag&BF_WEAPON && sd->special_state.no_weapon_damage)
  659. DAMAGE_SUBRATE(sd->special_state.no_weapon_damage)
  660. if(flag&BF_MAGIC && sd->special_state.no_magic_damage)
  661. DAMAGE_SUBRATE(sd->special_state.no_magic_damage)
  662. if(flag&BF_MISC && sd->special_state.no_misc_damage)
  663. DAMAGE_SUBRATE(sd->special_state.no_misc_damage)
  664. if(!damage) return 0;
  665. }
  666. sc = status_get_sc(bl); //check target status
  667. if( sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
  668. return 1;
  669. if (skill_id == PA_PRESSURE)
  670. return damage; //This skill bypass everything else.
  671. if( sc && sc->count ) {
  672. /**
  673. * SC_* that reduce damage to 0.
  674. **/
  675. if( sc->data[SC_BASILICA] && !(status_get_mode(src)&MD_BOSS) ) {
  676. d->dmg_lv = ATK_BLOCK;
  677. return 0;
  678. }
  679. if( sc->data[SC_WHITEIMPRISON] && skill_id != HW_GRAVITATION ) { // Gravitation and Pressure do damage without removing the effect
  680. if( skill_id == MG_NAPALMBEAT ||
  681. skill_id == MG_SOULSTRIKE ||
  682. skill_id == WL_SOULEXPANSION ||
  683. (skill_id && skill_get_ele(skill_id, skill_lv) == ELE_GHOST) ||
  684. (!skill_id && (status_get_status_data(src))->rhw.ele == ELE_GHOST) )
  685. {
  686. if( skill_id == WL_SOULEXPANSION )
  687. damage <<= 1; // If used against a player in White Imprison, the skill deals double damage.
  688. status_change_end(bl,SC_WHITEIMPRISON,INVALID_TIMER); // Those skills do damage and removes effect
  689. } else {
  690. d->dmg_lv = ATK_BLOCK;
  691. return 0;
  692. }
  693. }
  694. if(sc->data[SC_ZEPHYR] && (flag&(BF_LONG|BF_SHORT)) == (BF_SHORT|BF_LONG)) {
  695. d->dmg_lv = ATK_BLOCK;
  696. return 0;
  697. }
  698. if( sc->data[SC_SAFETYWALL] && (flag&(BF_SHORT|BF_MAGIC))==BF_SHORT ) {
  699. struct skill_unit_group* group = skill_id2group(sc->data[SC_SAFETYWALL]->val3);
  700. //uint16 skill_id = sc->data[SC_SAFETYWALL]->val2; (safetywall or steinwand)
  701. if (group) {
  702. //in RE, SW possesses a lifetime equal to group val2, (3x caster hp, or homon formula)
  703. #ifdef RENEWAL
  704. d->dmg_lv = ATK_BLOCK;
  705. if ( ( group->val2 - damage) > 0 ) {
  706. group->val2 -= (int)cap_value(damage,INT_MIN,INT_MAX);
  707. } else
  708. skill_delunitgroup(group);
  709. return 0;
  710. #else
  711. if (--group->val2<=0)
  712. skill_delunitgroup(group);
  713. d->dmg_lv = ATK_BLOCK;
  714. return 0;
  715. #endif
  716. }
  717. status_change_end(bl, SC_SAFETYWALL, INVALID_TIMER);
  718. }
  719. if (sc->data[SC__MANHOLE]) {
  720. d->dmg_lv = ATK_BLOCK;
  721. return 0;
  722. }
  723. if( sc->data[SC_PNEUMA] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG ) {
  724. d->dmg_lv = ATK_BLOCK;
  725. skill_blown(src,bl,skill_get_blewcount(skill_id,skill_lv),-1,0);
  726. return 0;
  727. }
  728. if( sc->data[SC_WEAPONBLOCKING] && flag&(BF_SHORT|BF_WEAPON) && rnd()%100 < sc->data[SC_WEAPONBLOCKING]->val2 ) {
  729. clif_skill_nodamage(bl,src,GC_WEAPONBLOCKING,1,1);
  730. d->dmg_lv = ATK_BLOCK;
  731. sc_start2(src,bl,SC_COMBO,100,GC_WEAPONBLOCKING,src->id,2000);
  732. return 0;
  733. }
  734. if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill_get_nk(skill_id)&NK_NO_CARDFIX_ATK) && rnd()%100 < sce->val2 ) {
  735. int delay;
  736. clif_skill_nodamage(bl,bl,CR_AUTOGUARD,sce->val1,1);
  737. // different delay depending on skill level [celest]
  738. if (sce->val1 <= 5)
  739. delay = 300;
  740. else if (sce->val1 > 5 && sce->val1 <= 9)
  741. delay = 200;
  742. else
  743. delay = 100;
  744. unit_set_walkdelay(bl, gettick(), delay, 1);
  745. if(sc->data[SC_SHRINK] && rnd()%100<5*sce->val1)
  746. skill_blown(bl,src,skill_get_blewcount(CR_SHRINK,1),-1,0);
  747. return 0;
  748. }
  749. if( (sce = sc->data[SC_MILLENNIUMSHIELD]) && sce->val2 > 0 && damage > 0 ) {
  750. clif_skill_nodamage(bl, bl, RK_MILLENNIUMSHIELD, 1, 1);
  751. sce->val3 -= (int)cap_value(damage,INT_MIN,INT_MAX); // absorb damage
  752. d->dmg_lv = ATK_BLOCK;
  753. sc_start(src,bl,SC_STUN,15,0,skill_get_time2(RK_MILLENNIUMSHIELD,sce->val1)); // There is a chance to be stuned when one shield is broken.
  754. if( sce->val3 <= 0 ) { // Shield Down
  755. sce->val2--;
  756. if( sce->val2 > 0 ) {
  757. if( sd )
  758. clif_millenniumshield(sd,sce->val2);
  759. sce->val3 = 1000; // Next Shield
  760. } else
  761. status_change_end(bl,SC_MILLENNIUMSHIELD,INVALID_TIMER); // All shields down
  762. }
  763. return 0;
  764. }
  765. // attack blocked by Parrying
  766. if( (sce=sc->data[SC_PARRYING]) && flag&BF_WEAPON && skill_id != WS_CARTTERMINATION && rnd()%100 < sce->val2 ) {
  767. clif_skill_nodamage(bl, bl, LK_PARRYING, sce->val1,1);
  768. return 0;
  769. }
  770. if(sc->data[SC_DODGE] && ( !sc->opt1 || sc->opt1 == OPT1_BURNING ) &&
  771. (flag&BF_LONG || sc->data[SC_SPURT])
  772. && rnd()%100 < 20)
  773. {
  774. if (sd && pc_issit(sd)) pc_setstand(sd); //Stand it to dodge.
  775. clif_skill_nodamage(bl,bl,TK_DODGE,1,1);
  776. if (!sc->data[SC_COMBO])
  777. sc_start4(src,bl, SC_COMBO, 100, TK_JUMPKICK, src->id, 1, 0, 2000);
  778. return 0;
  779. }
  780. if(sc->data[SC_HERMODE] && flag&BF_MAGIC)
  781. return 0;
  782. if(sc->data[SC_TATAMIGAESHI] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG)
  783. return 0;
  784. // TODO: Find out whether Neutral Barrier really blocks all splash damage or just specific cases (Earthquake)
  785. if( sc->data[SC_NEUTRALBARRIER] && ((flag&(BF_MAGIC|BF_LONG)) == BF_LONG || (skill_id && skill_get_splash(skill_id,skill_lv))) ) {
  786. d->dmg_lv = ATK_MISS;
  787. return 0;
  788. }
  789. //Kaupe blocks damage (skill or otherwise) from players, mobs, homuns, mercenaries.
  790. if((sce=sc->data[SC_KAUPE]) && rnd()%100 < sce->val2) {
  791. clif_specialeffect(bl, 462, AREA);
  792. //Shouldn't end until Breaker's non-weapon part connects.
  793. #ifndef RENEWAL
  794. if (skill_id != ASC_BREAKER || !(flag&BF_WEAPON))
  795. #endif
  796. if (--(sce->val3) <= 0) //We make it work like Safety Wall, even though it only blocks 1 time.
  797. status_change_end(bl, SC_KAUPE, INVALID_TIMER);
  798. return 0;
  799. }
  800. if( flag&BF_MAGIC && (sce=sc->data[SC_PRESTIGE]) && rnd()%100 < sce->val2) {
  801. clif_specialeffect(bl, 462, AREA); // Still need confirm it.
  802. return 0;
  803. }
  804. if (((sce=sc->data[SC_UTSUSEMI]) || sc->data[SC_BUNSINJYUTSU])
  805. && flag&BF_WEAPON && !(skill_get_nk(skill_id)&NK_NO_CARDFIX_ATK))
  806. {
  807. skill_additional_effect (src, bl, skill_id, skill_lv, flag, ATK_BLOCK, gettick() );
  808. if( !status_isdead(src) )
  809. skill_counter_additional_effect( src, bl, skill_id, skill_lv, flag, gettick() );
  810. if (sce) {
  811. clif_specialeffect(bl, 462, AREA);
  812. skill_blown(src,bl,sce->val3,-1,0);
  813. }
  814. //Both need to be consumed if they are active.
  815. if (sce && --(sce->val2) <= 0)
  816. status_change_end(bl, SC_UTSUSEMI, INVALID_TIMER);
  817. if ((sce=sc->data[SC_BUNSINJYUTSU]) && --(sce->val2) <= 0)
  818. status_change_end(bl, SC_BUNSINJYUTSU, INVALID_TIMER);
  819. return 0;
  820. }
  821. //Now damage increasing effects
  822. if( sc->data[SC_AETERNA] && skill_id != PF_SOULBURN ) {
  823. if( src->type != BL_MER || skill_id == 0 )
  824. damage <<= 1; // Lex Aeterna only doubles damage of regular attacks from mercenaries
  825. #ifndef RENEWAL
  826. if( skill_id != ASC_BREAKER || !(flag&BF_WEAPON) )
  827. #endif
  828. status_change_end(bl, SC_AETERNA, INVALID_TIMER); //Shouldn't end until Breaker's non-weapon part connects.
  829. }
  830. #ifdef RENEWAL
  831. if( sc->data[SC_RAID] ) {
  832. DAMAGE_ADDRATE(20)
  833. if (--sc->data[SC_RAID]->val1 == 0)
  834. status_change_end(bl, SC_RAID, INVALID_TIMER);
  835. }
  836. #endif
  837. if( damage ) {
  838. struct map_session_data *tsd = BL_CAST(BL_PC, src);
  839. if( sc->data[SC_DEEPSLEEP] ) {
  840. damage += damage / 2; // 1.5 times more damage while in Deep Sleep.
  841. status_change_end(bl,SC_DEEPSLEEP,INVALID_TIMER);
  842. }
  843. if( tsd && sd && sc->data[SC_CRYSTALIZE] && flag&BF_WEAPON ) {
  844. switch(tsd->status.weapon) {
  845. case W_MACE:
  846. case W_2HMACE:
  847. case W_1HAXE:
  848. case W_2HAXE:
  849. DAMAGE_RATE(150)
  850. break;
  851. case W_MUSICAL:
  852. case W_WHIP:
  853. if(!sd->state.arrow_atk)
  854. break;
  855. case W_BOW:
  856. case W_REVOLVER:
  857. case W_RIFLE:
  858. case W_GATLING:
  859. case W_SHOTGUN:
  860. case W_GRENADE:
  861. case W_DAGGER:
  862. case W_1HSWORD:
  863. case W_2HSWORD:
  864. DAMAGE_RATE(50)
  865. break;
  866. }
  867. }
  868. if( sc->data[SC_VOICEOFSIREN] )
  869. status_change_end(bl,SC_VOICEOFSIREN,INVALID_TIMER);
  870. }
  871. /**
  872. * Damage reductions
  873. **/
  874. // Assumptio doubles the def & mdef on RE mode, otherwise gives a reduction on the final damage. [Igniz]
  875. #ifndef RENEWAL
  876. if( sc->data[SC_ASSUMPTIO] ) {
  877. if( map_flag_vs(bl->m) )
  878. damage = (int64)damage*2/3; //Receive 66% damage
  879. else
  880. damage >>= 1; //Receive 50% damage
  881. }
  882. #endif
  883. if(sc->data[SC_DEFENDER] &&
  884. (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
  885. DAMAGE_RATE(100-sc->data[SC_DEFENDER]->val2)
  886. if(sc->data[SC_ADJUSTMENT] &&
  887. (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
  888. DAMAGE_SUBRATE(20)
  889. if(sc->data[SC_FOGWALL] && skill_id != RK_DRAGONBREATH) {
  890. if(flag&BF_SKILL) //25% reduction
  891. DAMAGE_SUBRATE(25)
  892. else if ((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
  893. damage >>= 2; //75% reduction
  894. }
  895. // Compressed code, fixed by map.h [Epoque]
  896. if (src->type == BL_MOB) {
  897. int i;
  898. if (sc->data[SC_MANU_DEF])
  899. for (i=0;ARRAYLENGTH(mob_manuk)>i;i++)
  900. if (mob_manuk[i]==((TBL_MOB*)src)->class_) {
  901. DAMAGE_SUBRATE(sc->data[SC_MANU_DEF]->val1)
  902. break;
  903. }
  904. if (sc->data[SC_SPL_DEF])
  905. for (i=0;ARRAYLENGTH(mob_splendide)>i;i++)
  906. if (mob_splendide[i]==((TBL_MOB*)src)->class_) {
  907. DAMAGE_SUBRATE(sc->data[SC_SPL_DEF]->val1)
  908. break;
  909. }
  910. }
  911. if((sce=sc->data[SC_ARMOR]) && //NPC_DEFENDER
  912. sce->val3&flag && sce->val4&flag)
  913. DAMAGE_SUBRATE(sc->data[SC_ARMOR]->val2)
  914. #ifdef RENEWAL
  915. if(sc->data[SC_ENERGYCOAT] && (flag&BF_WEAPON || flag&BF_MAGIC) && skill_id != WS_CARTTERMINATION)
  916. #else
  917. if(sc->data[SC_ENERGYCOAT] && flag&BF_WEAPON && skill_id != WS_CARTTERMINATION)
  918. #endif
  919. {
  920. struct status_data *status = status_get_status_data(bl);
  921. int per = 100*status->sp / status->max_sp -1; //100% should be counted as the 80~99% interval
  922. per /=20; //Uses 20% SP intervals.
  923. //SP Cost: 1% + 0.5% per every 20% SP
  924. if (!status_charge(bl, 0, (10+5*per)*status->max_sp/1000))
  925. status_change_end(bl, SC_ENERGYCOAT, INVALID_TIMER);
  926. //Reduction: 6% + 6% every 20%
  927. DAMAGE_SUBRATE(6 * (1+per))
  928. }
  929. if(sc->data[SC_GRANITIC_ARMOR]){
  930. DAMAGE_SUBRATE(sc->data[SC_GRANITIC_ARMOR]->val2)
  931. }
  932. if(sc->data[SC_PAIN_KILLER]){
  933. damage -= sc->data[SC_PAIN_KILLER]->val3;
  934. damage = max(1,damage);
  935. }
  936. if((sce=sc->data[SC_MAGMA_FLOW]) && (rnd()%100 <= sce->val2) ){
  937. skill_castend_damage_id(bl,src,MH_MAGMA_FLOW,sce->val1,gettick(),0);
  938. }
  939. if( damage > 0 && ((flag&(BF_WEAPON|BF_SHORT))==(BF_WEAPON|BF_SHORT)) && (sce = sc->data[SC_STONEHARDSKIN]) ) {
  940. sce->val2 -= (int)cap_value(damage,INT_MIN,INT_MAX);;
  941. if( src->type == BL_MOB ) //using explicite call instead break_equip for duration
  942. sc_start(src,src, SC_STRIPWEAPON, 30, 0, skill_get_time2(RK_STONEHARDSKIN, sce->val1));
  943. else
  944. skill_break_equip(src,src, EQP_WEAPON, 3000, BCT_SELF);
  945. if( sce->val2 <= 0 )
  946. status_change_end(bl, SC_STONEHARDSKIN, INVALID_TIMER);
  947. }
  948. #ifdef RENEWAL
  949. // Renewal: steel body reduces all incoming damage to 1/10 [helvetica]
  950. if( sc->data[SC_STEELBODY] ) {
  951. damage = damage > 10 ? damage / 10 : 1;
  952. }
  953. #endif
  954. //Finally added to remove the status of immobile when aimedbolt is used. [Jobbie]
  955. if( skill_id == RA_AIMEDBOLT && (sc->data[SC_BITE] || sc->data[SC_ANKLE] || sc->data[SC_ELECTRICSHOCKER]) ) {
  956. status_change_end(bl, SC_BITE, INVALID_TIMER);
  957. status_change_end(bl, SC_ANKLE, INVALID_TIMER);
  958. status_change_end(bl, SC_ELECTRICSHOCKER, INVALID_TIMER);
  959. }
  960. //Finally Kyrie because it may, or not, reduce damage to 0.
  961. if((sce = sc->data[SC_KYRIE]) && damage > 0){
  962. sce->val2 -= (int)cap_value(damage,INT_MIN,INT_MAX);;
  963. if(flag&BF_WEAPON || skill_id == TF_THROWSTONE){
  964. if(sce->val2>=0)
  965. damage=0;
  966. else
  967. damage=-sce->val2;
  968. }
  969. if((--sce->val3)<=0 || (sce->val2<=0) || skill_id == AL_HOLYLIGHT)
  970. status_change_end(bl, SC_KYRIE, INVALID_TIMER);
  971. }
  972. if( sc->data[SC_MEIKYOUSISUI] && rand()%100 < 40 ) // custom value
  973. damage = 0;
  974. if (!damage) return 0;
  975. if( (sce = sc->data[SC_LIGHTNINGWALK]) && flag&BF_LONG && rnd()%100 < sce->val1 ) {
  976. int dx[8]={0,-1,-1,-1,0,1,1,1};
  977. int dy[8]={1,1,0,-1,-1,-1,0,1};
  978. uint8 dir = map_calc_dir(bl, src->x, src->y);
  979. if( unit_movepos(bl, src->x-dx[dir], src->y-dy[dir], 1, 1) ) {
  980. clif_slide(bl,src->x-dx[dir],src->y-dy[dir]);
  981. unit_setdir(bl, dir);
  982. }
  983. d->dmg_lv = ATK_DEF;
  984. status_change_end(bl, SC_LIGHTNINGWALK, INVALID_TIMER);
  985. return 0;
  986. }
  987. //Probably not the most correct place, but it'll do here
  988. //(since battle_drain is strictly for players currently)
  989. if ((sce=sc->data[SC_BLOODLUST]) && flag&BF_WEAPON && damage > 0 &&
  990. rnd()%100 < sce->val3)
  991. status_heal(src, (int64)damage*sce->val4/100, 0, 3);
  992. if( sd && (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rnd()%100 < sce->val2 )
  993. pc_addspiritball(sd,skill_get_time(LG_FORCEOFVANGUARD,sce->val1),sce->val3);
  994. if (sc->data[SC_STYLE_CHANGE]) {
  995. TBL_HOM *hd = BL_CAST(BL_HOM,bl); //when being hit
  996. if (hd && (rnd()%100<(status_get_lv(bl)/2)) ) hom_addspiritball(hd, 10); //add a sphere
  997. }
  998. if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 )
  999. status_change_spread(bl, src); // Deadly infect attacked side
  1000. if( sc && sc->data[SC__SHADOWFORM] ) {
  1001. struct block_list *s_bl = map_id2bl(sc->data[SC__SHADOWFORM]->val2);
  1002. if( !s_bl || s_bl->m != bl->m ) { // If the shadow form target is not present remove the sc.
  1003. status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
  1004. } else if( status_isdead(s_bl) || !battle_check_target(src,s_bl,BCT_ENEMY)) { // If the shadow form target is dead or not your enemy remove the sc in both.
  1005. status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
  1006. if( s_bl->type == BL_PC )
  1007. ((TBL_PC*)s_bl)->shadowform_id = 0;
  1008. } else {
  1009. if( (--sc->data[SC__SHADOWFORM]->val3) < 0 ) { // If you have exceded max hits supported, remove the sc in both.
  1010. status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
  1011. if( s_bl->type == BL_PC )
  1012. ((TBL_PC*)s_bl)->shadowform_id = 0;
  1013. } else {
  1014. status_damage(bl, s_bl, damage, 0, clif_damage(s_bl, s_bl, gettick(), 500, 500, damage, -1, 0, 0), 0);
  1015. return ATK_NONE;
  1016. }
  1017. }
  1018. }
  1019. }
  1020. //SC effects from caster side.
  1021. sc = status_get_sc(src);
  1022. if (sc && sc->count) {
  1023. if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
  1024. DAMAGE_ADDRATE(75)
  1025. // [Epoque]
  1026. if (bl->type == BL_MOB) {
  1027. uint8 i;
  1028. if ( ((sce=sc->data[SC_MANU_ATK]) && (flag&BF_WEAPON)) ||
  1029. ((sce=sc->data[SC_MANU_MATK]) && (flag&BF_MAGIC))
  1030. )
  1031. for (i=0;ARRAYLENGTH(mob_manuk)>i;i++)
  1032. if (((TBL_MOB*)bl)->class_==mob_manuk[i]) {
  1033. DAMAGE_ADDRATE(sce->val1)
  1034. break;
  1035. }
  1036. if ( ((sce=sc->data[SC_SPL_ATK]) && (flag&BF_WEAPON)) ||
  1037. ((sce=sc->data[SC_SPL_MATK]) && (flag&BF_MAGIC))
  1038. )
  1039. for (i=0;ARRAYLENGTH(mob_splendide)>i;i++)
  1040. if (((TBL_MOB*)bl)->class_==mob_splendide[i]) {
  1041. DAMAGE_ADDRATE(sce->val1)
  1042. break;
  1043. }
  1044. }
  1045. if( sc->data[SC_POISONINGWEAPON]
  1046. && ((flag&BF_WEAPON) && (!skill_id || skill_id == GC_VENOMPRESSURE)) //chk skill type poison_smoke is a unit
  1047. && (damage > 0 && rnd()%100 < sc->data[SC_POISONINGWEAPON]->val3 )) //did some dammage and chance ok (why no additional effect ??
  1048. sc_start(src,bl,(enum sc_type)sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,skill_get_time2(GC_POISONINGWEAPON, 1));
  1049. if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 )
  1050. status_change_spread(src, bl);
  1051. if (sc->data[SC_STYLE_CHANGE]) {
  1052. TBL_HOM *hd = BL_CAST(BL_HOM,src); //when attacking
  1053. if (hd && (rnd()%100<(20+status_get_lv(bl)/5)) ) hom_addspiritball(hd, 10);
  1054. }
  1055. }
  1056. //PK damage rates
  1057. if (battle_config.pk_mode && sd && bl->type == BL_PC && damage && map[bl->m].flag.pvp) {
  1058. if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex]
  1059. if (flag&BF_WEAPON)
  1060. DAMAGE_RATE(battle_config.pk_weapon_damage_rate)
  1061. if (flag&BF_MAGIC)
  1062. DAMAGE_RATE(battle_config.pk_magic_damage_rate)
  1063. if (flag&BF_MISC)
  1064. DAMAGE_RATE(battle_config.pk_misc_damage_rate)
  1065. } else { //Normal attacks get reductions based on range.
  1066. if (flag & BF_SHORT)
  1067. DAMAGE_RATE(battle_config.pk_short_damage_rate)
  1068. if (flag & BF_LONG)
  1069. DAMAGE_RATE(battle_config.pk_long_damage_rate)
  1070. }
  1071. if(!damage) damage = 1;
  1072. }
  1073. if(battle_config.skill_min_damage && damage > 0 && damage < div_) {
  1074. if ((flag&BF_WEAPON && battle_config.skill_min_damage&1)
  1075. || (flag&BF_MAGIC && battle_config.skill_min_damage&2)
  1076. || (flag&BF_MISC && battle_config.skill_min_damage&4)
  1077. )
  1078. damage = div_;
  1079. }
  1080. if( bl->type == BL_MOB && !status_isdead(bl) && src != bl) {
  1081. if (damage > 0 )
  1082. mobskill_event((TBL_MOB*)bl,src,gettick(),flag);
  1083. if (skill_id)
  1084. mobskill_event((TBL_MOB*)bl,src,gettick(),MSC_SKILLUSED|(skill_id<<16));
  1085. }
  1086. if( sd ) {
  1087. if( pc_ismadogear(sd) && rnd()%100 < 50 ) {
  1088. short element = skill_get_ele(skill_id, skill_lv);
  1089. if( !skill_id || element == -1 ) { //Take weapon's element
  1090. struct status_data *sstatus = NULL;
  1091. if( src->type == BL_PC && ((TBL_PC*)src)->bonus.arrow_ele )
  1092. element = ((TBL_PC*)src)->bonus.arrow_ele;
  1093. else if( (sstatus = status_get_status_data(src)) ) {
  1094. element = sstatus->rhw.ele;
  1095. }
  1096. }
  1097. else if( element == -2 ) //Use enchantment's element
  1098. element = status_get_attack_sc_element(src,status_get_sc(src));
  1099. else if( element == -3 ) //Use random element
  1100. element = rnd()%ELE_MAX;
  1101. if( element == ELE_FIRE || element == ELE_WATER )
  1102. pc_overheat(sd,element == ELE_FIRE ? 1 : -1);
  1103. }
  1104. }
  1105. return damage;
  1106. }
  1107. /*==========================================
  1108. * Calculates BG related damage adjustments.
  1109. *------------------------------------------
  1110. * Credits:
  1111. * Original coder Skoltex
  1112. * Initial refactoring by Baalberith
  1113. * Refined and optimized by helvetica
  1114. */
  1115. int64 battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int64 damage, int div_, uint16 skill_id, uint16 skill_lv, int flag)
  1116. {
  1117. if( !damage )
  1118. return 0;
  1119. if( bl->type == BL_MOB ) {
  1120. struct mob_data* md = BL_CAST(BL_MOB, bl);
  1121. if( map[bl->m].flag.battleground && (md->class_ == MOBID_BLUE_CRYST || md->class_ == MOBID_PINK_CRYST) && flag&BF_SKILL )
  1122. return 0; // Crystal cannot receive skill damage on battlegrounds
  1123. }
  1124. if(skill_get_inf2(skill_id)&INF2_NO_BG_DMG)
  1125. return damage; //skill that ignore bg map reduction
  1126. if( flag&BF_SKILL ) { //Skills get a different reduction than non-skills. [Skotlex]
  1127. if( flag&BF_WEAPON )
  1128. DAMAGE_RATE(battle_config.bg_weapon_damage_rate)
  1129. if( flag&BF_MAGIC )
  1130. DAMAGE_RATE(battle_config.bg_magic_damage_rate)
  1131. if( flag&BF_MISC )
  1132. DAMAGE_RATE(battle_config.bg_misc_damage_rate)
  1133. }
  1134. else { //Normal attacks get reductions based on range.
  1135. if( flag&BF_SHORT )
  1136. DAMAGE_RATE(battle_config.bg_short_damage_rate)
  1137. if( flag&BF_LONG )
  1138. DAMAGE_RATE(battle_config.bg_long_damage_rate)
  1139. }
  1140. damage = max(damage,1); //min 1 dammage
  1141. return damage;
  1142. }
  1143. /*==========================================
  1144. * Calculates GVG related damage adjustments.
  1145. *------------------------------------------*/
  1146. int64 battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int64 damage,int div_,uint16 skill_id,uint16 skill_lv,int flag)
  1147. {
  1148. struct mob_data* md = BL_CAST(BL_MOB, bl);
  1149. int class_ = status_get_class(bl);
  1150. if (!damage) //No reductions to make.
  1151. return 0;
  1152. if(md && md->guardian_data) {
  1153. if(class_ == MOBID_EMPERIUM && flag&BF_SKILL && !(skill_get_inf3(skill_id)&INF3_HIT_EMP)) //Skill immunity.
  1154. return 0;
  1155. if(src->type != BL_MOB) {
  1156. struct guild *g = src->type == BL_PC ? ((TBL_PC *)src)->guild : guild_search(status_get_guild_id(src));
  1157. if (class_ == MOBID_EMPERIUM && (!g || guild_checkskill(g,GD_APPROVAL) <= 0 ))
  1158. return 0;
  1159. if (g && battle_config.guild_max_castles && guild_checkcastles(g)>=battle_config.guild_max_castles)
  1160. return 0; // [MouseJstr]
  1161. }
  1162. }
  1163. if(skill_get_inf2(skill_id)&INF2_NO_GVG_DMG) //Skills with no gvg damage reduction.
  1164. return damage;
  1165. /* Uncomment if you want god-mode Emperiums at 100 defense. [Kisuka]
  1166. if (md && md->guardian_data) {
  1167. damage -= damage * (md->guardian_data->castle->defense/100) * battle_config.castle_defense_rate/100;
  1168. }
  1169. */
  1170. if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex]
  1171. if (flag&BF_WEAPON)
  1172. DAMAGE_RATE(battle_config.gvg_weapon_damage_rate)
  1173. if (flag&BF_MAGIC)
  1174. DAMAGE_RATE(battle_config.gvg_magic_damage_rate)
  1175. if (flag&BF_MISC)
  1176. DAMAGE_RATE(battle_config.gvg_misc_damage_rate)
  1177. } else { //Normal attacks get reductions based on range.
  1178. if (flag & BF_SHORT)
  1179. DAMAGE_RATE(battle_config.gvg_short_damage_rate)
  1180. if (flag & BF_LONG)
  1181. DAMAGE_RATE(battle_config.gvg_long_damage_rate)
  1182. }
  1183. damage = max(damage,1);
  1184. return damage;
  1185. }
  1186. /*==========================================
  1187. * HP/SP drain calculation
  1188. *------------------------------------------*/
  1189. static int battle_calc_drain(int64 damage, int rate, int per)
  1190. {
  1191. int64 diff = 0;
  1192. if (per && rnd()%1000 < rate) {
  1193. diff = (damage * per) / 100;
  1194. if (diff == 0) {
  1195. if (per > 0)
  1196. diff = 1;
  1197. else
  1198. diff = -1;
  1199. }
  1200. }
  1201. return (int)diff;
  1202. }
  1203. /*==========================================
  1204. * Passive skill damage increases
  1205. *------------------------------------------*/
  1206. int64 battle_addmastery(struct map_session_data *sd,struct block_list *target,int64 dmg,int type)
  1207. {
  1208. int64 damage;
  1209. struct status_data *status = status_get_status_data(target);
  1210. int weapon,skill;
  1211. #ifdef RENEWAL
  1212. damage = 0;
  1213. #else
  1214. damage = dmg;
  1215. #endif
  1216. nullpo_ret(sd);
  1217. if((skill = pc_checkskill(sd,AL_DEMONBANE)) > 0 &&
  1218. target->type == BL_MOB && //This bonus doesnt work against players.
  1219. (battle_check_undead(status->race,status->def_ele) || status->race==RC_DEMON) )
  1220. damage += (skill*(int)(3+(sd->status.base_level+1)*0.05)); // submitted by orn
  1221. //damage += (skill * 3);
  1222. if( (skill = pc_checkskill(sd, RA_RANGERMAIN)) > 0 && (status->race == RC_BRUTE || status->race == RC_PLANT || status->race == RC_FISH) )
  1223. damage += (skill * 5);
  1224. if( (skill = pc_checkskill(sd,NC_RESEARCHFE)) > 0 && (status->def_ele == ELE_FIRE || status->def_ele == ELE_EARTH) )
  1225. damage += (skill * 10);
  1226. if( pc_ismadogear(sd) )
  1227. damage += 20 + 20 * pc_checkskill(sd, NC_MADOLICENCE);
  1228. if((skill = pc_checkskill(sd,HT_BEASTBANE)) > 0 && (status->race==RC_BRUTE || status->race==RC_INSECT) ) {
  1229. damage += (skill * 4);
  1230. if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_HUNTER)
  1231. damage += sd->status.str;
  1232. }
  1233. if(type == 0)
  1234. weapon = sd->weapontype1;
  1235. else
  1236. weapon = sd->weapontype2;
  1237. switch(weapon) {
  1238. case W_1HSWORD:
  1239. #ifdef RENEWAL
  1240. if((skill = pc_checkskill(sd,AM_AXEMASTERY)) > 0)
  1241. damage += (skill * 3);
  1242. #endif
  1243. case W_DAGGER:
  1244. if((skill = pc_checkskill(sd,SM_SWORD)) > 0)
  1245. damage += (skill * 4);
  1246. if((skill = pc_checkskill(sd,GN_TRAINING_SWORD)) > 0)
  1247. damage += skill * 10;
  1248. break;
  1249. case W_2HSWORD:
  1250. #ifdef RENEWAL
  1251. if((skill = pc_checkskill(sd,AM_AXEMASTERY)) > 0)
  1252. damage += (skill * 3);
  1253. #endif
  1254. if((skill = pc_checkskill(sd,SM_TWOHAND)) > 0)
  1255. damage += (skill * 4);
  1256. break;
  1257. case W_1HSPEAR:
  1258. case W_2HSPEAR:
  1259. if((skill = pc_checkskill(sd,KN_SPEARMASTERY)) > 0) {
  1260. if(!pc_isriding(sd) || !pc_isridingdragon(sd))
  1261. damage += (skill * 4);
  1262. else
  1263. damage += (skill * 5);
  1264. // Increase damage by level of KN_SPEARMASTERY * 10
  1265. if(pc_checkskill(sd,RK_DRAGONTRAINING) > 0)
  1266. damage += (skill * 10);
  1267. }
  1268. break;
  1269. case W_1HAXE:
  1270. case W_2HAXE:
  1271. if((skill = pc_checkskill(sd,AM_AXEMASTERY)) > 0)
  1272. damage += (skill * 3);
  1273. if((skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
  1274. damage += (skill * 5);
  1275. break;
  1276. case W_MACE:
  1277. case W_2HMACE:
  1278. if((skill = pc_checkskill(sd,PR_MACEMASTERY)) > 0)
  1279. damage += (skill * 3);
  1280. if((skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
  1281. damage += (skill * 5);
  1282. break;
  1283. case W_FIST:
  1284. if((skill = pc_checkskill(sd,TK_RUN)) > 0)
  1285. damage += (skill * 10);
  1286. // No break, fallthrough to Knuckles
  1287. case W_KNUCKLE:
  1288. if((skill = pc_checkskill(sd,MO_IRONHAND)) > 0)
  1289. damage += (skill * 3);
  1290. break;
  1291. case W_MUSICAL:
  1292. if((skill = pc_checkskill(sd,BA_MUSICALLESSON)) > 0)
  1293. damage += (skill * 3);
  1294. break;
  1295. case W_WHIP:
  1296. if((skill = pc_checkskill(sd,DC_DANCINGLESSON)) > 0)
  1297. damage += (skill * 3);
  1298. break;
  1299. case W_BOOK:
  1300. if((skill = pc_checkskill(sd,SA_ADVANCEDBOOK)) > 0)
  1301. damage += (skill * 3);
  1302. break;
  1303. case W_KATAR:
  1304. if((skill = pc_checkskill(sd,AS_KATAR)) > 0)
  1305. damage += (skill * 3);
  1306. break;
  1307. }
  1308. if(sd && (skill=pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0) // weapon research bonus applies to all weapons
  1309. damage += skill*2;
  1310. if(sd->sc.data[SC_GN_CARTBOOST]) // cart boost adds mastery type damage
  1311. damage += 10*sd->sc.data[SC_GN_CARTBOOST]->val1;
  1312. return damage;
  1313. }
  1314. #ifdef RENEWAL
  1315. static int64 battle_calc_sizefix(int64 damage, struct map_session_data *sd, unsigned char t_size, unsigned char weapon_type, short flag)
  1316. {
  1317. if (sd) {
  1318. //SizeFix only for players
  1319. if (!(sd->special_state.no_sizefix) && !flag)
  1320. DAMAGE_RATE(weapon_type==EQI_HAND_L?
  1321. sd->left_weapon.atkmods[t_size]:
  1322. sd->right_weapon.atkmods[t_size])
  1323. }
  1324. return damage;
  1325. }
  1326. static int battle_calc_status_attack(struct status_data *status, short hand)
  1327. {
  1328. //left-hand penalty on sATK is always 50% [Baalberith]
  1329. if (hand == EQI_HAND_L)
  1330. return status->batk;
  1331. else
  1332. return 2 * status->batk;
  1333. }
  1334. static int battle_calc_base_weapon_attack(struct block_list *src, struct status_data *tstatus, struct weapon_atk *wa, struct map_session_data *sd)
  1335. {
  1336. struct status_data *status = status_get_status_data(src);
  1337. unsigned short atkmax = (wa == &status->lhw)?status->watk2:status->watk;
  1338. unsigned short atkmin = atkmax;
  1339. unsigned short weapon_perfection = 0;
  1340. int damage;
  1341. struct status_change *sc = status_get_sc(src);
  1342. unsigned char type = (wa == &status->lhw)?EQI_HAND_L:EQI_HAND_R;
  1343. if (sd->equip_index[type] >= 0 && sd->inventory_data[sd->equip_index[type]]) {
  1344. atkmin -= wa->atk * (sd->inventory_data[sd->equip_index[type]]->wlv*5)/100;
  1345. atkmax += wa->atk * (sd->inventory_data[sd->equip_index[type]]->wlv*5)/100;
  1346. }
  1347. if (sc && sc->data[SC_MAXIMIZEPOWER])
  1348. damage = atkmax;
  1349. else
  1350. damage = (atkmax>atkmin? rnd()%(atkmax-atkmin):0) + atkmin;
  1351. if (sc && sc->data[SC_WEAPONPERFECTION])
  1352. weapon_perfection = 1;
  1353. damage = (int)battle_calc_sizefix(damage, sd, tstatus->size, type, weapon_perfection);
  1354. return damage;
  1355. }
  1356. #endif
  1357. /*==========================================
  1358. * Calculates the standard damage of a normal attack assuming it hits,
  1359. * it calculates nothing extra fancy, is needed for magnum break's WATK_ELEMENT bonus. [Skotlex]
  1360. * This applies to pre-renewal and non-sd in renewal
  1361. *------------------------------------------
  1362. * Pass damage2 as NULL to not calc it.
  1363. * Flag values:
  1364. * &1: Critical hit
  1365. * &2: Arrow attack
  1366. * &4: Skill is Magic Crasher
  1367. * &8: Skip target size adjustment (Extremity Fist?)
  1368. *&16: Arrow attack but BOW, REVOLVER, RIFLE, SHOTGUN, GATLING or GRENADE type weapon not equipped (i.e. shuriken, kunai and venom knives not affected by DEX)
  1369. *
  1370. * Credits:
  1371. * Original coder Skoltex
  1372. * Initial refactoring by Baalberith
  1373. * Refined and optimized by helvetica
  1374. */
  1375. static int64 battle_calc_base_damage(struct status_data *status, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag)
  1376. {
  1377. unsigned int atkmin=0, atkmax=0;
  1378. short type = 0;
  1379. int64 damage = 0;
  1380. if (!sd) { //Mobs/Pets
  1381. if(flag&4) {
  1382. atkmin = status->matk_min;
  1383. atkmax = status->matk_max;
  1384. } else {
  1385. atkmin = wa->atk;
  1386. atkmax = wa->atk2;
  1387. }
  1388. if (atkmin > atkmax)
  1389. atkmin = atkmax;
  1390. } else { //PCs
  1391. atkmax = wa->atk;
  1392. type = (wa == &status->lhw)?EQI_HAND_L:EQI_HAND_R;
  1393. if (!(flag&1) || (flag&2)) { //Normal attacks
  1394. atkmin = status->dex;
  1395. if (sd->equip_index[type] >= 0 && sd->inventory_data[sd->equip_index[type]])
  1396. atkmin = atkmin*(80 + sd->inventory_data[sd->equip_index[type]]->wlv*20)/100;
  1397. if (atkmin > atkmax)
  1398. atkmin = atkmax;
  1399. if(flag&2 && !(flag&16)) { //Bows
  1400. atkmin = atkmin*atkmax/100;
  1401. if (atkmin > atkmax)
  1402. atkmax = atkmin;
  1403. }
  1404. }
  1405. }
  1406. if (sc && sc->data[SC_MAXIMIZEPOWER])
  1407. atkmin = atkmax;
  1408. //Weapon Damage calculation
  1409. if (!(flag&1))
  1410. damage = (atkmax>atkmin? rnd()%(atkmax-atkmin):0)+atkmin;
  1411. else
  1412. damage = atkmax;
  1413. if (sd) {
  1414. //rodatazone says the range is 0~arrow_atk-1 for non crit
  1415. if (flag&2 && sd->bonus.arrow_atk)
  1416. damage += ( (flag&1) ? sd->bonus.arrow_atk : rnd()%sd->bonus.arrow_atk );
  1417. //SizeFix only for players
  1418. if (!(sd->special_state.no_sizefix || (flag&8)))
  1419. DAMAGE_RATE(type==EQI_HAND_L?
  1420. sd->left_weapon.atkmods[t_size]:
  1421. sd->right_weapon.atkmods[t_size])
  1422. }
  1423. //Finally, add baseatk
  1424. if(flag&4)
  1425. damage += status->matk_min;
  1426. else
  1427. damage += status->batk;
  1428. //rodatazone says that Overrefine bonuses are part of baseatk
  1429. //Here we also apply the weapon_atk_rate bonus so it is correctly applied on left/right hands.
  1430. if(sd) {
  1431. if (type == EQI_HAND_L) {
  1432. if(sd->left_weapon.overrefine)
  1433. damage += rnd()%sd->left_weapon.overrefine+1;
  1434. if (sd->weapon_atk_rate[sd->weapontype2])
  1435. DAMAGE_ADDRATE(sd->weapon_atk_rate[sd->weapontype2])
  1436. } else { //Right hand
  1437. if(sd->right_weapon.overrefine)
  1438. damage += rnd()%sd->right_weapon.overrefine+1;
  1439. if (sd->weapon_atk_rate[sd->weapontype1])
  1440. DAMAGE_ADDRATE(sd->weapon_atk_rate[sd->weapontype1])
  1441. }
  1442. }
  1443. #ifdef RENEWAL
  1444. if (flag&1)
  1445. damage = (damage * 14) / 10;
  1446. #endif
  1447. return damage;
  1448. }
  1449. /*==========================================
  1450. * Consumes ammo for the given skill.
  1451. *------------------------------------------
  1452. * Credits:
  1453. * Original coder Skoltex
  1454. * Initial refactoring by Baalberith
  1455. * Refined and optimized by helvetica
  1456. */
  1457. void battle_consume_ammo(TBL_PC*sd, int skill, int lv)
  1458. {
  1459. int qty=1;
  1460. if (!battle_config.arrow_decrement)
  1461. return;
  1462. if (skill) {
  1463. qty = skill_get_ammo_qty(skill, lv);
  1464. if (!qty) qty = 1;
  1465. }
  1466. if(sd->equip_index[EQI_AMMO]>=0) //Qty check should have been done in skill_check_condition
  1467. pc_delitem(sd,sd->equip_index[EQI_AMMO],qty,0,1,LOG_TYPE_CONSUME);
  1468. sd->state.arrow_atk = 0;
  1469. }
  1470. static int battle_range_type(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv)
  1471. {
  1472. // [Akinari] , [Xynvaroth]: Traps are always short range.
  1473. if( skill_get_inf2( skill_id ) & INF2_TRAP )
  1474. return BF_SHORT;
  1475. //Skill Range Criteria
  1476. if (battle_config.skillrange_by_distance &&
  1477. (src->type&battle_config.skillrange_by_distance)
  1478. ) { //based on distance between src/target [Skotlex]
  1479. if (check_distance_bl(src, target, 5))
  1480. return BF_SHORT;
  1481. return BF_LONG;
  1482. }
  1483. //based on used skill's range
  1484. if (skill_get_range2(src, skill_id, skill_lv) < 5)
  1485. return BF_SHORT;
  1486. return BF_LONG;
  1487. }
  1488. static int battle_blewcount_bonus(struct map_session_data *sd, uint16 skill_id)
  1489. {
  1490. uint8 i;
  1491. if (!sd->skillblown[0].id)
  1492. return 0;
  1493. //Apply the bonus blewcount. [Skotlex]
  1494. for (i = 0; i < ARRAYLENGTH(sd->skillblown) && sd->skillblown[i].id; i++) {
  1495. if (sd->skillblown[i].id == skill_id)
  1496. return sd->skillblown[i].val;
  1497. }
  1498. return 0;
  1499. }
  1500. /*==========================================
  1501. * Damage calculation for adjusting skill damage
  1502. * Credits:
  1503. [Lilith] for the first release of this
  1504. [Cydh] finishing and adding mapflag
  1505. * battle_skill_damage_skill() - skill_id based
  1506. * battle_skill_damage_map() - map based
  1507. *------------------------------------------*/
  1508. #ifdef ADJUST_SKILL_DAMAGE
  1509. bool battle_skill_damage_iscaster(uint8 caster, enum bl_type type)
  1510. {
  1511. if (caster == 0)
  1512. return false;
  1513. while (1) {
  1514. if (caster&SDC_PC && type == BL_PC) break;
  1515. if (caster&SDC_MOB && type == BL_MOB) break;
  1516. if (caster&SDC_PET && type == BL_PET) break;
  1517. if (caster&SDC_HOM && type == BL_HOM) break;
  1518. if (caster&SDC_MER && type == BL_MER) break;
  1519. if (caster&SDC_ELEM && type == BL_ELEM) break;
  1520. return false;
  1521. }
  1522. return true;
  1523. }
  1524. int battle_skill_damage_skill(struct block_list *src, struct block_list *target, uint16 skill_id)
  1525. {
  1526. unsigned short m = src->m;
  1527. int idx;
  1528. struct s_skill_damage *damage = NULL;
  1529. if ((idx = skill_get_index(skill_id)) < 0 || !skill_db[idx].damage.map)
  1530. return 0;
  1531. damage = &skill_db[idx].damage;
  1532. //check the adjustment works for specified type
  1533. if (!battle_skill_damage_iscaster(damage->caster,src->type))
  1534. return 0;
  1535. if ((damage->map&1 && (!map[m].flag.pvp && !map_flag_gvg(m) && !map[m].flag.battleground && !map[m].flag.skill_damage && !map[m].flag.restricted)) ||
  1536. (damage->map&2 && map[m].flag.pvp) ||
  1537. (damage->map&4 && map_flag_gvg(m)) ||
  1538. (damage->map&8 && map[m].flag.battleground) ||
  1539. (damage->map&16 && map[m].flag.skill_damage) ||
  1540. (map[m].flag.restricted && skill_db[idx].damage.map&(8*map[m].zone)))
  1541. {
  1542. switch (target->type) {
  1543. case BL_PC:
  1544. return damage->pc;
  1545. case BL_MOB:
  1546. if (is_boss(target))
  1547. return damage->boss;
  1548. else
  1549. return damage->mob;
  1550. default:
  1551. return damage->other;
  1552. }
  1553. }
  1554. return 0;
  1555. }
  1556. int battle_skill_damage_map(struct block_list *src, struct block_list *target, uint16 skill_id)
  1557. {
  1558. int rate = 0;
  1559. uint16 m = src->m;
  1560. uint8 i;
  1561. if (!map[m].flag.skill_damage)
  1562. return 0;
  1563. /* modifier for all skills */
  1564. if (battle_skill_damage_iscaster(map[m].adjust.damage.caster,src->type)) {
  1565. switch (target->type) {
  1566. case BL_PC:
  1567. rate = map[m].adjust.damage.pc;
  1568. break;
  1569. case BL_MOB:
  1570. if (is_boss(target))
  1571. rate = map[m].adjust.damage.boss;
  1572. else
  1573. rate = map[m].adjust.damage.mob;
  1574. break;
  1575. default:
  1576. rate = map[m].adjust.damage.other;
  1577. break;
  1578. }
  1579. }
  1580. /* modifier for specified map */
  1581. ARR_FIND(0,MAX_MAP_SKILL_MODIFIER,i,map[m].skill_damage[i].skill_id == skill_id);
  1582. if (i < MAX_MAP_SKILL_MODIFIER) {
  1583. if (battle_skill_damage_iscaster(map[m].skill_damage[i].caster,src->type)) {
  1584. switch (target->type) {
  1585. case BL_PC:
  1586. rate += map[m].skill_damage[i].pc;
  1587. break;
  1588. case BL_MOB:
  1589. if (is_boss(target))
  1590. rate += map[m].skill_damage[i].boss;
  1591. else
  1592. rate += map[m].skill_damage[i].mob;
  1593. break;
  1594. default:
  1595. rate += map[m].skill_damage[i].other;
  1596. break;
  1597. }
  1598. }
  1599. }
  1600. return rate;
  1601. }
  1602. int battle_skill_damage(struct block_list *src, struct block_list *target, uint16 skill_id)
  1603. {
  1604. if (!target)
  1605. return 0;
  1606. return battle_skill_damage_skill(src,target,skill_id) + battle_skill_damage_map(src,target,skill_id);
  1607. }
  1608. #endif
  1609. struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag);
  1610. struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag);
  1611. /*=======================================================
  1612. * Should infinite defense be applied on target? (plant)
  1613. *-------------------------------------------------------
  1614. * Credits:
  1615. * Original coder Skoltex
  1616. * Initial refactoring by Baalberith
  1617. * Refined and optimized by helvetica
  1618. */
  1619. static bool target_has_infinite_defense(struct block_list *target, int skill_id)
  1620. {
  1621. struct status_data *tstatus = status_get_status_data(target);
  1622. if(target->type == BL_SKILL){
  1623. TBL_SKILL *su = (TBL_SKILL*)target;
  1624. if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) )
  1625. return true;
  1626. }
  1627. return (tstatus->mode&MD_PLANT && skill_id != RA_CLUSTERBOMB
  1628. #ifdef RENEWAL
  1629. && skill_id != HT_FREEZINGTRAP && skill_id != HT_CLAYMORETRAP
  1630. #endif
  1631. );
  1632. }
  1633. /*========================
  1634. * Is attack arrow based?
  1635. *------------------------
  1636. * Credits:
  1637. * Original coder Skoltex
  1638. * Initial refactoring by Baalberith
  1639. * Refined and optimized by helvetica
  1640. */
  1641. static bool is_skill_using_arrow(struct block_list *src, int skill_id)
  1642. {
  1643. if(src != NULL) {
  1644. struct status_data *sstatus = status_get_status_data(src);
  1645. struct map_session_data *sd = BL_CAST(BL_PC, src);
  1646. return ((sd && sd->state.arrow_atk) || (!sd && ((skill_id && skill_get_ammotype(skill_id)) || sstatus->rhw.range>3)) || (skill_id == HT_PHANTASMIC));
  1647. } else
  1648. return false;
  1649. }
  1650. /*=========================================
  1651. * Is attack right handed? By default yes.
  1652. *-----------------------------------------
  1653. * Credits:
  1654. * Original coder Skoltex
  1655. * Initial refactoring by Baalberith
  1656. * Refined and optimized by helvetica
  1657. */
  1658. static bool is_attack_right_handed(struct block_list *src, int skill_id)
  1659. {
  1660. if(src != NULL) {
  1661. struct map_session_data *sd = BL_CAST(BL_PC, src);
  1662. //Skills ALWAYS use ONLY your right-hand weapon (tested on Aegis 10.2)
  1663. if(!skill_id && sd && sd->weapontype1 == 0 && sd->weapontype2 > 0)
  1664. return false;
  1665. }
  1666. return true;
  1667. }
  1668. /*=======================================
  1669. * Is attack left handed? By default no.
  1670. *---------------------------------------
  1671. * Credits:
  1672. * Original coder Skoltex
  1673. * Initial refactoring by Baalberith
  1674. * Refined and optimized by helvetica
  1675. */
  1676. static bool is_attack_left_handed(struct block_list *src, int skill_id)
  1677. {
  1678. if(src != NULL) {
  1679. struct status_data *sstatus = status_get_status_data(src);
  1680. struct map_session_data *sd = BL_CAST(BL_PC, src);
  1681. //Skills ALWAYS use ONLY your right-hand weapon (tested on Aegis 10.2)
  1682. if(!skill_id) {
  1683. if (sd && sd->weapontype1 == 0 && sd->weapontype2 > 0)
  1684. return true;
  1685. if (sstatus->lhw.atk)
  1686. return true;
  1687. if (sd && sd->status.weapon == W_KATAR)
  1688. return true;
  1689. }
  1690. }
  1691. return false;
  1692. }
  1693. /*=============================
  1694. * Do we score a critical hit?
  1695. *-----------------------------
  1696. * Credits:
  1697. * Original coder Skoltex
  1698. * Initial refactoring by Baalberith
  1699. * Refined and optimized by helvetica
  1700. */
  1701. static bool is_attack_critical(struct Damage wd, struct block_list *src, struct block_list *target, int skill_id, int skill_lv, bool first_call)
  1702. {
  1703. struct status_data *sstatus = status_get_status_data(src);
  1704. struct status_data *tstatus = status_get_status_data(target);
  1705. struct status_change *sc = status_get_sc(src);
  1706. struct status_change *tsc = status_get_sc(target);
  1707. struct map_session_data *sd = BL_CAST(BL_PC, src);
  1708. struct map_session_data *tsd = BL_CAST(BL_PC, target);
  1709. if (!first_call)
  1710. return (wd.type == 0x0a);
  1711. if (skill_id == NPC_CRITICALSLASH || skill_id == LG_PINPOINTATTACK) //Always critical skills
  1712. return true;
  1713. if( !(wd.type&0x08) && sstatus->cri &&
  1714. (!skill_id ||
  1715. skill_id == KN_AUTOCOUNTER ||
  1716. skill_id == SN_SHARPSHOOTING || skill_id == MA_SHARPSHOOTING ||
  1717. skill_id == NJ_KIRIKAGE))
  1718. {
  1719. short cri = sstatus->cri;
  1720. if (sd) {
  1721. cri+= sd->critaddrace[tstatus->race];
  1722. if(is_skill_using_arrow(src, skill_id))
  1723. cri += sd->bonus.arrow_cri;
  1724. }
  1725. if( sc && sc->data[SC_CAMOUFLAGE] )
  1726. cri += 100 * min(10,sc->data[SC_CAMOUFLAGE]->val3); //max 100% (1K)
  1727. //The official equation is *2, but that only applies when sd's do critical.
  1728. //Therefore, we use the old value 3 on cases when an sd gets attacked by a mob
  1729. cri -= tstatus->luk*(!sd&&tsd?3:2);
  1730. if( tsc && tsc->data[SC_SLEEP] )
  1731. cri <<= 1;
  1732. switch (skill_id) {
  1733. case KN_AUTOCOUNTER:
  1734. if(battle_config.auto_counter_type &&
  1735. (battle_config.auto_counter_type&src->type))
  1736. return true;
  1737. else
  1738. cri <<= 1;
  1739. break;
  1740. case SN_SHARPSHOOTING:
  1741. case MA_SHARPSHOOTING:
  1742. cri += 200;
  1743. break;
  1744. case NJ_KIRIKAGE:
  1745. cri += 250 + 50*skill_lv;
  1746. break;
  1747. }
  1748. if(tsd && tsd->bonus.critical_def)
  1749. cri = cri * ( 100 - tsd->bonus.critical_def ) / 100;
  1750. return (rnd()%1000 < cri);
  1751. }
  1752. return 0;
  1753. }
  1754. /*==========================================================
  1755. * Is the attack piercing? (Investigate/Ice Pick in pre-re)
  1756. *----------------------------------------------------------
  1757. * Credits:
  1758. * Original coder Skoltex
  1759. * Initial refactoring by Baalberith
  1760. * Refined and optimized by helvetica
  1761. */
  1762. static int is_attack_piercing(struct Damage wd, struct block_list *src, struct block_list *target, int skill_id, int skill_lv, short weapon_position)
  1763. {
  1764. if (skill_id == MO_INVESTIGATE)
  1765. return 2;
  1766. if(src != NULL) {
  1767. struct map_session_data *sd = BL_CAST(BL_PC, src);
  1768. struct status_data *tstatus = status_get_status_data(target);
  1769. #ifdef RENEWAL
  1770. if( skill_id != PA_SACRIFICE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS
  1771. && skill_id != PA_SHIELDCHAIN && skill_id != ASC_BREAKER ) // Renewal: Soul Breaker no longer gains ice pick effect and ice pick effect gets crit benefit [helvetica]
  1772. #else
  1773. if( skill_id != PA_SACRIFICE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS
  1774. && skill_id != PA_SHIELDCHAIN && !is_attack_critical(wd, src, target, skill_id, skill_lv, false) )
  1775. #endif
  1776. { //Elemental/Racial adjustments
  1777. if( sd && (sd->right_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) ||
  1778. sd->right_weapon.def_ratio_atk_race & (1<<tstatus->race) ||
  1779. sd->right_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS)))
  1780. )
  1781. if (weapon_position == EQI_HAND_R)
  1782. return 1;
  1783. if( sd && (sd->left_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) ||
  1784. sd->left_weapon.def_ratio_atk_race & (1<<tstatus->race) ||
  1785. sd->left_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS))) )
  1786. { //Pass effect onto right hand if configured so. [Skotlex]
  1787. if (battle_config.left_cardfix_to_right && is_attack_right_handed(src, skill_id))
  1788. if (weapon_position == EQI_HAND_R)
  1789. return 1;
  1790. else if (weapon_position == EQI_HAND_L)
  1791. return 1;
  1792. }
  1793. }
  1794. }
  1795. return 0;
  1796. }
  1797. static bool battle_skill_get_damage_properties(uint16 skill_id, int is_splash)
  1798. {
  1799. int nk = skill_get_nk(skill_id);
  1800. if( !skill_id && is_splash ) //If flag, this is splash damage from Baphomet Card and it always hits.
  1801. nk |= NK_NO_CARDFIX_ATK|NK_IGNORE_FLEE;
  1802. return nk;
  1803. }
  1804. /*=============================
  1805. * Checks if attack is hitting
  1806. *-----------------------------
  1807. * Credits:
  1808. * Original coder Skoltex
  1809. * Initial refactoring by Baalberith
  1810. * Refined and optimized by helvetica
  1811. */
  1812. static bool is_attack_hitting(struct Damage wd, struct block_list *src, struct block_list *target, int skill_id, int skill_lv, bool first_call)
  1813. {
  1814. struct status_data *sstatus = status_get_status_data(src);
  1815. struct status_data *tstatus = status_get_status_data(target);
  1816. struct status_change *sc = status_get_sc(src);
  1817. struct status_change *tsc = status_get_sc(target);
  1818. struct map_session_data *sd = BL_CAST(BL_PC, src);
  1819. int skill, nk;
  1820. short flee, hitrate;
  1821. if (!first_call)
  1822. return (wd.dmg_lv != ATK_FLEE);
  1823. nk = battle_skill_get_damage_properties(skill_id, wd.miscflag);
  1824. if (is_attack_critical(wd, src, target, skill_id, skill_lv, false))
  1825. return true;
  1826. else if(sd && sd->bonus.perfect_hit > 0 && rnd()%100 < sd->bonus.perfect_hit)
  1827. return true;
  1828. else if (sc && sc->data[SC_FUSION])
  1829. return true;
  1830. else if (skill_id == AS_SPLASHER && !wd.miscflag)
  1831. return true;
  1832. else if (skill_id == CR_SHIELDBOOMERANG && sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_CRUSADER )
  1833. return true;
  1834. else if (tsc && tsc->opt1 && tsc->opt1 != OPT1_STONEWAIT && tsc->opt1 != OPT1_BURNING)
  1835. return true;
  1836. else if (nk&NK_IGNORE_FLEE)
  1837. return true;
  1838. if( sc && (sc->data[SC_NEUTRALBARRIER] || sc->data[SC_NEUTRALBARRIER_MASTER]) && wd.flag&BF_LONG )
  1839. return false;
  1840. flee = tstatus->flee;
  1841. #ifdef RENEWAL
  1842. hitrate = 0; //Default hitrate
  1843. #else
  1844. hitrate = 80; //Default hitrate
  1845. #endif
  1846. if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) {
  1847. unsigned char attacker_count = unit_counttargeted(target); //256 max targets should be a sane max
  1848. if(attacker_count >= battle_config.agi_penalty_count) {
  1849. if (battle_config.agi_penalty_type == 1)
  1850. flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100;
  1851. else //asume type 2: absolute reduction
  1852. flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num;
  1853. if(flee < 1) flee = 1;
  1854. }
  1855. }
  1856. hitrate+= sstatus->hit - flee;
  1857. if(wd.flag&BF_LONG && !skill_id && //Fogwall's hit penalty is only for normal ranged attacks.
  1858. tsc && tsc->data[SC_FOGWALL])
  1859. hitrate -= 50;
  1860. if(sd && is_skill_using_arrow(src, skill_id))
  1861. hitrate += sd->bonus.arrow_hit;
  1862. #ifdef RENEWAL
  1863. if( sd ) //in Renewal hit bonus from Vultures Eye is not anymore shown in status window
  1864. hitrate += pc_checkskill(sd,AC_VULTURE);
  1865. #endif
  1866. if(skill_id)
  1867. switch(skill_id) { //Hit skill modifiers
  1868. //It is proven that bonus is applied on final hitrate, not hit.
  1869. case SM_BASH:
  1870. case MS_BASH:
  1871. hitrate += hitrate * 5 * skill_lv / 100;
  1872. break;
  1873. case MS_MAGNUM:
  1874. case SM_MAGNUM:
  1875. hitrate += hitrate * 10 * skill_lv / 100;
  1876. break;
  1877. case KN_AUTOCOUNTER:
  1878. case PA_SHIELDCHAIN:
  1879. case NPC_WATERATTACK:
  1880. case NPC_GROUNDATTACK:
  1881. case NPC_FIREATTACK:
  1882. case NPC_WINDATTACK:
  1883. case NPC_POISONATTACK:
  1884. case NPC_HOLYATTACK:
  1885. case NPC_DARKNESSATTACK:
  1886. case NPC_UNDEADATTACK:
  1887. case NPC_TELEKINESISATTACK:
  1888. case NPC_BLEEDING:
  1889. hitrate += hitrate * 20 / 100;
  1890. break;
  1891. case KN_PIERCE:
  1892. case ML_PIERCE:
  1893. hitrate += hitrate * 5 * skill_lv / 100;
  1894. break;
  1895. case AS_SONICBLOW:
  1896. if(sd && pc_checkskill(sd,AS_SONICACCEL)>0)
  1897. hitrate += hitrate * 50 / 100;
  1898. break;
  1899. case MC_CARTREVOLUTION:
  1900. case GN_CART_TORNADO:
  1901. case GN_CARTCANNON:
  1902. if( sd && pc_checkskill(sd, GN_REMODELING_CART) )
  1903. hitrate += pc_checkskill(sd, GN_REMODELING_CART) * 4;
  1904. break;
  1905. case LG_BANISHINGPOINT:
  1906. hitrate += 3 * skill_lv;
  1907. break;
  1908. case GC_VENOMPRESSURE:
  1909. hitrate += 10 + 4 * skill_lv;
  1910. break;
  1911. }
  1912. else if( sd && wd.type&0x08 && wd.div_ == 2 ) // +1 hit per level of Double Attack on a successful double attack (making sure other multi attack skills do not trigger this) [helvetica]
  1913. hitrate += pc_checkskill(sd,TF_DOUBLE);
  1914. if( sd ) {
  1915. // Weaponry Research hidden bonus
  1916. if ((skill = pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0)
  1917. hitrate += hitrate * ( 2 * skill ) / 100;
  1918. if( (sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DAGGER) &&
  1919. (skill = pc_checkskill(sd, GN_TRAINING_SWORD))>0 )
  1920. hitrate += 3 * skill;
  1921. }
  1922. hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate);
  1923. return (rnd()%100 < hitrate);
  1924. }
  1925. /*==========================================
  1926. * If attack ignores def..
  1927. *------------------------------------------
  1928. * Credits:
  1929. * Original coder Skoltex
  1930. * Initial refactoring by Baalberith
  1931. * Refined and optimized by helvetica
  1932. */
  1933. static bool attack_ignores_def(struct Damage wd, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, short weapon_position)
  1934. {
  1935. struct status_data *tstatus = status_get_status_data(target);
  1936. struct status_change *sc = status_get_sc(src);
  1937. struct map_session_data *sd = BL_CAST(BL_PC, src);
  1938. int nk = battle_skill_get_damage_properties(skill_id, wd.miscflag);
  1939. #ifndef RENEWAL
  1940. if (is_attack_critical(wd, src, target, skill_id, skill_lv, false))
  1941. return true;
  1942. else
  1943. #endif
  1944. if (sc && sc->data[SC_FUSION])
  1945. return true;
  1946. #ifdef RENEWAL
  1947. else if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS && skill_id != ASC_BREAKER) // Renewal: Soul Breaker no longer gains ignore DEF from weapon [helvetica]
  1948. #else
  1949. else if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS)
  1950. #endif
  1951. { //Ignore Defense?
  1952. if (sd && ((sd->right_weapon.ignore_def_ele & (1<<tstatus->def_ele)) ||
  1953. sd->right_weapon.ignore_def_race & (1<<tstatus->race) ||
  1954. sd->right_weapon.ignore_def_race & (is_boss(target)?1<<RC_BOSS:1<<RC_NONBOSS)))
  1955. if (weapon_position == EQI_HAND_R)
  1956. return true;
  1957. if (sd && ((sd->left_weapon.ignore_def_ele & (1<<tstatus->def_ele)) ||
  1958. sd->left_weapon.ignore_def_race & (1<<tstatus->race) ||
  1959. sd->left_weapon.ignore_def_race & (is_boss(target)?1<<RC_BOSS:1<<RC_NONBOSS)))
  1960. {
  1961. if(battle_config.left_cardfix_to_right && is_attack_right_handed(src, skill_id)) {//Move effect to right hand. [Skotlex]
  1962. if (weapon_position == EQI_HAND_R)
  1963. return true;
  1964. } else if (weapon_position == EQI_HAND_L)
  1965. return true;
  1966. }
  1967. }
  1968. return (nk&NK_IGNORE_DEF);
  1969. }
  1970. /*================================================
  1971. * Should skill attack consider VVS and masteries?
  1972. *------------------------------------------------
  1973. * Credits:
  1974. * Original coder Skoltex
  1975. * Initial refactoring by Baalberith
  1976. * Refined and optimized by helvetica
  1977. */
  1978. static bool battle_skill_stacks_masteries_vvs(uint16 skill_id)
  1979. {
  1980. if (
  1981. #ifndef RENEWAL
  1982. skill_id == PA_SHIELDCHAIN || skill_id == CR_SHIELDBOOMERANG ||
  1983. #endif
  1984. skill_id == LG_SHIELDPRESS || skill_id == LG_EARTHDRIVE)
  1985. return false;
  1986. return true;
  1987. }
  1988. #ifdef RENEWAL
  1989. /*========================================
  1990. * Calulate equipment ATK for renewal ATK
  1991. *----------------------------------------
  1992. * Credits:
  1993. * Original coder Skoltex
  1994. * Initial refactoring by Baalberith
  1995. * Refined and optimized by helvetica
  1996. */
  1997. static int battle_calc_equip_attack(struct block_list *src, int skill_id)
  1998. {
  1999. if(src != NULL) {
  2000. int eatk=0;
  2001. struct status_data *status = status_get_status_data(src);
  2002. struct status_change *sc = status_get_sc(src);
  2003. struct map_session_data *sd = BL_CAST(BL_PC, src);
  2004. if(sc){
  2005. if(sc->data[SC_CAMOUFLAGE] )
  2006. eatk += 30 * min(10,sc->data[SC_CAMOUFLAGE]->val3); //max +300atk
  2007. }
  2008. if(sd) eatk += is_skill_using_arrow(src, skill_id) ? sd->bonus.arrow_atk : 0; // add arrow atk if using an applicable skill
  2009. return eatk + status->eatk;
  2010. }
  2011. return 0; // shouldn't happen but just in case
  2012. }
  2013. #endif
  2014. /*========================================
  2015. * Returns the element type of attack
  2016. *----------------------------------------
  2017. * Credits:
  2018. * Original coder Skoltex
  2019. * Initial refactoring by Baalberith
  2020. * Refined and optimized by helvetica
  2021. */
  2022. static int battle_get_weapon_element(struct Damage wd, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, short weapon_position, bool calc_for_damage_only)
  2023. {
  2024. struct map_session_data *sd = BL_CAST(BL_PC, src);
  2025. struct status_change *sc = status_get_sc(src);
  2026. struct status_data *sstatus = status_get_status_data(src);
  2027. uint8 i;
  2028. int nk = battle_skill_get_damage_properties(skill_id, wd.miscflag);
  2029. int element = skill_get_ele(skill_id, skill_lv);
  2030. //Take weapon's element
  2031. if( !skill_id || element == -1 ) {
  2032. if (weapon_position == EQI_HAND_R)
  2033. element = sstatus->rhw.ele;
  2034. else
  2035. element = sstatus->lhw.ele;
  2036. if(is_skill_using_arrow(src, skill_id) && sd && sd->bonus.arrow_ele && weapon_position == EQI_HAND_R)
  2037. element = sd->bonus.arrow_ele;
  2038. if( battle_config.attack_attr_none&src->type )
  2039. element = ELE_NONE; //Weapon's element is "not elemental"
  2040. // on official endows override all other elements [helvetica]
  2041. if( sd ){ //Summoning 10 talisman will endow your weapon.
  2042. ARR_FIND(1, 6, i, sd->talisman[i] >= 10);
  2043. if( i < 5 )
  2044. element = i;
  2045. if(sc) { // check for endows
  2046. if(sc->data[SC_ENCHANTARMS])
  2047. element = sc->data[SC_ENCHANTARMS]->val2;
  2048. }
  2049. }
  2050. }
  2051. else if( element == -2 ) //Use enchantment's element
  2052. element = status_get_attack_sc_element(src,sc);
  2053. else if( element == -3 ) //Use random element
  2054. element = rnd()%ELE_MAX;
  2055. switch( skill_id ) {
  2056. case GS_GROUNDDRIFT:
  2057. element = wd.miscflag; //element comes in flag.
  2058. break;
  2059. case LK_SPIRALPIERCE:
  2060. if (!sd)
  2061. element = ELE_NEUTRAL; //forced neutral for monsters
  2062. break;
  2063. case KO_KAIHOU:
  2064. if( sd ){
  2065. ARR_FIND(1, 6, i, sd->talisman[i] > 0);
  2066. if( i < 5 )
  2067. element = i;
  2068. }
  2069. break;
  2070. }
  2071. if (!(nk & NK_NO_ELEFIX) && element != ELE_NONE)
  2072. if (src->type == BL_HOM)
  2073. element = ELE_NONE; //skill is "not elemental"
  2074. if (sc && sc->data[SC_GOLDENE_FERSE] && ((!skill_id && (rnd() % 100 < sc->data[SC_GOLDENE_FERSE]->val4)) || skill_id == MH_STAHL_HORN)) {
  2075. element = ELE_HOLY;
  2076. }
  2077. // calc_flag means the element should be calculated for damage only
  2078. if (calc_for_damage_only)
  2079. return element;
  2080. #ifdef RENEWAL
  2081. if (skill_id == CR_SHIELDBOOMERANG)
  2082. element = ELE_NEUTRAL;
  2083. #endif
  2084. return element;
  2085. }
  2086. /*========================================
  2087. * Do element damage modifier calculation
  2088. *----------------------------------------
  2089. * Credits:
  2090. * Original coder Skoltex
  2091. * Initial refactoring by Baalberith
  2092. * Refined and optimized by helvetica
  2093. */
  2094. static struct Damage battle_calc_element_damage(struct Damage wd, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv)
  2095. {
  2096. struct map_session_data *sd = BL_CAST(BL_PC, src);
  2097. struct status_change *sc = status_get_sc(src);
  2098. struct status_data *sstatus = status_get_status_data(src);
  2099. struct status_data *tstatus = status_get_status_data(target);
  2100. int left_element = battle_get_weapon_element(wd, src, target, skill_id, skill_lv, EQI_HAND_L, true);
  2101. int right_element = battle_get_weapon_element(wd, src, target, skill_id, skill_lv, EQI_HAND_R, true);
  2102. int nk = battle_skill_get_damage_properties(skill_id, wd.miscflag);
  2103. if( !(nk&NK_NO_ELEFIX) && right_element != ELE_NONE )
  2104. { //Elemental attribute fix
  2105. if( wd.damage > 0 )
  2106. {
  2107. wd.damage=battle_attr_fix(src, target, wd.damage, right_element, tstatus->def_ele, tstatus->ele_lv);
  2108. if( skill_id == MC_CARTREVOLUTION ) //Cart Revolution apply the element fix once more with neutral element
  2109. wd.damage = battle_attr_fix(src, target, wd.damage, ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
  2110. if( skill_id == GS_GROUNDDRIFT ) //Additional 50*lv Neutral damage.
  2111. wd.damage += battle_attr_fix(src, target, 50*skill_lv, ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
  2112. }
  2113. if( is_attack_left_handed(src, skill_id) && wd.damage2 > 0 )
  2114. wd.damage2 = battle_attr_fix(src, target, wd.damage2, left_element ,tstatus->def_ele, tstatus->ele_lv);
  2115. if( sc && sc->data[SC_WATK_ELEMENT] )
  2116. { // Descriptions indicate this means adding a percent of a normal attack in another element. [Skotlex]
  2117. int64 damage = battle_calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, (is_skill_using_arrow(src, skill_id)?2:0)) * sc->data[SC_WATK_ELEMENT]->val2 / 100;
  2118. wd.damage += battle_attr_fix(src, target, damage, sc->data[SC_WATK_ELEMENT]->val1, tstatus->def_ele, tstatus->ele_lv);
  2119. if( is_attack_left_handed(src, skill_id) )
  2120. {
  2121. damage = battle_calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, sd, (is_skill_using_arrow(src, skill_id)?2:0)) * sc->data[SC_WATK_ELEMENT]->val2 / 100;
  2122. wd.damage2 += battle_attr_fix(src, target, damage, sc->data[SC_WATK_ELEMENT]->val1, tstatus->def_ele, tstatus->ele_lv);
  2123. }
  2124. }
  2125. }
  2126. return wd;
  2127. }
  2128. #define ATK_RATE(damage, damage2, a ) {damage= damage*(a)/100 ; if(is_attack_left_handed(src, skill_id)) damage2= damage2*(a)/100; }
  2129. #define ATK_RATE2(damage, damage2, a , b ) { damage= damage*(a)/100 ; if(is_attack_left_handed(src, skill_id)) damage2= damage2*(b)/100; }
  2130. #define ATK_RATER(damage, a){ damage = (int64)damage*(a)/100;}
  2131. #define ATK_RATEL(damage2, a){ damage2 = (int64)damage2*(a)/100;}
  2132. //Adds dmg%. 100 = +100% (double) damage. 10 = +10% damage
  2133. #define ATK_ADDRATE(damage, damage2, a ) { damage+= damage*(a)/100 ; if(is_attack_left_handed(src, skill_id)) damage2+= damage2*(a)/100; }
  2134. #define ATK_ADDRATE2(damage, damage2, a , b ) { damage+= damage*(a)/100 ; if(is_attack_left_handed(src, skill_id)) damage2+= damage2*(b)/100; }
  2135. //Adds an absolute value to damage. 100 = +100 damage
  2136. #define ATK_ADD(damage, damage2, a ) { damage+= a; if (is_attack_left_handed(src, skill_id)) damage2+= a; }
  2137. #define ATK_ADD2(damage, damage2, a , b ) { damage+= a; if (is_attack_left_handed(src, skill_id)) damage2+= b; }
  2138. #ifdef RENEWAL
  2139. #define RE_ALLATK_ADD(wd, a ) {ATK_ADD(wd.statusAtk, wd.statusAtk2, a); ATK_ADD(wd.weaponAtk, wd.weaponAtk2, a); ATK_ADD(wd.equipAtk, wd.equipAtk2, a); ATK_ADD(wd.masteryAtk, wd.masteryAtk2, a); }
  2140. #define RE_ALLATK_RATE(wd, a ) {ATK_RATE(wd.statusAtk, wd.statusAtk2, a); ATK_RATE(wd.weaponAtk, wd.weaponAtk2, a); ATK_RATE(wd.equipAtk, wd.equipAtk2, a); ATK_RATE(wd.masteryAtk, wd.masteryAtk2, a); }
  2141. #define RE_ALLATK_ADDRATE(wd, a ) {ATK_ADDRATE(wd.statusAtk, wd.statusAtk2, a); ATK_ADDRATE(wd.weaponAtk, wd.weaponAtk2, a); ATK_ADDRATE(wd.equipAtk, wd.equipAtk2, a); ATK_ADDRATE(wd.masteryAtk, wd.masteryAtk2, a); }
  2142. #else
  2143. #define RE_ALLATK_ADD(wd, a ) {;}
  2144. #define RE_ALLATK_RATE(wd, a ) {;}
  2145. #define RE_ALLATK_ADDRATE(wd, a ) {;}
  2146. #endif
  2147. /*==================================
  2148. * Calculate weapon mastery damages
  2149. *----------------------------------
  2150. * Credits:
  2151. * Original coder Skoltex
  2152. * Initial refactoring by Baalberith
  2153. * Refined and optimized by helvetica
  2154. */
  2155. static struct Damage battle_calc_attack_masteries(struct Damage wd, struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv)
  2156. {
  2157. struct map_session_data *sd = BL_CAST(BL_PC, src);
  2158. struct status_change *sc = status_get_sc(src);
  2159. struct status_data *sstatus = status_get_status_data(src);
  2160. int t_class = status_get_class(target);
  2161. if (sd && battle_skill_stacks_masteries_vvs(skill_id) &&
  2162. skill_id != MO_INVESTIGATE &&
  2163. skill_id != MO_EXTREMITYFIST &&
  2164. skill_id != CR_GRANDCROSS)
  2165. { //Add mastery damage
  2166. int skill, skillratio;
  2167. uint8 i;
  2168. wd.damage = battle_addmastery(sd,target,wd.damage,0);
  2169. #ifdef RENEWAL
  2170. wd.masteryAtk = (int)battle_addmastery(sd,target,wd.weaponAtk,0);
  2171. #endif
  2172. if (is_attack_left_handed(src, skill_id)) {
  2173. wd.damage2 = battle_addmastery(sd,target,wd.damage2,1);
  2174. #ifdef RENEWAL
  2175. wd.masteryAtk2 = (int)battle_addmastery(sd,target,wd.weaponAtk2,1);
  2176. #endif
  2177. }
  2178. if (sc && sc->data[SC_MIRACLE])
  2179. i = 2; //Star anger
  2180. else
  2181. ARR_FIND(0, MAX_PC_FEELHATE, i, t_class == sd->hate_mob[i]);
  2182. if (i < MAX_PC_FEELHATE && (skill=pc_checkskill(sd,sg_info[i].anger_id))){
  2183. skillratio = sd->status.base_level + sstatus->dex + sstatus->luk;
  2184. if (i == 2) skillratio += sstatus->str; //Star Anger
  2185. if (skill<4)
  2186. skillratio /= 12-3*skill;
  2187. ATK_ADDRATE(wd.damage, wd.damage2, skillratio);
  2188. #ifdef RENEWAL
  2189. ATK_ADDRATE(wd.masteryAtk, wd.masteryAtk2, skillratio);
  2190. #endif
  2191. }
  2192. if (skill_id == NJ_SYURIKEN && (skill = pc_checkskill(sd,NJ_TOBIDOUGU)) > 0) {
  2193. ATK_ADD(wd.damage, wd.damage2, 3*skill);
  2194. #ifdef RENEWAL
  2195. ATK_ADD(wd.masteryAtk, wd.masteryAtk2, 3*skill);
  2196. #endif
  2197. }
  2198. }
  2199. return wd;
  2200. }
  2201. #ifdef RENEWAL
  2202. /*=========================================
  2203. * Calculate the various Renewal ATK parts
  2204. *-----------------------------------------
  2205. * Credits:
  2206. * Original coder Skoltex
  2207. * Initial refactoring by Baalberith
  2208. * Refined and optimized by helvetica
  2209. */
  2210. struct Damage battle_calc_damage_parts(struct Damage wd, struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv)
  2211. {
  2212. struct status_data *sstatus = status_get_status_data(src);
  2213. struct status_data *tstatus = status_get_status_data(target);
  2214. struct map_session_data *sd = BL_CAST(BL_PC, src);
  2215. int right_element = battle_get_weapon_element(wd, src, target, skill_id, skill_lv, EQI_HAND_R, false);
  2216. int left_element = battle_get_weapon_element(wd, src, target, skill_id, skill_lv, EQI_HAND_L, false);
  2217. wd.statusAtk += battle_calc_status_attack(sstatus, EQI_HAND_R);
  2218. wd.statusAtk2 += battle_calc_status_attack(sstatus, EQI_HAND_L);
  2219. if (!skill_id) { // status atk is considered neutral on normal attacks [helvetica]
  2220. if(sd && sd->sc.data[SC_SEVENWIND]) { // Mild Wind applies element to status ATK as well as weapon ATK [helvetica]
  2221. wd.statusAtk = (int)battle_attr_fix(src, target, wd.statusAtk, right_element, tstatus->def_ele, tstatus->ele_lv);
  2222. wd.statusAtk2 = (int)battle_attr_fix(src, target, wd.statusAtk, left_element, tstatus->def_ele, tstatus->ele_lv);
  2223. }
  2224. else {
  2225. wd.statusAtk = (int)battle_attr_fix(src, target, wd.statusAtk, ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
  2226. wd.statusAtk2 = (int)battle_attr_fix(src, target, wd.statusAtk, ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
  2227. }
  2228. }
  2229. else {
  2230. wd.statusAtk = (int)battle_attr_fix(src, target, wd.statusAtk, right_element, tstatus->def_ele, tstatus->ele_lv);
  2231. wd.statusAtk2 = (int)battle_attr_fix(src, target, wd.statusAtk, left_element, tstatus->def_ele, tstatus->ele_lv);
  2232. }
  2233. wd.weaponAtk += battle_calc_base_weapon_attack(src, tstatus, &sstatus->rhw, sd);
  2234. wd.weaponAtk = (int)battle_attr_fix(src, target, wd.weaponAtk, right_element, tstatus->def_ele, tstatus->ele_lv);
  2235. wd.weaponAtk2 += battle_calc_base_weapon_attack(src, tstatus, &sstatus->lhw, sd);
  2236. wd.weaponAtk2 = (int)battle_attr_fix(src, target, wd.weaponAtk2, left_element, tstatus->def_ele, tstatus->ele_lv);
  2237. wd.equipAtk += battle_calc_equip_attack(src, skill_id);
  2238. wd.equipAtk = (int)battle_attr_fix(src, target, wd.equipAtk, right_element, tstatus->def_ele, tstatus->ele_lv);
  2239. wd.equipAtk2 += battle_calc_equip_attack(src, skill_id);
  2240. wd.equipAtk2 = (int)battle_attr_fix(src, target, wd.equipAtk2, left_element, tstatus->def_ele, tstatus->ele_lv);
  2241. wd = battle_calc_attack_masteries(wd, src, target, skill_id, skill_lv);
  2242. wd.damage = 0;
  2243. wd.damage2 = 0;
  2244. return wd;
  2245. }
  2246. #endif
  2247. /*==========================================================
  2248. * Calculate basic ATK that goes into the skill ATK formula
  2249. *----------------------------------------------------------
  2250. * Credits:
  2251. * Original coder Skoltex
  2252. * Initial refactoring by Baalberith
  2253. * Refined and optimized by helvetica
  2254. */
  2255. struct Damage battle_calc_skill_base_damage(struct Damage wd, struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv)
  2256. {
  2257. struct status_change *sc = status_get_sc(src);
  2258. struct status_data *sstatus = status_get_status_data(src);
  2259. struct status_data *tstatus = status_get_status_data(target);
  2260. struct map_session_data *sd = BL_CAST(BL_PC, src);
  2261. int skill;
  2262. uint16 i;
  2263. int nk = battle_skill_get_damage_properties(skill_id, wd.miscflag);
  2264. switch (skill_id) { //Calc base damage according to skill
  2265. case PA_SACRIFICE:
  2266. wd.damage = (int64)sstatus->max_hp* 9/100;
  2267. wd.damage2 = 0;
  2268. #ifdef RENEWAL
  2269. wd.weaponAtk = (int)wd.damage;
  2270. wd.weaponAtk2 = (int)wd.damage2;
  2271. #endif
  2272. break;
  2273. #ifdef RENEWAL
  2274. case LK_SPIRALPIERCE:
  2275. case ML_SPIRALPIERCE:
  2276. if (sd) {
  2277. short index = sd->equip_index[EQI_HAND_R];
  2278. if (index >= 0 &&
  2279. sd->inventory_data[index] &&
  2280. sd->inventory_data[index]->type == IT_WEAPON)
  2281. wd.equipAtk += sd->inventory_data[index]->weight/20; // weight from spear is treated as equipment ATK on official [helvetica]
  2282. wd = battle_calc_damage_parts(wd, src, target, skill_id, skill_lv);
  2283. wd.masteryAtk = 0; // weapon mastery is ignored for spiral
  2284. } else {
  2285. wd.damage = battle_calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, 0); //Monsters have no weight and use ATK instead
  2286. }
  2287. switch (tstatus->size) { //Size-fix. Is this modified by weapon perfection?
  2288. case SZ_SMALL: //Small: 125%
  2289. ATK_RATE(wd.damage, wd.damage2, 125);
  2290. RE_ALLATK_RATE(wd, 125);
  2291. break;
  2292. //case SZ_MEDIUM: //Medium: 100%
  2293. case SZ_BIG: //Large: 75%
  2294. ATK_RATE(wd.damage, wd.damage2, 75);
  2295. RE_ALLATK_RATE(wd, 75);
  2296. break;
  2297. }
  2298. #else
  2299. case NJ_ISSEN:
  2300. wd.damage = 40*sstatus->str +skill_lv*(sstatus->hp/10 + 35);
  2301. wd.damage2 = 0;
  2302. break;
  2303. case LK_SPIRALPIERCE:
  2304. case ML_SPIRALPIERCE:
  2305. if (sd) {
  2306. short index = sd->equip_index[EQI_HAND_R];
  2307. if (index >= 0 &&
  2308. sd->inventory_data[index] &&
  2309. sd->inventory_data[index]->type == IT_WEAPON)
  2310. wd.damage = sd->inventory_data[index]->weight*8/100; //80% of weight
  2311. ATK_ADDRATE(wd.damage, wd.damage2, 50*skill_lv); //Skill modifier applies to weight only.
  2312. } else {
  2313. wd.damage = battle_calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, 0); //Monsters have no weight and use ATK instead
  2314. }
  2315. i = sstatus->str/10;
  2316. i*=i;
  2317. ATK_ADD(wd.damage, wd.damage2, i); //Add str bonus.
  2318. switch (tstatus->size) { //Size-fix. Is this modified by weapon perfection?
  2319. case SZ_SMALL: //Small: 125%
  2320. ATK_RATE(wd.damage, wd.damage2, 125);
  2321. break;
  2322. //case SZ_MEDIUM: //Medium: 100%
  2323. case SZ_BIG: //Large: 75%
  2324. ATK_RATE(wd.damage, wd.damage2, 75);
  2325. break;
  2326. }
  2327. #endif
  2328. break;
  2329. case TF_POISON: // Additional 15*skill level damage
  2330. ATK_ADD(wd.damage, wd.damage2, 15*skill_lv);
  2331. #ifdef RENEWAL
  2332. wd.masteryAtk += 15*skill_lv; // ATK from Envenom is treated as mastery type damage [helvetica]
  2333. #endif
  2334. case CR_SHIELDBOOMERANG:
  2335. case PA_SHIELDCHAIN:
  2336. case LG_SHIELDPRESS:
  2337. case LG_EARTHDRIVE:
  2338. wd.damage = sstatus->batk;
  2339. if (sd) {
  2340. short index = sd->equip_index[EQI_HAND_L];
  2341. if (index >= 0 &&
  2342. sd->inventory_data[index] &&
  2343. sd->inventory_data[index]->type == IT_ARMOR)
  2344. ATK_ADD(wd.damage, wd.damage2, sd->inventory_data[index]->weight/10);
  2345. } else
  2346. ATK_ADD(wd.damage, wd.damage2, sstatus->rhw.atk2); //Else use Atk2
  2347. #ifdef RENEWAL
  2348. wd.weaponAtk = (int)wd.damage;
  2349. wd.weaponAtk2 = (int)wd.damage2;
  2350. #endif
  2351. break;
  2352. case HFLI_SBR44: //[orn]
  2353. if(src->type == BL_HOM) {
  2354. wd.damage = ((TBL_HOM*)src)->homunculus.intimacy ;
  2355. }
  2356. break;
  2357. default:
  2358. {
  2359. #ifdef RENEWAL
  2360. if (sd)
  2361. wd = battle_calc_damage_parts(wd, src, target, skill_id, skill_lv);
  2362. else {
  2363. i = (is_attack_critical(wd, src, target, skill_id, skill_lv, false)?1:0)|
  2364. (!skill_id && sc && sc->data[SC_CHANGE]?4:0);
  2365. wd.damage = battle_calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, i);
  2366. if (is_attack_left_handed(src, skill_id))
  2367. wd.damage2 = battle_calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, sd, i);
  2368. }
  2369. #else
  2370. i = (is_attack_critical(wd, src, target, skill_id, skill_lv, false)?1:0)|
  2371. (is_skill_using_arrow(src, skill_id)?2:0)|
  2372. (skill_id == HW_MAGICCRASHER?4:0)|
  2373. (!skill_id && sc && sc->data[SC_CHANGE]?4:0)|
  2374. (skill_id == MO_EXTREMITYFIST?8:0)|
  2375. (sc && sc->data[SC_WEAPONPERFECTION]?8:0);
  2376. if (is_skill_using_arrow(src, skill_id) && sd)
  2377. switch(sd->status.weapon) {
  2378. case W_BOW:
  2379. case W_REVOLVER:
  2380. case W_GATLING:
  2381. case W_SHOTGUN:
  2382. case W_GRENADE:
  2383. break;
  2384. default:
  2385. i |= 16; // for ex. shuriken must not be influenced by DEX
  2386. }
  2387. wd.damage = battle_calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, i);
  2388. if (is_attack_left_handed(src, skill_id))
  2389. wd.damage2 = battle_calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, sd, i);
  2390. #endif
  2391. if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets
  2392. if(wd.miscflag > 0) {
  2393. wd.damage /= wd.miscflag;
  2394. #ifdef RENEWAL
  2395. wd.statusAtk /= wd.miscflag;
  2396. wd.weaponAtk /= wd.miscflag;
  2397. wd.equipAtk /= wd.miscflag;
  2398. wd.masteryAtk /= wd.miscflag;
  2399. #endif
  2400. }
  2401. else
  2402. ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_id, skill_get_name(skill_id));
  2403. }
  2404. //Add any bonuses that modify the base atk (pre-skills)
  2405. if(sd) {
  2406. if (sd->bonus.atk_rate) {
  2407. ATK_ADDRATE(wd.damage, wd.damage2, sd->bonus.atk_rate);
  2408. RE_ALLATK_ADDRATE(wd, sd->bonus.atk_rate);
  2409. }
  2410. #ifndef RENEWAL
  2411. if(is_attack_critical(wd, src, target, skill_id, skill_lv, false) && sd->bonus.crit_atk_rate) { // add +crit damage bonuses here in pre-renewal mode [helvetica]
  2412. ATK_ADDRATE(wd.damage, wd.damage2, sd->bonus.crit_atk_rate);
  2413. }
  2414. #endif
  2415. if(sd->status.party_id && (skill=pc_checkskill(sd,TK_POWER)) > 0) {
  2416. if( (i = party_foreachsamemap(party_sub_count, sd, 0)) > 1 ) { // exclude the player himself [Inkfish]
  2417. ATK_ADDRATE(wd.damage, wd.damage2, 2*skill*i);
  2418. RE_ALLATK_ADDRATE(wd, 2*skill*i);
  2419. }
  2420. }
  2421. }
  2422. break;
  2423. } //End default case
  2424. } //End switch(skill_id)
  2425. return wd;
  2426. }
  2427. //For quick div adjustment.
  2428. #define damage_div_fix(dmg, div) { if (div > 1) (dmg)*=div; else if (div < 0) (div)*=-1; }
  2429. #define damage_div_fix2(dmg, div) { if (div > 1) (dmg)*=div; }
  2430. #define damage_div_fix_renewal(wd, div) { damage_div_fix2(wd.statusAtk, div); damage_div_fix2(wd.weaponAtk, div); damage_div_fix2(wd.equipAtk, div); damage_div_fix2(wd.masteryAtk, div); }
  2431. /*=======================================
  2432. * Check for and calculate multi attacks
  2433. *---------------------------------------
  2434. * Credits:
  2435. * Original coder Skoltex
  2436. * Initial refactoring by Baalberith
  2437. * Refined and optimized by helvetica
  2438. */
  2439. static struct Damage battle_calc_multi_attack(struct Damage wd, struct block_list *src,struct block_list *target, uint16 skill_id, uint16 skill_lv)
  2440. {
  2441. struct map_session_data *sd = BL_CAST(BL_PC, src);
  2442. struct status_change *sc = status_get_sc(src);
  2443. struct status_change *tsc = status_get_sc(target);
  2444. struct status_data *tstatus = status_get_status_data(target);
  2445. short i;
  2446. if( sd && !skill_id ) { // if no skill_id passed, check for double attack [helvetica]
  2447. if( ( ( skill_lv = pc_checkskill(sd,TF_DOUBLE) ) > 0 && sd->weapontype1 == W_DAGGER )
  2448. || ( sd->bonus.double_rate > 0 && sd->weapontype1 != W_FIST ) //Will fail bare-handed
  2449. || ( sc && sc->data[SC_KAGEMUSYA] && sd->weapontype1 != W_FIST )) // Need confirmation
  2450. { //Success chance is not added, the higher one is used [Skotlex]
  2451. if( rnd()%100 < ( 5*skill_lv > sd->bonus.double_rate ? 5*skill_lv : sc && sc->data[SC_KAGEMUSYA]?sc->data[SC_KAGEMUSYA]->val1*3:sd->bonus.double_rate ) ) {
  2452. wd.div_ = skill_get_num(TF_DOUBLE,skill_lv?skill_lv:1);
  2453. wd.type = 0x08;
  2454. }
  2455. }
  2456. else if( sd->weapontype1 == W_REVOLVER && (skill_lv = pc_checkskill(sd,GS_CHAINACTION)) > 0 && rnd()%100 < 5*skill_lv )
  2457. {
  2458. wd.div_ = skill_get_num(GS_CHAINACTION,skill_lv);
  2459. wd.type = 0x08;
  2460. }
  2461. else if(sc && sc->data[SC_FEARBREEZE] && sd->weapontype1==W_BOW
  2462. && (i = sd->equip_index[EQI_AMMO]) >= 0 && sd->inventory_data[i] && sd->status.inventory[i].amount > 1)
  2463. {
  2464. int chance = rnd()%100;
  2465. wd.type = 0x08;
  2466. switch(sc->data[SC_FEARBREEZE]->val1) {
  2467. case 5: if( chance < 4) { wd.div_ = 5; break; } // 3 % chance to attack 5 times.
  2468. case 4: if( chance < 7) { wd.div_ = 4; break; } // 6 % chance to attack 4 times.
  2469. case 3: if( chance < 10) { wd.div_ = 3; break; } // 9 % chance to attack 3 times.
  2470. case 2:
  2471. case 1: if( chance < 13) { wd.div_ = 2; break; } // 12 % chance to attack 2 times.
  2472. }
  2473. wd.div_ = min(wd.div_,sd->status.inventory[i].amount);
  2474. sc->data[SC_FEARBREEZE]->val4 = wd.div_-1;
  2475. }
  2476. }
  2477. switch (skill_id) {
  2478. case RA_AIMEDBOLT:
  2479. if( tsc && (tsc->data[SC_BITE] || tsc->data[SC_ANKLE] || tsc->data[SC_ELECTRICSHOCKER]) )
  2480. wd.div_ = tstatus->size + 2 + ( (rnd()%100 < 50-tstatus->size*10) ? 1 : 0 );
  2481. break;
  2482. case SC_JYUMONJIKIRI:
  2483. if( tsc && tsc->data[SC_JYUMONJIKIRI] )
  2484. wd.div_ = wd.div_ * -1;// needs more info
  2485. break;
  2486. }
  2487. return wd;
  2488. }
  2489. /*======================================================
  2490. * Calculate skill level ratios for weapon-based skills
  2491. *------------------------------------------------------
  2492. * Credits:
  2493. * Original coder Skoltex
  2494. * Initial refactoring by Baalberith
  2495. * Refined and optimized by helvetica
  2496. */
  2497. static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv)
  2498. {
  2499. struct map_session_data *sd = BL_CAST(BL_PC, src);
  2500. struct map_session_data *tsd = BL_CAST(BL_PC, src);
  2501. struct status_change *sc = status_get_sc(src);
  2502. struct status_change *tsc = status_get_sc(target);
  2503. struct status_data *sstatus = status_get_status_data(src);
  2504. struct status_data *tstatus = status_get_status_data(target);
  2505. int skillratio = 100;
  2506. int i;
  2507. //Skill damage modifiers that stack linearly
  2508. if(sc && skill_id != PA_SACRIFICE) {
  2509. if(sc->data[SC_OVERTHRUST])
  2510. skillratio += sc->data[SC_OVERTHRUST]->val3;
  2511. if(sc->data[SC_MAXOVERTHRUST])
  2512. skillratio += sc->data[SC_MAXOVERTHRUST]->val2;
  2513. if (sc->data[SC_BERSERK] || sc->data[SC_SATURDAYNIGHTFEVER])
  2514. skillratio += 100;
  2515. if(sc->data[SC_ZENKAI] && sstatus->rhw.ele == sc->data[SC_ZENKAI]->val2 )
  2516. skillratio += sc->data[SC_ZENKAI]->val1 * 2;
  2517. #ifdef RENEWAL
  2518. if( sc && sc->data[SC_TRUESIGHT] )
  2519. skillratio += 2*sc->data[SC_TRUESIGHT]->val1;
  2520. #endif
  2521. }
  2522. switch( skill_id ) {
  2523. case SM_BASH:
  2524. case MS_BASH:
  2525. skillratio += 30*skill_lv;
  2526. break;
  2527. case SM_MAGNUM:
  2528. case MS_MAGNUM:
  2529. skillratio += 20*skill_lv;
  2530. break;
  2531. case MC_MAMMONITE:
  2532. skillratio += 50*skill_lv;
  2533. break;
  2534. case HT_POWER:
  2535. skillratio += -50+8*sstatus->str;
  2536. break;
  2537. case AC_DOUBLE:
  2538. case MA_DOUBLE:
  2539. skillratio += 10*(skill_lv-1);
  2540. break;
  2541. case AC_SHOWER:
  2542. case MA_SHOWER:
  2543. #ifdef RENEWAL
  2544. skillratio += 50+10*skill_lv;
  2545. #else
  2546. skillratio += -25+5*skill_lv;
  2547. #endif
  2548. break;
  2549. case AC_CHARGEARROW:
  2550. case MA_CHARGEARROW:
  2551. skillratio += 50;
  2552. break;
  2553. #ifndef RENEWAL
  2554. case HT_FREEZINGTRAP:
  2555. case MA_FREEZINGTRAP:
  2556. skillratio += -50+10*skill_lv;
  2557. break;
  2558. #endif
  2559. case KN_PIERCE:
  2560. case ML_PIERCE:
  2561. skillratio += 10*skill_lv;
  2562. break;
  2563. case MER_CRASH:
  2564. skillratio += 10*skill_lv;
  2565. break;
  2566. case KN_SPEARSTAB:
  2567. skillratio += 15*skill_lv;
  2568. break;
  2569. case KN_SPEARBOOMERANG:
  2570. skillratio += 50*skill_lv;
  2571. break;
  2572. case KN_BRANDISHSPEAR:
  2573. case ML_BRANDISH:
  2574. {
  2575. int ratio = 100+20*skill_lv;
  2576. skillratio += ratio-100;
  2577. if(skill_lv>3 && wd.miscflag==1) skillratio += ratio/2;
  2578. if(skill_lv>6 && wd.miscflag==1) skillratio += ratio/4;
  2579. if(skill_lv>9 && wd.miscflag==1) skillratio += ratio/8;
  2580. if(skill_lv>6 && wd.miscflag==2) skillratio += ratio/2;
  2581. if(skill_lv>9 && wd.miscflag==2) skillratio += ratio/4;
  2582. if(skill_lv>9 && wd.miscflag==3) skillratio += ratio/2;
  2583. break;
  2584. }
  2585. case KN_BOWLINGBASH:
  2586. case MS_BOWLINGBASH:
  2587. skillratio+= 40*skill_lv;
  2588. break;
  2589. case AS_GRIMTOOTH:
  2590. skillratio += 20*skill_lv;
  2591. break;
  2592. case AS_POISONREACT:
  2593. skillratio += 30*skill_lv;
  2594. break;
  2595. case AS_SONICBLOW:
  2596. skillratio += -50+5*skill_lv;
  2597. break;
  2598. case TF_SPRINKLESAND:
  2599. skillratio += 30;
  2600. break;
  2601. case MC_CARTREVOLUTION:
  2602. skillratio += 50;
  2603. if(sd && sd->cart_weight)
  2604. skillratio += 100*sd->cart_weight/sd->cart_weight_max; // +1% every 1% weight
  2605. else if (!sd)
  2606. skillratio += 100; //Max damage for non players.
  2607. break;
  2608. case NPC_PIERCINGATT:
  2609. skillratio += -25; //75% base damage
  2610. break;
  2611. case NPC_COMBOATTACK:
  2612. skillratio += 25*skill_lv;
  2613. break;
  2614. case NPC_RANDOMATTACK:
  2615. case NPC_WATERATTACK:
  2616. case NPC_GROUNDATTACK:
  2617. case NPC_FIREATTACK:
  2618. case NPC_WINDATTACK:
  2619. case NPC_POISONATTACK:
  2620. case NPC_HOLYATTACK:
  2621. case NPC_DARKNESSATTACK:
  2622. case NPC_UNDEADATTACK:
  2623. case NPC_TELEKINESISATTACK:
  2624. case NPC_BLOODDRAIN:
  2625. case NPC_ACIDBREATH:
  2626. case NPC_DARKNESSBREATH:
  2627. case NPC_FIREBREATH:
  2628. case NPC_ICEBREATH:
  2629. case NPC_THUNDERBREATH:
  2630. case NPC_HELLJUDGEMENT:
  2631. case NPC_PULSESTRIKE:
  2632. skillratio += 100*(skill_lv-1);
  2633. break;
  2634. case RG_BACKSTAP:
  2635. if(sd && sd->status.weapon == W_BOW && battle_config.backstab_bow_penalty)
  2636. skillratio += (200+40*skill_lv)/2;
  2637. else
  2638. skillratio += 200+40*skill_lv;
  2639. break;
  2640. case RG_RAID:
  2641. skillratio += 40*skill_lv;
  2642. break;
  2643. case RG_INTIMIDATE:
  2644. skillratio += 30*skill_lv;
  2645. break;
  2646. case CR_SHIELDCHARGE:
  2647. skillratio += 20*skill_lv;
  2648. break;
  2649. case CR_SHIELDBOOMERANG:
  2650. skillratio += 30*skill_lv;
  2651. break;
  2652. case NPC_DARKCROSS:
  2653. case CR_HOLYCROSS:
  2654. {
  2655. #ifdef RENEWAL
  2656. if(sd && sd->status.weapon == W_2HSPEAR)
  2657. skillratio += 2*(35*skill_lv);
  2658. else
  2659. #endif
  2660. skillratio += 35*skill_lv;
  2661. break;
  2662. }
  2663. case AM_DEMONSTRATION:
  2664. skillratio += 20*skill_lv;
  2665. break;
  2666. case AM_ACIDTERROR:
  2667. skillratio += 40*skill_lv;
  2668. break;
  2669. case MO_FINGEROFFENSIVE:
  2670. skillratio+= 50 * skill_lv;
  2671. break;
  2672. case MO_INVESTIGATE:
  2673. skillratio += 75*skill_lv;
  2674. break;
  2675. case MO_EXTREMITYFIST:
  2676. skillratio += 100*(7 + sstatus->sp/10);
  2677. skillratio = min(500000,skillratio); //We stop at roughly 50k SP for overflow protection
  2678. break;
  2679. case MO_TRIPLEATTACK:
  2680. skillratio += 20*skill_lv;
  2681. break;
  2682. case MO_CHAINCOMBO:
  2683. skillratio += 50+50*skill_lv;
  2684. break;
  2685. case MO_COMBOFINISH:
  2686. skillratio += 140+60*skill_lv;
  2687. break;
  2688. case BA_MUSICALSTRIKE:
  2689. case DC_THROWARROW:
  2690. skillratio += 25+25*skill_lv;
  2691. break;
  2692. case CH_TIGERFIST:
  2693. skillratio += 100*skill_lv-60;
  2694. break;
  2695. case CH_CHAINCRUSH:
  2696. skillratio += 300+100*skill_lv;
  2697. break;
  2698. case CH_PALMSTRIKE:
  2699. skillratio += 100+100*skill_lv;
  2700. break;
  2701. case LK_HEADCRUSH:
  2702. skillratio += 40*skill_lv;
  2703. break;
  2704. case LK_JOINTBEAT:
  2705. i = 10*skill_lv-50;
  2706. // Although not clear, it's being assumed that the 2x damage is only for the break neck ailment.
  2707. if (wd.miscflag&BREAK_NECK) i*=2;
  2708. skillratio += i;
  2709. break;
  2710. #ifdef RENEWAL
  2711. // Renewal: skill ratio applies to entire damage [helvetica]
  2712. case LK_SPIRALPIERCE:
  2713. case ML_SPIRALPIERCE:
  2714. skillratio += 50*skill_lv;
  2715. break;
  2716. #endif
  2717. case ASC_METEORASSAULT:
  2718. skillratio += 40*skill_lv-60;
  2719. break;
  2720. case SN_SHARPSHOOTING:
  2721. case MA_SHARPSHOOTING:
  2722. skillratio += 100+50*skill_lv;
  2723. break;
  2724. case CG_ARROWVULCAN:
  2725. skillratio += 100+100*skill_lv;
  2726. break;
  2727. case AS_SPLASHER:
  2728. skillratio += 400+50*skill_lv;
  2729. if(sd)
  2730. skillratio += 20 * pc_checkskill(sd,AS_POISONREACT);
  2731. break;
  2732. #ifndef RENEWAL
  2733. // Pre-Renewal: skill ratio for weapon part of damage [helvetica]
  2734. case ASC_BREAKER:
  2735. skillratio += 100*skill_lv-100;
  2736. break;
  2737. #endif
  2738. case PA_SACRIFICE:
  2739. skillratio += 10*skill_lv-10;
  2740. break;
  2741. case PA_SHIELDCHAIN:
  2742. skillratio += 30*skill_lv;
  2743. break;
  2744. case WS_CARTTERMINATION:
  2745. i = 10 * (16 - skill_lv);
  2746. if (i < 1) i = 1;
  2747. //Preserve damage ratio when max cart weight is changed.
  2748. if(sd && sd->cart_weight)
  2749. skillratio += sd->cart_weight/i * 80000/battle_config.max_cart_weight - 100;
  2750. else if (!sd)
  2751. skillratio += 80000 / i - 100;
  2752. break;
  2753. case TK_DOWNKICK:
  2754. skillratio += 60 + 20*skill_lv;
  2755. break;
  2756. case TK_STORMKICK:
  2757. skillratio += 60 + 20*skill_lv;
  2758. break;
  2759. case TK_TURNKICK:
  2760. skillratio += 90 + 30*skill_lv;
  2761. break;
  2762. case TK_COUNTER:
  2763. skillratio += 90 + 30*skill_lv;
  2764. break;
  2765. case TK_JUMPKICK:
  2766. skillratio += -70 + 10*skill_lv;
  2767. if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_id)
  2768. skillratio += 10*status_get_lv(src)/3; //Tumble bonus
  2769. if (wd.miscflag)
  2770. {
  2771. skillratio += 10*status_get_lv(src)/3; //Running bonus (TODO: What is the real bonus?)
  2772. if( sc && sc->data[SC_SPURT] ) // Spurt bonus
  2773. skillratio *= 2;
  2774. }
  2775. break;
  2776. case GS_TRIPLEACTION:
  2777. skillratio += 50*skill_lv;
  2778. break;
  2779. case GS_BULLSEYE:
  2780. //Only works well against brute/demihumans non bosses.
  2781. if((tstatus->race == RC_BRUTE || tstatus->race == RC_DEMIHUMAN)
  2782. && !(tstatus->mode&MD_BOSS))
  2783. skillratio += 400;
  2784. break;
  2785. case GS_TRACKING:
  2786. skillratio += 100 *(skill_lv+1);
  2787. break;
  2788. case GS_PIERCINGSHOT:
  2789. skillratio += 20*skill_lv;
  2790. break;
  2791. case GS_RAPIDSHOWER:
  2792. skillratio += 10*skill_lv;
  2793. break;
  2794. case GS_DESPERADO:
  2795. skillratio += 50*(skill_lv-1);
  2796. break;
  2797. case GS_DUST:
  2798. skillratio += 50*skill_lv;
  2799. break;
  2800. case GS_FULLBUSTER:
  2801. skillratio += 100*(skill_lv+2);
  2802. break;
  2803. case GS_SPREADATTACK:
  2804. #ifdef RENEWAL
  2805. skillratio += 20*(skill_lv);
  2806. #else
  2807. skillratio += 20*(skill_lv-1);
  2808. #endif
  2809. break;
  2810. case NJ_HUUMA:
  2811. skillratio += 50 + 150*skill_lv;
  2812. break;
  2813. case NJ_TATAMIGAESHI:
  2814. #ifdef RENEWAL
  2815. skillratio += 200;
  2816. #endif
  2817. skillratio += 10*skill_lv;
  2818. break;
  2819. case NJ_KASUMIKIRI:
  2820. skillratio += 10*skill_lv;
  2821. break;
  2822. case NJ_KIRIKAGE:
  2823. skillratio += 100*(skill_lv-1);
  2824. break;
  2825. case KN_CHARGEATK:
  2826. {
  2827. int k = (wd.miscflag-1)/3; //+100% every 3 cells of distance
  2828. if( k > 2 ) k = 2; // ...but hard-limited to 300%.
  2829. skillratio += 100 * k;
  2830. }
  2831. break;
  2832. case HT_PHANTASMIC:
  2833. skillratio += 50;
  2834. break;
  2835. case MO_BALKYOUNG:
  2836. skillratio += 200;
  2837. break;
  2838. case HFLI_MOON: //[orn]
  2839. skillratio += 10+110*skill_lv;
  2840. break;
  2841. case HFLI_SBR44: //[orn]
  2842. skillratio += 100 *(skill_lv-1);
  2843. break;
  2844. case NPC_VAMPIRE_GIFT:
  2845. skillratio += ((skill_lv-1)%5+1)*100;
  2846. break;
  2847. case RK_SONICWAVE:
  2848. skillratio = (skill_lv + 5) * 100; // ATK = {((Skill Level + 5) x 100) x (1 + [(Caster's Base Level - 100) / 200])} %
  2849. skillratio = skillratio * (100 + (status_get_lv(src) - 100) / 2) / 100;
  2850. break;
  2851. case RK_HUNDREDSPEAR:
  2852. skillratio += 500 + (80 * skill_lv);
  2853. if( sd ) {
  2854. short index = sd->equip_index[EQI_HAND_R];
  2855. if( index >= 0 && sd->inventory_data[index]
  2856. && sd->inventory_data[index]->type == IT_WEAPON )
  2857. skillratio += max(10000 - sd->inventory_data[index]->weight, 0) / 10;
  2858. skillratio += 50 * pc_checkskill(sd,LK_SPIRALPIERCE);
  2859. } // (1 + [(Casters Base Level - 100) / 200])
  2860. skillratio = skillratio * (100 + (status_get_lv(src) - 100) / 2) / 100;
  2861. break;
  2862. case RK_WINDCUTTER:
  2863. skillratio = (skill_lv + 2) * 50;
  2864. RE_LVL_DMOD(100);
  2865. break;
  2866. case RK_IGNITIONBREAK:
  2867. {
  2868. // 3x3 cell Damage = ATK [{(Skill Level x 300) x (1 + [(Caster's Base Level - 100) / 100])}] %
  2869. // 7x7 cell Damage = ATK [{(Skill Level x 250) x (1 + [(Caster's Base Level - 100) / 100])}] %
  2870. // 11x11 cell Damage = ATK [{(Skill Level x 200) x (1 + [(Caster's Base Level - 100) / 100])}] %
  2871. int dmg = 300; // Base maximum damage at less than 3 cells.
  2872. i = distance_bl(src,target);
  2873. if( i > 7 )
  2874. dmg -= 100; // Greather than 7 cells. (200 damage)
  2875. else if( i > 3 )
  2876. dmg -= 50; // Greater than 3 cells, less than 7. (250 damage)
  2877. dmg = (dmg * skill_lv) * (100 + (status_get_lv(src) - 100) / 12) / 100;
  2878. // Elemental check, 1.5x damage if your element is fire.
  2879. if( sstatus->rhw.ele == ELE_FIRE )
  2880. dmg += dmg/2;
  2881. skillratio = dmg;
  2882. }
  2883. break;
  2884. case RK_CRUSHSTRIKE:
  2885. if( sd ) { //ATK [{Weapon Level * (Weapon Upgrade Level + 6) * 100} + (Weapon ATK) + (Weapon Weight)]%
  2886. short index = sd->equip_index[EQI_HAND_R];
  2887. if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON )
  2888. skillratio = sd->inventory_data[index]->weight/10 + sstatus->rhw.atk +
  2889. 100 * sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6);
  2890. }
  2891. break;
  2892. case RK_STORMBLAST:
  2893. skillratio = ((sd ? pc_checkskill(sd,RK_RUNEMASTERY) : 1) + (sstatus->int_ / 8)) * 100; // ATK = [{Rune Mastery Skill Level + (Caster's INT / 8)} x 100] %
  2894. break;
  2895. case RK_PHANTOMTHRUST: // ATK = [{(Skill Level x 50) + (Spear Master Level x 10)} x Caster's Base Level / 150] %
  2896. skillratio = 50 * skill_lv + 10 * (sd ? pc_checkskill(sd,KN_SPEARMASTERY) : 5);
  2897. RE_LVL_DMOD(150); // Base level bonus.
  2898. break;
  2899. /**
  2900. * GC Guilotine Cross
  2901. **/
  2902. case GC_CROSSIMPACT:
  2903. skillratio += 900 + 100 * skill_lv;
  2904. RE_LVL_DMOD(120);
  2905. break;
  2906. case GC_PHANTOMMENACE:
  2907. skillratio += 200;
  2908. break;
  2909. case GC_COUNTERSLASH:
  2910. //ATK [{(Skill Level x 100) + 300} x Caster's Base Level / 120]% + ATK [(AGI x 2) + (Caster's Job Level x 4)]%
  2911. skillratio += 200 + (100 * skill_lv);
  2912. RE_LVL_DMOD(120);
  2913. skillratio += sstatus->agi + (sd?sd->status.job_level:0) * 4;
  2914. break;
  2915. case GC_ROLLINGCUTTER:
  2916. skillratio += -50 + 50 * skill_lv;
  2917. RE_LVL_DMOD(100);
  2918. break;
  2919. case GC_CROSSRIPPERSLASHER:
  2920. skillratio += 300 + 80 * skill_lv;
  2921. RE_LVL_DMOD(100);
  2922. if( sc && sc->data[SC_ROLLINGCUTTER] )
  2923. skillratio += sc->data[SC_ROLLINGCUTTER]->val1 * sstatus->agi;
  2924. break;
  2925. /**
  2926. * Arch Bishop
  2927. **/
  2928. case AB_DUPLELIGHT_MELEE:
  2929. skillratio += 10 * skill_lv;
  2930. break;
  2931. /**
  2932. * Ranger
  2933. **/
  2934. case RA_ARROWSTORM:
  2935. skillratio += 900 + 80 * skill_lv;
  2936. RE_LVL_DMOD(100);
  2937. break;
  2938. case RA_AIMEDBOLT:
  2939. skillratio += 400 + 50 * skill_lv;
  2940. RE_LVL_DMOD(100);
  2941. break;
  2942. case RA_CLUSTERBOMB:
  2943. skillratio += 100 + 100 * skill_lv;
  2944. break;
  2945. case RA_WUGDASH:// ATK 300%
  2946. skillratio += 200;
  2947. break;
  2948. case RA_WUGSTRIKE:
  2949. skillratio = 200 * skill_lv;
  2950. break;
  2951. case RA_WUGBITE:
  2952. skillratio += 300 + 200 * skill_lv;
  2953. if ( skill_lv == 5 ) skillratio += 100;
  2954. break;
  2955. case RA_SENSITIVEKEEN:
  2956. skillratio += 50 * skill_lv;
  2957. break;
  2958. /**
  2959. * Mechanic
  2960. **/
  2961. case NC_BOOSTKNUCKLE:
  2962. skillratio += 100 + 100 * skill_lv + sstatus->dex;
  2963. RE_LVL_DMOD(100);
  2964. break;
  2965. case NC_PILEBUNKER:
  2966. skillratio += 200 + 100 * skill_lv + sstatus->str;
  2967. RE_LVL_DMOD(100);
  2968. break;
  2969. case NC_VULCANARM:
  2970. skillratio = 70 * skill_lv + sstatus->dex;
  2971. RE_LVL_DMOD(100);
  2972. break;
  2973. case NC_FLAMELAUNCHER:
  2974. case NC_COLDSLOWER:
  2975. skillratio += 200 + 300 * skill_lv;
  2976. RE_LVL_DMOD(100);
  2977. break;
  2978. case NC_ARMSCANNON:
  2979. switch( tstatus->size ) {
  2980. case SZ_SMALL: skillratio += 100 + 500 * skill_lv; break;// Small
  2981. case SZ_MEDIUM: skillratio += 100 + 400 * skill_lv; break;// Medium
  2982. case SZ_BIG: skillratio += 100 + 300 * skill_lv; break;// Large
  2983. }
  2984. RE_LVL_DMOD(100);
  2985. //NOTE: Their's some other factors that affects damage, but not sure how exactly. Will recheck one day. [Rytech]
  2986. break;
  2987. case NC_AXEBOOMERANG:
  2988. skillratio += (skill_lv * 50) + 150;
  2989. if( sd ) {
  2990. short index = sd->equip_index[EQI_HAND_R];
  2991. if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON )
  2992. skillratio += sd->inventory_data[index]->weight / 10;// Weight is divided by 10 since 10 weight in coding make 1 whole actural weight. [Rytech]
  2993. }
  2994. RE_LVL_DMOD(100);
  2995. break;
  2996. case NC_POWERSWING: // According to current sources, only the str + dex gets modified by level [Akinari]
  2997. skillratio = sstatus->str + sstatus->dex;
  2998. RE_LVL_DMOD(100);
  2999. skillratio += 200 + 100 * skill_lv;
  3000. break;
  3001. case NC_AXETORNADO:
  3002. skillratio += 100 + 100 * skill_lv + sstatus->vit;
  3003. RE_LVL_DMOD(100);
  3004. break;
  3005. case SC_FATALMENACE:
  3006. skillratio += 100 * skill_lv;
  3007. break;
  3008. case SC_TRIANGLESHOT:
  3009. skillratio += ((skill_lv - 1) * (sstatus->agi / 2)) + 200;
  3010. RE_LVL_DMOD(120);
  3011. break;
  3012. case SC_FEINTBOMB:
  3013. skillratio = (skill_lv + 1) * (sstatus->dex / 2) * (sd?(sd->status.job_level / 10):5);
  3014. RE_LVL_DMOD(120);
  3015. break;
  3016. case LG_CANNONSPEAR:// Stimated formula. Still need confirm it.
  3017. skillratio += -100 + (50 + sstatus->str) * skill_lv;
  3018. RE_LVL_DMOD(100);
  3019. break;
  3020. case LG_BANISHINGPOINT:
  3021. skillratio += -100 + ((50 * skill_lv) + (30 * ((sd)?pc_checkskill(sd,SM_BASH):1)));
  3022. RE_LVL_DMOD(100);
  3023. break;
  3024. case LG_SHIELDPRESS:
  3025. skillratio = 150 * skill_lv + sstatus->str;
  3026. if( sd ) {
  3027. short index = sd->equip_index[EQI_HAND_L];
  3028. if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR ) {
  3029. skillratio += sd->inventory_data[index]->weight / 10;
  3030. RE_LVL_DMOD(100);
  3031. skillratio += sstatus->vit * sd->status.inventory[index].refine;
  3032. }
  3033. } else {
  3034. RE_LVL_DMOD(100);
  3035. }
  3036. break;
  3037. case LG_PINPOINTATTACK:
  3038. skillratio = ((100 * skill_lv) + (10 * status_get_agi(src)) );
  3039. RE_LVL_DMOD(100);
  3040. break;
  3041. case LG_RAGEBURST:
  3042. if( sd && sd->spiritball_old )
  3043. skillratio += -100 + (sd->spiritball_old * 200);
  3044. else
  3045. skillratio += -100 + 15 * 200;
  3046. RE_LVL_DMOD(100);
  3047. break;
  3048. case LG_SHIELDSPELL:// [(Casters Base Level x 4) + (Shield DEF x 10) + (Casters VIT x 2)] %
  3049. if( sd ) {
  3050. struct item_data *shield_data = sd->inventory_data[sd->equip_index[EQI_HAND_L]];
  3051. skillratio = status_get_lv(src) * 4 + status_get_vit(src) * 2;
  3052. if( shield_data )
  3053. skillratio += shield_data->def * 10;
  3054. } else
  3055. skillratio += 2400; //2500%
  3056. break;
  3057. case LG_MOONSLASHER:
  3058. skillratio += -100 + (120 * skill_lv + ((sd) ? pc_checkskill(sd,LG_OVERBRAND) : 5) * 80);
  3059. RE_LVL_DMOD(100);
  3060. break;
  3061. case LG_OVERBRAND:
  3062. skillratio = 200 * skill_lv + (pc_checkskill(sd,CR_SPEARQUICKEN) * 50);
  3063. RE_LVL_DMOD(100);
  3064. break;
  3065. case LG_OVERBRAND_BRANDISH:
  3066. skillratio = 100 * skill_lv + (sstatus->str + sstatus->dex);
  3067. RE_LVL_DMOD(100);
  3068. break;
  3069. case LG_OVERBRAND_PLUSATK: // Only Piercing and Swing damage get RE_LVL_DMOD bonus damage
  3070. skillratio = (100 * skill_lv) + rnd()%90 + 10;
  3071. break;
  3072. case LG_RAYOFGENESIS:
  3073. skillratio = 300 + 300 * skill_lv;
  3074. RE_LVL_DMOD(100);
  3075. break;
  3076. case LG_EARTHDRIVE:
  3077. skillratio = (skillratio + 100) * skill_lv;
  3078. RE_LVL_DMOD(100);
  3079. break;
  3080. case LG_HESPERUSLIT:
  3081. skillratio += 120 * skill_lv - 100;
  3082. break;
  3083. case SR_DRAGONCOMBO:
  3084. skillratio += 40 * skill_lv;
  3085. RE_LVL_DMOD(100);
  3086. break;
  3087. case SR_SKYNETBLOW:
  3088. //ATK [{(Skill Level x 80) + (Caster AGI)} x Caster Base Level / 100] %
  3089. skillratio = 80 * skill_lv + sstatus->agi;
  3090. if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_DRAGONCOMBO )//ATK [{(Skill Level x 100) + (Caster AGI) + 150} x Caster Base Level / 100] %
  3091. skillratio = 100 * skill_lv + sstatus->agi + 150;
  3092. RE_LVL_DMOD(100);
  3093. break;
  3094. case SR_EARTHSHAKER:
  3095. if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || // [(Skill Level x 150) x (Caster Base Level / 100) + (Caster INT x 3)] %
  3096. tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED] || tsc->data[SC__INVISIBILITY]) ){
  3097. skillratio = 150 * skill_lv;
  3098. RE_LVL_DMOD(100);
  3099. skillratio += sstatus->int_ * 3;
  3100. }else{ //[(Skill Level x 50) x (Caster Base Level / 100) + (Caster INT x 2)] %
  3101. skillratio += 50 * (skill_lv-2);
  3102. RE_LVL_DMOD(100);
  3103. skillratio += sstatus->int_ * 2;
  3104. }
  3105. break;
  3106. case SR_FALLENEMPIRE:// ATK [(Skill Level x 150 + 100) x Caster Base Level / 150] %
  3107. skillratio += 150 *skill_lv;
  3108. RE_LVL_DMOD(150);
  3109. break;
  3110. case SR_TIGERCANNON:// ATK [((Caster consumed HP + SP) / 4) x Caster Base Level / 100] %
  3111. {
  3112. int hp = (int64)sstatus->max_hp * (10 + 2 * skill_lv) / 100,
  3113. sp = (int64)sstatus->max_sp * (6 + skill_lv) / 100;
  3114. skillratio = ((int64)hp+sp) / 4;
  3115. if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE ) // ATK [((Caster consumed HP + SP) / 2) x Caster Base Level / 100] %
  3116. skillratio = (int64)hp+sp / 2;
  3117. RE_LVL_DMOD(100);
  3118. }
  3119. break;
  3120. case SR_RAMPAGEBLASTER:
  3121. skillratio += 20 * skill_lv * (sd?sd->spiritball_old:5) - 100;
  3122. if( sc && sc->data[SC_EXPLOSIONSPIRITS] ){
  3123. skillratio += sc->data[SC_EXPLOSIONSPIRITS]->val1 * 20;
  3124. RE_LVL_DMOD(120);
  3125. }else
  3126. RE_LVL_DMOD(150);
  3127. break;
  3128. case SR_KNUCKLEARROW:
  3129. if( wd.miscflag&4 ){ // ATK [(Skill Level x 150) + (1000 x Target current weight / Maximum weight) + (Target Base Level x 5) x (Caster Base Level / 150)] %
  3130. skillratio = 150 * skill_lv + status_get_lv(target) * 5 * (status_get_lv(src) / 100) ;
  3131. if( tsd && tsd->weight )
  3132. skillratio += 100 * (tsd->weight / tsd->max_weight);
  3133. }else // ATK [(Skill Level x 100 + 500) x Caster Base Level / 100] %
  3134. skillratio += 400 + (100 * skill_lv);
  3135. RE_LVL_DMOD(100);
  3136. break;
  3137. case SR_WINDMILL: // ATK [(Caster Base Level + Caster DEX) x Caster Base Level / 100] %
  3138. skillratio = status_get_lv(src) + sstatus->dex;
  3139. RE_LVL_DMOD(100);
  3140. break;
  3141. case SR_GATEOFHELL:
  3142. if( sc && sc->data[SC_COMBO]
  3143. && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE )
  3144. skillratio += 800 * skill_lv -100;
  3145. else
  3146. skillratio += 500 * skill_lv -100;
  3147. RE_LVL_DMOD(100);
  3148. break;
  3149. case SR_GENTLETOUCH_QUIET:
  3150. skillratio += 100 * skill_lv - 100 + sstatus->dex;
  3151. RE_LVL_DMOD(100);
  3152. break;
  3153. case SR_HOWLINGOFLION:
  3154. skillratio += 300 * skill_lv - 100;
  3155. RE_LVL_DMOD(150);
  3156. break;
  3157. case SR_RIDEINLIGHTNING: // ATK [{(Skill Level x 200) + Additional Damage} x Caster Base Level / 100] %
  3158. if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND )
  3159. skillratio += skill_lv * 50;
  3160. skillratio += -100 + 200 * skill_lv;
  3161. RE_LVL_DMOD(100);
  3162. break;
  3163. case WM_REVERBERATION_MELEE:
  3164. // ATK [{(Skill Level x 100) + 300} x Caster Base Level / 100]
  3165. skillratio += 200 + 100 * pc_checkskill(sd, WM_REVERBERATION);
  3166. RE_LVL_DMOD(100);
  3167. break;
  3168. case WM_SEVERE_RAINSTORM_MELEE:
  3169. //ATK [{(Caster DEX + AGI) x (Skill Level / 5)} x Caster Base Level / 100] %
  3170. skillratio = (sstatus->dex + sstatus->agi) * (skill_lv * 2);
  3171. RE_LVL_DMOD(100);
  3172. skillratio /= 10;
  3173. break;
  3174. case WM_GREAT_ECHO:
  3175. skillratio += 800 + 100 * skill_lv;
  3176. if( sd ) { // Still need official value [pakpil]
  3177. uint16 lv = skill_lv;
  3178. skillratio += 100 * skill_check_pc_partner(sd,skill_id,&lv,skill_get_splash(skill_id,skill_lv),0);
  3179. }
  3180. break;
  3181. case WM_SOUND_OF_DESTRUCTION:
  3182. skillratio += 400;
  3183. break;
  3184. case GN_CART_TORNADO:
  3185. // ATK [( Skill Level x 50 ) + ( Cart Weight / ( 150 - Caster Base STR ))] + ( Cart Remodeling Skill Level x 50 )] %
  3186. skillratio = 50 * skill_lv;
  3187. if( sd && sd->cart_weight)
  3188. skillratio += sd->cart_weight/10 / max(150-sd->status.str,1) + pc_checkskill(sd, GN_REMODELING_CART) * 50;
  3189. break;
  3190. case GN_CARTCANNON:
  3191. // ATK [{( Cart Remodeling Skill Level x 50 ) x ( INT / 40 )} + ( Cart Cannon Skill Level x 60 )] %
  3192. skillratio = 60 * skill_lv;
  3193. if( sd ) skillratio += pc_checkskill(sd, GN_REMODELING_CART) * 50 * (sstatus->int_ / 40);
  3194. break;
  3195. case GN_SPORE_EXPLOSION:
  3196. skillratio += 200 + 100 * skill_lv;
  3197. break;
  3198. case GN_CRAZYWEED_ATK:
  3199. skillratio += 400 + 100 * skill_lv;
  3200. break;
  3201. case GN_SLINGITEM_RANGEMELEEATK:
  3202. if( sd ) {
  3203. switch( sd->itemid ) {
  3204. case 13260: // Apple Bomob
  3205. case 13261: // Coconut Bomb
  3206. case 13262: // Melon Bomb
  3207. case 13263: // Pinapple Bomb
  3208. skillratio += 400; // Unconfirded
  3209. break;
  3210. case 13264: // Banana Bomb 2000%
  3211. skillratio += 1900;
  3212. break;
  3213. case 13265: skillratio -= 75; break; // Black Lump 25%
  3214. case 13266: skillratio -= 25; break; // Hard Black Lump 75%
  3215. case 13267: skillratio += 100; break; // Extremely Hard Black Lump 200%
  3216. }
  3217. } else
  3218. skillratio += 300; // Bombs
  3219. break;
  3220. case SO_VARETYR_SPEAR://ATK [{( Striking Level x 50 ) + ( Varetyr Spear Skill Level x 50 )} x Caster Base Level / 100 ] %
  3221. skillratio = 50 * skill_lv + ( sd ? pc_checkskill(sd, SO_STRIKING) * 50 : 0 );
  3222. if( sc && sc->data[SC_BLAST_OPTION] )
  3223. skillratio += sd ? sd->status.job_level * 5 : 0;
  3224. break;
  3225. // Physical Elemantal Spirits Attack Skills
  3226. case EL_CIRCLE_OF_FIRE:
  3227. case EL_FIRE_BOMB_ATK:
  3228. case EL_STONE_RAIN:
  3229. skillratio += 200;
  3230. break;
  3231. case EL_FIRE_WAVE_ATK:
  3232. skillratio += 500;
  3233. break;
  3234. case EL_TIDAL_WEAPON:
  3235. skillratio += 1400;
  3236. break;
  3237. case EL_WIND_SLASH:
  3238. skillratio += 100;
  3239. break;
  3240. case EL_HURRICANE:
  3241. skillratio += 600;
  3242. break;
  3243. case EL_TYPOON_MIS:
  3244. case EL_WATER_SCREW_ATK:
  3245. skillratio += 900;
  3246. break;
  3247. case EL_STONE_HAMMER:
  3248. skillratio += 400;
  3249. break;
  3250. case EL_ROCK_CRUSHER:
  3251. skillratio += 700;
  3252. break;
  3253. case KO_JYUMONJIKIRI:
  3254. skillratio += -100 + 150 * skill_lv;
  3255. case KO_HUUMARANKA:
  3256. skillratio += -100 + 150 * skill_lv + sstatus->dex/2 + sstatus->agi/2; // needs more info
  3257. break;
  3258. case KO_SETSUDAN:
  3259. skillratio += 100 * (skill_lv-1);
  3260. break;
  3261. case KO_BAKURETSU:
  3262. skillratio = 50 * skill_lv * (sd?pc_checkskill(sd,NJ_TOBIDOUGU):10);
  3263. break;
  3264. case MH_NEEDLE_OF_PARALYZE:
  3265. skillratio += 600 + 100 * skill_lv;
  3266. break;
  3267. case MH_STAHL_HORN:
  3268. skillratio += 400 + 100 * skill_lv * status_get_lv(src);
  3269. skillratio = skillratio/100; //@TODO uv1 factor need to be confirmed
  3270. break;
  3271. case MH_LAVA_SLIDE:
  3272. skillratio += -100 + 70 * skill_lv;
  3273. break;
  3274. case MH_SONIC_CRAW:
  3275. skillratio += -100 + 40 * skill_lv * status_get_lv(src);
  3276. skillratio = skillratio/100; //@TODO uv1 factor need to be confirmed
  3277. break;
  3278. case MH_SILVERVEIN_RUSH:
  3279. skillratio += -100 + (150 * skill_lv * status_get_lv(src)) / 100;
  3280. break;
  3281. case MH_MIDNIGHT_FRENZY:
  3282. skillratio += -100 + (300 * skill_lv * status_get_lv(src)) / 150;
  3283. break;
  3284. case MH_TINDER_BREAKER:
  3285. skillratio += -100 + (100 * skill_lv + status_get_str(src));
  3286. skillratio = (skillratio * status_get_lv(src)) / 120;
  3287. break;
  3288. case MH_CBC:
  3289. skillratio += 300 * skill_lv + 4 * status_get_lv(src);
  3290. break;
  3291. case MH_MAGMA_FLOW:
  3292. skillratio += -100 + 100 * skill_lv + 3 * status_get_lv(src);
  3293. skillratio = (skillratio * status_get_lv(src)) / 120;
  3294. break;
  3295. }
  3296. return skillratio;
  3297. }
  3298. /*==================================================================================================
  3299. * Constant skill damage additions are added before SC modifiers and after skill base ATK calculation
  3300. *--------------------------------------------------------------------------------------------------*
  3301. * Credits:
  3302. * Original coder Skoltex
  3303. * Initial refactoring by Baalberith
  3304. * Refined and optimized by helvetica
  3305. */
  3306. static int battle_calc_skill_constant_addition(struct Damage wd, struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv)
  3307. {
  3308. struct map_session_data *sd = BL_CAST(BL_PC, src);
  3309. struct map_session_data *tsd = BL_CAST(BL_PC, target);
  3310. struct status_change *sc = status_get_sc(src);
  3311. struct status_change *tsc = status_get_sc(target);
  3312. struct status_data *sstatus = status_get_status_data(src);
  3313. struct status_data *tstatus = status_get_status_data(target);
  3314. int i, atk = 0;
  3315. //Constant/misc additions from skills
  3316. switch (skill_id) {
  3317. case MO_EXTREMITYFIST:
  3318. atk = 250 + 150*skill_lv;
  3319. break;
  3320. case TK_DOWNKICK:
  3321. case TK_STORMKICK:
  3322. case TK_TURNKICK:
  3323. case TK_COUNTER:
  3324. case TK_JUMPKICK:
  3325. //TK_RUN kick damage bonus.
  3326. if(sd && sd->weapontype1 == W_FIST && sd->weapontype2 == W_FIST)
  3327. atk = 10*pc_checkskill(sd, TK_RUN);
  3328. break;
  3329. case GS_MAGICALBULLET:
  3330. if(sstatus->matk_max>sstatus->matk_min) {
  3331. atk = sstatus->matk_min+rnd()%(sstatus->matk_max-sstatus->matk_min);
  3332. } else {
  3333. atk = sstatus->matk_min;
  3334. }
  3335. break;
  3336. case NJ_SYURIKEN:
  3337. atk = 4*skill_lv;
  3338. break;
  3339. case HT_FREEZINGTRAP:
  3340. if(sd)
  3341. atk = ( 40 * pc_checkskill(sd, RA_RESEARCHTRAP) );
  3342. break;
  3343. case RA_WUGDASH ://(Caster Current Weight x 10 / 8)
  3344. if( sd && sd->weight )
  3345. atk = ( sd->weight / 8 );
  3346. case RA_WUGSTRIKE:
  3347. case RA_WUGBITE:
  3348. if(sd)
  3349. atk = (30*pc_checkskill(sd, RA_TOOTHOFWUG));
  3350. break;
  3351. case SR_GATEOFHELL:
  3352. atk = (sstatus->max_hp - status_get_hp(src));
  3353. if(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE) {
  3354. atk += ( ((int64)sstatus->max_sp * (1 + skill_lv * 2 / 10)) + 40 * status_get_lv(src) );
  3355. } else {
  3356. atk += ( ((int64)sstatus->sp * (1 + skill_lv * 2 / 10)) + 10 * status_get_lv(src) );
  3357. }
  3358. break;
  3359. case SR_TIGERCANNON: // (Tiger Cannon skill level x 240) + (Target Base Level x 40)
  3360. atk = ( skill_lv * 240 + status_get_lv(target) * 40 );
  3361. if( sc && sc->data[SC_COMBO]
  3362. && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE ) // (Tiger Cannon skill level x 500) + (Target Base Level x 40)
  3363. atk = ( skill_lv * 500 + status_get_lv(target) * 40 );
  3364. break;
  3365. case SR_FALLENEMPIRE:// [(Target Size value + Skill Level - 1) x Caster STR] + [(Target current weight x Caster DEX / 120)]
  3366. atk = ( ((tstatus->size+1)*2 + skill_lv - 1) * sstatus->str);
  3367. if( tsd && tsd->weight ){
  3368. atk = ( (tsd->weight/10) * sstatus->dex / 120 );
  3369. }else{
  3370. atk = ( status_get_lv(target) * 50 ); //mobs
  3371. }
  3372. break;
  3373. case KO_SETSUDAN:
  3374. if( tsc && tsc->data[SC_SPIRIT] ){
  3375. #ifdef RENEWAL
  3376. atk = ((wd.equipAtk + wd.weaponAtk + wd.statusAtk + wd.masteryAtk) * (10*tsc->data[SC_SPIRIT]->val1)) / 100;// +10% custom value.
  3377. #else
  3378. atk = (int) ((wd.damage) * (10*tsc->data[SC_SPIRIT]->val1)) / 100;// +10% custom value.
  3379. #endif
  3380. status_change_end(target,SC_SPIRIT,INVALID_TIMER);
  3381. }
  3382. break;
  3383. case KO_KAIHOU:
  3384. if( sd ){
  3385. ARR_FIND(1, 6, i, sd->talisman[i] > 0);
  3386. if( i < 5 ){
  3387. #ifdef RENEWAL
  3388. atk = ((wd.equipAtk + wd.weaponAtk + wd.statusAtk + wd.masteryAtk) * (100 * sd->talisman[i])) / 100;// +100% custom value.
  3389. #else
  3390. atk = (int) ((wd.damage) * (100 * sd->talisman[i])) / 100;// +100% custom value.
  3391. #endif
  3392. pc_del_talisman(sd, sd->talisman[i], i);
  3393. }
  3394. }
  3395. break;
  3396. }
  3397. return atk;
  3398. }
  3399. /*==============================================================
  3400. * Stackable SC bonuses added on top of calculated skill damage
  3401. *--------------------------------------------------------------
  3402. * Credits:
  3403. * Original coder Skoltex
  3404. * Initial refactoring by Baalberith
  3405. * Refined and optimized by helvetica
  3406. */
  3407. struct Damage battle_attack_sc_bonus(struct Damage wd, struct block_list *src, uint16 skill_id)
  3408. {
  3409. struct status_change *sc = status_get_sc(src);
  3410. //The following are applied on top of current damage and are stackable.
  3411. if ( sc ) {
  3412. #ifndef RENEWAL
  3413. if( sc->data[SC_TRUESIGHT] )
  3414. ATK_ADDRATE(wd.damage, wd.damage2, 2*sc->data[SC_TRUESIGHT]->val1);
  3415. #endif
  3416. if( sc->data[SC_GLOOMYDAY_SK] &&
  3417. ( skill_id == LK_SPIRALPIERCE || skill_id == KN_BRANDISHSPEAR ||
  3418. skill_id == CR_SHIELDBOOMERANG || skill_id == PA_SHIELDCHAIN ||
  3419. skill_id == LG_SHIELDPRESS ) ) {
  3420. ATK_ADDRATE(wd.damage, wd.damage2, sc->data[SC_GLOOMYDAY_SK]->val2);
  3421. #ifdef RENEWAL
  3422. ATK_ADDRATE(wd.weaponAtk, wd.weaponAtk2, sc->data[SC_GLOOMYDAY_SK]->val2);
  3423. #endif
  3424. }
  3425. if (sc->data[SC_SPIRIT]){
  3426. if(skill_id == AS_SONICBLOW && sc->data[SC_SPIRIT]->val2 == SL_ASSASIN){
  3427. ATK_ADDRATE(wd.damage, wd.damage2, map_flag_gvg(src->m)?25:100); //+25% dmg on woe/+100% dmg on nonwoe
  3428. #ifdef RENEWAL
  3429. ATK_ADDRATE(wd.weaponAtk, wd.weaponAtk2, map_flag_gvg(src->m)?25:100); //+25% dmg on woe/+100% dmg on nonwoe
  3430. #endif
  3431. }
  3432. else if (skill_id == CR_SHIELDBOOMERANG && (sc->data[SC_SPIRIT]->val2 == SL_CRUSADER)){
  3433. ATK_ADDRATE(wd.damage, wd.damage2, 100);
  3434. #ifdef RENEWAL
  3435. ATK_ADDRATE(wd.weaponAtk, wd.weaponAtk2, 100);
  3436. #endif
  3437. }
  3438. }
  3439. if( sc->data[SC_EDP] ){
  3440. switch(skill_id){
  3441. case AS_SPLASHER:
  3442. // Pre-Renewal only: Soul Breaker and Meteor Assault ignores EDP
  3443. // Renewal only: Grimtooth and Venom Knife ignore EDP
  3444. // Both: Venom Splasher ignores EDP [helvetica]
  3445. #ifndef RENEWAL
  3446. case ASC_BREAKER: case ASC_METEORASSAULT:
  3447. #else
  3448. case AS_GRIMTOOTH: case AS_VENOMKNIFE:
  3449. #endif
  3450. break; // skills above have no effect with edp
  3451. #ifdef RENEWAL
  3452. // renewal EDP mode requires renewal enabled as well
  3453. // Renewal EDP: damage gets a half modifier on top of EDP bonus for skills [helvetica]
  3454. // * Sonic Blow
  3455. // * Soul Breaker
  3456. // * Counter Slash
  3457. // * Cross Impact
  3458. case AS_SONICBLOW:
  3459. case ASC_BREAKER:
  3460. case GC_COUNTERSLASH:
  3461. case GC_CROSSIMPACT:
  3462. ATK_RATE(wd.weaponAtk, wd.weaponAtk2, 50);
  3463. ATK_RATE(wd.equipAtk, wd.equipAtk2, 50);
  3464. default: // fall through to apply EDP bonuses
  3465. // Renewal EDP formula [helvetica]
  3466. // weapon atk * (1 + (edp level * .8))
  3467. // equip atk * (1 + (edp level * .6))
  3468. ATK_RATE(wd.weaponAtk, wd.weaponAtk2, 100 + (sc->data[SC_EDP]->val1 * 80));
  3469. ATK_RATE(wd.equipAtk, wd.equipAtk2, 100 + (sc->data[SC_EDP]->val1 * 60));
  3470. break;
  3471. #else
  3472. default:
  3473. ATK_ADDRATE(wd.damage, wd.damage2, sc->data[SC_EDP]->val3);
  3474. #endif
  3475. }
  3476. }
  3477. if(sc->data[SC_STYLE_CHANGE]){
  3478. TBL_HOM *hd = BL_CAST(BL_HOM,src);
  3479. if (hd) ATK_ADD(wd.damage, wd.damage2, hd->homunculus.spiritball * 3);
  3480. }
  3481. }
  3482. return wd;
  3483. }
  3484. /*====================================
  3485. * Calc defense damage reduction
  3486. *------------------------------------
  3487. * Credits:
  3488. * Original coder Skoltex
  3489. * Initial refactoring by Baalberith
  3490. * Refined and optimized by helvetica
  3491. */
  3492. struct Damage battle_calc_defense_reduction(struct Damage wd, struct block_list *src,struct block_list *target, uint16 skill_id, uint16 skill_lv)
  3493. {
  3494. struct map_session_data *sd = BL_CAST(BL_PC, src);
  3495. struct map_session_data *tsd = BL_CAST(BL_PC, target);
  3496. struct status_change *sc = status_get_sc(src);
  3497. struct status_change *tsc = status_get_sc(target);
  3498. struct status_data *sstatus = status_get_status_data(src);
  3499. struct status_data *tstatus = status_get_status_data(target);
  3500. int i, skill;
  3501. //Defense reduction
  3502. short vit_def;
  3503. defType def1 = status_get_def(target); //Don't use tstatus->def1 due to skill timer reductions.
  3504. short def2 = tstatus->def2;
  3505. #ifdef RENEWAL
  3506. if( tsc && tsc->data[SC_ASSUMPTIO] )
  3507. def1 <<= 1; // only eDEF is doubled
  3508. #endif
  3509. if( sd )
  3510. {
  3511. i = sd->ignore_def[is_boss(target)?RC_BOSS:RC_NONBOSS];
  3512. i += sd->ignore_def[tstatus->race];
  3513. if( i )
  3514. {
  3515. if( i > 100 ) i = 100;
  3516. def1 -= def1 * i / 100;
  3517. def2 -= def2 * i / 100;
  3518. }
  3519. }
  3520. if( sc && sc->data[SC_EXPIATIO] ){
  3521. i = 5 * sc->data[SC_EXPIATIO]->val1; // 5% per level
  3522. def1 -= def1 * i / 100;
  3523. def2 -= def2 * i / 100;
  3524. }
  3525. if( tsc && tsc->data[SC_GT_REVITALIZE] && tsc->data[SC_GT_REVITALIZE]->val4 )
  3526. def2 += 2 * tsc->data[SC_GT_REVITALIZE]->val4;
  3527. if( tsc && tsc->data[SC_CAMOUFLAGE] ){
  3528. i = 5 * tsc->data[SC_CAMOUFLAGE]->val3;
  3529. def1 = max(0,def1); //min 0 def
  3530. def2 = max(0,def2);
  3531. }
  3532. if( battle_config.vit_penalty_type && battle_config.vit_penalty_target&target->type ) {
  3533. unsigned char target_count; //256 max targets should be a sane max
  3534. target_count = unit_counttargeted(target);
  3535. if(target_count >= battle_config.vit_penalty_count) {
  3536. if(battle_config.vit_penalty_type == 1) {
  3537. if( !tsc || !tsc->data[SC_STEELBODY] )
  3538. def1 = (def1 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100;
  3539. def2 = (def2 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100;
  3540. } else { //Assume type 2
  3541. if( !tsc || !tsc->data[SC_STEELBODY] )
  3542. def1 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num;
  3543. def2 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num;
  3544. }
  3545. }
  3546. if(skill_id == AM_ACIDTERROR) def1 = 0; //Acid Terror ignores only armor defense. [Skotlex]
  3547. if(def2 < 1) def2 = 1;
  3548. }
  3549. //Vitality reduction from rodatazone: http://rodatazone.simgaming.net/mechanics/substats.php#def
  3550. if (tsd) //Sd vit-eq
  3551. {
  3552. #ifndef RENEWAL
  3553. //[VIT*0.5] + rnd([VIT*0.3], max([VIT*0.3],[VIT^2/150]-1))
  3554. vit_def = def2*(def2-15)/150;
  3555. vit_def = def2/2 + (vit_def>0?rnd()%vit_def:0);
  3556. #else
  3557. vit_def = def2;
  3558. #endif
  3559. if((battle_check_undead(sstatus->race,sstatus->def_ele) || sstatus->race==RC_DEMON) && //This bonus already doesnt work vs players
  3560. src->type == BL_MOB && (skill=pc_checkskill(tsd,AL_DP)) > 0)
  3561. vit_def += skill*(int)(3 +(tsd->status.base_level+1)*0.04); // submitted by orn
  3562. if( src->type == BL_MOB && (skill=pc_checkskill(tsd,RA_RANGERMAIN))>0 &&
  3563. (sstatus->race == RC_BRUTE || sstatus->race == RC_FISH || sstatus->race == RC_PLANT) )
  3564. vit_def += skill*5;
  3565. }
  3566. else { //Mob-Pet vit-eq
  3567. #ifndef RENEWAL
  3568. //VIT + rnd(0,[VIT/20]^2-1)
  3569. vit_def = (def2/20)*(def2/20);
  3570. vit_def = def2 + (vit_def>0?rnd()%vit_def:0);
  3571. #else
  3572. //renewal monsters have their def swapped
  3573. vit_def = def1;
  3574. def1 = def2;
  3575. #endif
  3576. }
  3577. if (battle_config.weapon_defense_type) {
  3578. vit_def += def1*battle_config.weapon_defense_type;
  3579. def1 = 0;
  3580. }
  3581. #ifdef RENEWAL
  3582. /**
  3583. * RE DEF Reduction
  3584. * Damage = Attack * (4000+eDEF)/(4000+eDEF*10) - sDEF
  3585. * Pierce defence gains 1 atk per def/2
  3586. **/
  3587. if( def1 == -400 ) /* being hit by a gazillion units, -400 creates a division by 0 and subsequently crashes */
  3588. def1 = -399;
  3589. ATK_ADD2(wd.damage, wd.damage2,
  3590. is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ?(def1/2):0,
  3591. is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L)?(def1/2):0
  3592. );
  3593. if( !attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_R) && !is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) )
  3594. wd.damage = wd.damage * (4000+def1) / (4000+10*def1) - vit_def;
  3595. if( is_attack_left_handed(src, skill_id) && !attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_L) && !is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L) )
  3596. wd.damage2 = wd.damage2 * (4000+def1) / (4000+10*def1) - vit_def;
  3597. #else
  3598. if (def1 > 100) def1 = 100;
  3599. ATK_RATE2(wd.damage, wd.damage2,
  3600. attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ?100:(is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ? (int64)is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R)*(def1+vit_def) : (100-def1)),
  3601. attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_L)?100:(is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L)? (int64)is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L)*(def1+vit_def) : (100-def1))
  3602. );
  3603. ATK_ADD2(wd.damage, wd.damage2,
  3604. attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_R) || is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ?0:-vit_def,
  3605. attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_L) || is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L)?0:-vit_def
  3606. );
  3607. #endif
  3608. return wd;
  3609. }
  3610. /*====================================
  3611. * Modifiers ignoring DEF
  3612. *------------------------------------
  3613. * Credits:
  3614. * Original coder Skoltex
  3615. * Initial refactoring by Baalberith
  3616. * Refined and optimized by helvetica
  3617. */
  3618. struct Damage battle_calc_attack_post_defense(struct Damage wd, struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv)
  3619. {
  3620. struct map_session_data *sd = BL_CAST(BL_PC, src);
  3621. struct status_change *sc = status_get_sc(src);
  3622. struct status_data *sstatus = status_get_status_data(src);
  3623. //Post skill/vit reduction damage increases
  3624. if( sc )
  3625. { //SC skill damages
  3626. if(sc->data[SC_AURABLADE]
  3627. #ifndef RENEWAL
  3628. && skill_id != LK_SPIRALPIERCE && skill_id != ML_SPIRALPIERCE
  3629. #endif
  3630. ){
  3631. int lv = sc->data[SC_AURABLADE]->val1;
  3632. #ifdef RENEWAL
  3633. lv *= ((skill_id == LK_SPIRALPIERCE || skill_id == ML_SPIRALPIERCE)?wd.div_:1); // +100 per hit in lv 5
  3634. #endif
  3635. ATK_ADD(wd.damage, wd.damage2, 20*lv);
  3636. }
  3637. if(sc->data[SC_GT_CHANGE] && sc->data[SC_GT_CHANGE]->val2){
  3638. struct block_list *bl; // ATK increase: ATK [{(Caster DEX / 4) + (Caster STR / 2)} x Skill Level / 5]
  3639. if( (bl = map_id2bl(sc->data[SC_GT_CHANGE]->val2)) )
  3640. ATK_ADD(wd.damage, wd.damage2, ( status_get_dex(bl)/4 + status_get_str(bl)/2 ) * sc->data[SC_GT_CHANGE]->val1 / 5 );
  3641. }
  3642. }
  3643. #ifndef RENEWAL
  3644. wd = battle_calc_attack_masteries(wd, src, target, skill_id, skill_lv);
  3645. //Refine bonus
  3646. if( sd && battle_skill_stacks_masteries_vvs(skill_id) && skill_id != MO_INVESTIGATE && skill_id != MO_EXTREMITYFIST )
  3647. { // Counts refine bonus multiple times
  3648. if( skill_id == MO_FINGEROFFENSIVE )
  3649. {
  3650. ATK_ADD2(wd.damage, wd.damage2, wd.div_*sstatus->rhw.atk2, wd.div_*sstatus->lhw.atk2);
  3651. } else {
  3652. ATK_ADD2(wd.damage, wd.damage2, sstatus->rhw.atk2, sstatus->lhw.atk2);
  3653. }
  3654. }
  3655. #endif
  3656. //Set to min of 1
  3657. if (is_attack_right_handed(src, skill_id) && wd.damage < 1) wd.damage = 1;
  3658. if (is_attack_left_handed(src, skill_id) && wd.damage2 < 1) wd.damage2 = 1;
  3659. if (skill_id == NJ_KUNAI) {
  3660. RE_ALLATK_ADD(wd, 60);
  3661. ATK_ADD(wd.damage, wd.damage2, 60);
  3662. }
  3663. switch (skill_id) {
  3664. case AS_SONICBLOW:
  3665. if(sd && pc_checkskill(sd,AS_SONICACCEL)>0)
  3666. ATK_ADDRATE(wd.damage, wd.damage2, 10);
  3667. break;
  3668. case NC_AXETORNADO:
  3669. if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND )
  3670. ATK_ADDRATE(wd.damage, wd.damage2, 50);
  3671. break;
  3672. }
  3673. return wd;
  3674. }
  3675. /*=================================================================================
  3676. * "Plant"-type (mobs that only take 1 damage from all sources) damage calculation
  3677. *---------------------------------------------------------------------------------
  3678. * Credits:
  3679. * Original coder Skoltex
  3680. * Initial refactoring by Baalberith
  3681. * Refined and optimized by helvetica
  3682. */
  3683. struct Damage battle_calc_attack_plant(struct Damage wd, struct block_list *src,struct block_list *target, uint16 skill_id, uint16 skill_lv)
  3684. {
  3685. struct status_data *tstatus = status_get_status_data(target);
  3686. bool attack_hits = is_attack_hitting(wd, src, target, skill_id, skill_lv, false);
  3687. int right_element = battle_get_weapon_element(wd, src, target, skill_id, skill_lv, EQI_HAND_R, false);
  3688. int left_element = battle_get_weapon_element(wd, src, target, skill_id, skill_lv, EQI_HAND_L, false);
  3689. //Plants receive 1 damage when hit
  3690. short class_ = status_get_class(target);
  3691. if( attack_hits || wd.damage > 0 )
  3692. wd.damage = wd.div_; // In some cases, right hand no need to have a weapon to increase damage
  3693. if( is_attack_left_handed(src, skill_id) && (attack_hits || wd.damage2 > 0) )
  3694. wd.damage2 = wd.div_;
  3695. if (is_attack_right_handed(src, skill_id) && is_attack_left_handed(src, skill_id)) // force left hand to 1 damage while dual wielding [helvetica]
  3696. wd.damage2 = 1;
  3697. if( attack_hits && class_ == MOBID_EMPERIUM ) {
  3698. if(wd.damage2 > 0) {
  3699. wd.damage2 = battle_attr_fix(src, target, wd.damage2, left_element, tstatus->def_ele, tstatus->ele_lv);
  3700. wd.damage2 = battle_calc_gvg_damage(src, target, wd.damage2, wd.div_, skill_id, skill_lv, wd.flag);
  3701. }
  3702. else if(wd.damage > 0) {
  3703. wd.damage = battle_attr_fix(src, target, wd.damage, right_element, tstatus->def_ele, tstatus->ele_lv);
  3704. wd.damage = battle_calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag);
  3705. }
  3706. return wd;
  3707. }
  3708. //if( !(battle_config.skill_min_damage&1) )
  3709. //Do not return if you are supposed to deal greater damage to plants than 1. [Skotlex]
  3710. return wd;
  3711. }
  3712. /*========================================================================================
  3713. * Perform left/right hand weapon damage calculation based on previously calculated damage
  3714. *----------------------------------------------------------------------------------------
  3715. * Credits:
  3716. * Original coder Skoltex
  3717. * Initial refactoring by Baalberith
  3718. * Refined and optimized by helvetica
  3719. */
  3720. struct Damage battle_calc_attack_left_right_hands(struct Damage wd, struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv)
  3721. {
  3722. struct map_session_data *sd = BL_CAST(BL_PC, src);
  3723. int skill;
  3724. if (sd) {
  3725. if (!is_attack_right_handed(src, skill_id) && is_attack_left_handed(src, skill_id)) {
  3726. wd.damage = wd.damage2;
  3727. wd.damage2 = 0;
  3728. }
  3729. else if(sd->status.weapon == W_KATAR && !skill_id) { //Katars (offhand damage only applies to normal attacks, tested on Aegis 10.2)
  3730. skill = pc_checkskill(sd,TF_DOUBLE);
  3731. wd.damage2 = (int64)wd.damage * (1 + (skill * 2))/100;
  3732. }
  3733. else if(is_attack_right_handed(src, skill_id) && is_attack_left_handed(src, skill_id)) { //Dual-wield
  3734. if (wd.damage) {
  3735. if( (sd->class_&MAPID_BASEMASK) == MAPID_THIEF ) {
  3736. skill = pc_checkskill(sd,AS_RIGHT);
  3737. ATK_RATER(wd.damage, 50 + (skill * 10))
  3738. }
  3739. else if(sd->class_ == MAPID_KAGEROUOBORO) {
  3740. skill = pc_checkskill(sd,KO_RIGHT);
  3741. ATK_RATER(wd.damage, 70 + (skill * 10))
  3742. }
  3743. if(wd.damage < 1) wd.damage = 1;
  3744. }
  3745. if (wd.damage2) {
  3746. if( (sd->class_&MAPID_BASEMASK) == MAPID_THIEF) {
  3747. skill = pc_checkskill(sd,AS_LEFT);
  3748. ATK_RATEL(wd.damage2, 30 + (skill * 10))
  3749. }
  3750. else if(sd->class_ == MAPID_KAGEROUOBORO) {
  3751. skill = pc_checkskill(sd,KO_LEFT);
  3752. ATK_RATEL(wd.damage2, 50 + (skill * 10))
  3753. }
  3754. if(wd.damage2 < 1) wd.damage2 = 1;
  3755. }
  3756. }
  3757. }
  3758. if(!is_attack_right_handed(src, skill_id) && !is_attack_left_handed(src, skill_id) && wd.damage)
  3759. wd.damage=0;
  3760. if(!is_attack_left_handed(src, skill_id) && wd.damage2)
  3761. wd.damage2=0;
  3762. return wd;
  3763. }
  3764. /*==========================================
  3765. * BG/GvG attack modifiers
  3766. *------------------------------------------
  3767. * Credits:
  3768. * Original coder Skoltex
  3769. * Initial refactoring by Baalberith
  3770. * Refined and optimized by helvetica
  3771. */
  3772. struct Damage battle_calc_attack_gvg_bg(struct Damage wd, struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv)
  3773. {
  3774. if( wd.damage + wd.damage2 ) { //There is a total damage value
  3775. if(!wd.damage2) {
  3776. wd.damage = battle_calc_damage(src,target,&wd,wd.damage,skill_id,skill_lv);
  3777. if( map_flag_gvg2(target->m) )
  3778. wd.damage=battle_calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag);
  3779. else if( map[target->m].flag.battleground )
  3780. wd.damage=battle_calc_bg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag);
  3781. }
  3782. else if(!wd.damage) {
  3783. wd.damage2 = battle_calc_damage(src,target,&wd,wd.damage2,skill_id,skill_lv);
  3784. if( map_flag_gvg2(target->m) )
  3785. wd.damage2 = battle_calc_gvg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag);
  3786. else if( map[target->m].flag.battleground )
  3787. wd.damage2 = battle_calc_bg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag);
  3788. }
  3789. else {
  3790. int64 d1 = wd.damage + wd.damage2,d2 = wd.damage2;
  3791. wd.damage = battle_calc_damage(src,target,&wd,d1,skill_id,skill_lv);
  3792. if( map_flag_gvg2(target->m) )
  3793. wd.damage = battle_calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag);
  3794. else if( map[target->m].flag.battleground )
  3795. wd.damage = battle_calc_bg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag);
  3796. wd.damage2 = (int64)d2*100/d1 * wd.damage/100;
  3797. if(wd.damage > 1 && wd.damage2 < 1) wd.damage2 = 1;
  3798. wd.damage-=wd.damage2;
  3799. }
  3800. }
  3801. return wd;
  3802. }
  3803. /*==========================================
  3804. * final ATK modifiers - after BG/GvG calc
  3805. *------------------------------------------
  3806. * Credits:
  3807. * Original coder Skoltex
  3808. * Initial refactoring by Baalberith
  3809. * Refined and optimized by helvetica
  3810. */
  3811. struct Damage battle_calc_weapon_final_atk_modifiers(struct Damage wd, struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv)
  3812. {
  3813. struct map_session_data *sd = BL_CAST(BL_PC, src);
  3814. struct map_session_data *tsd = BL_CAST(BL_PC, target);
  3815. struct status_change *sc = status_get_sc(src);
  3816. struct status_change *tsc = status_get_sc(target);
  3817. struct status_data *sstatus = status_get_status_data(src);
  3818. struct status_data *tstatus = status_get_status_data(target);
  3819. //Reject Sword bugreport:4493 by Daegaladh
  3820. if(wd.damage && tsc && tsc->data[SC_REJECTSWORD] &&
  3821. (src->type!=BL_PC || (
  3822. ((TBL_PC *)src)->weapontype1 == W_DAGGER ||
  3823. ((TBL_PC *)src)->weapontype1 == W_1HSWORD ||
  3824. ((TBL_PC *)src)->status.weapon == W_2HSWORD
  3825. )) &&
  3826. rnd()%100 < tsc->data[SC_REJECTSWORD]->val2
  3827. ) {
  3828. ATK_RATER(wd.damage, 50)
  3829. status_fix_damage(target,src,wd.damage,clif_damage(target,src,gettick(),0,0,wd.damage,0,0,0));
  3830. clif_skill_nodamage(target,target,ST_REJECTSWORD,tsc->data[SC_REJECTSWORD]->val1,1);
  3831. if( --(tsc->data[SC_REJECTSWORD]->val3) <= 0 )
  3832. status_change_end(target, SC_REJECTSWORD, INVALID_TIMER);
  3833. }
  3834. if( tsc && tsc->data[SC_CRESCENTELBOW] && !is_boss(src) && rnd()%100 < tsc->data[SC_CRESCENTELBOW]->val2 ) {
  3835. //ATK [{(Target HP / 100) x Skill Level} x Caster Base Level / 125] % + [Received damage x {1 + (Skill Level x 0.2)}]
  3836. int64 rdamage = 0;
  3837. int ratio = (int64)(status_get_hp(src) / 100) * tsc->data[SC_CRESCENTELBOW]->val1 * status_get_lv(target) / 125;
  3838. if (ratio > 5000) ratio = 5000; // Maximum of 5000% ATK
  3839. rdamage = battle_calc_base_damage(tstatus,&tstatus->rhw,tsc,sstatus->size,tsd,0);
  3840. rdamage = (int64)rdamage * ratio / 100 + wd.damage * (10 + tsc->data[SC_CRESCENTELBOW]->val1 * 20 / 10) / 10;
  3841. skill_blown(target, src, skill_get_blewcount(SR_CRESCENTELBOW_AUTOSPELL, tsc->data[SC_CRESCENTELBOW]->val1), unit_getdir(src), 0);
  3842. clif_skill_damage(target, src, gettick(), status_get_amotion(src), 0, rdamage,
  3843. 1, SR_CRESCENTELBOW_AUTOSPELL, tsc->data[SC_CRESCENTELBOW]->val1, 6); // This is how official does
  3844. clif_damage(src, target, gettick(), status_get_amotion(src)+1000, 0, rdamage/10, 1, 0, 0);
  3845. status_damage(target, src, rdamage, 0, 0, 0);
  3846. status_damage(src, target, rdamage/10, 0, 0, 1);
  3847. status_change_end(target, SC_CRESCENTELBOW, INVALID_TIMER);
  3848. }
  3849. if( sc ) {
  3850. //SC_FUSION hp penalty [Komurka]
  3851. if (sc->data[SC_FUSION]) {
  3852. int hp= sstatus->max_hp;
  3853. if (sd && tsd) {
  3854. hp = 8*hp/100;
  3855. if (((int64)sstatus->hp * 100) <= ((int64)sstatus->max_hp * 20))
  3856. hp = sstatus->hp;
  3857. } else
  3858. hp = 2*hp/100; //2% hp loss per hit
  3859. status_zap(src, hp, 0);
  3860. }
  3861. /**
  3862. * affecting non-skills
  3863. **/
  3864. if( !skill_id ) {
  3865. /**
  3866. * RK Enchant Blade
  3867. **/
  3868. if( sc->data[SC_ENCHANTBLADE] && sd && ( (is_attack_right_handed(src, skill_id) && sd->weapontype1) || (is_attack_left_handed(src, skill_id) && sd->weapontype2) ) ) {
  3869. //[( ( Skill Lv x 20 ) + 100 ) x ( casterBaseLevel / 150 )] + casterInt
  3870. ATK_ADD(wd.damage, wd.damage2, ( sc->data[SC_ENCHANTBLADE]->val1*20+100 ) * status_get_lv(src) / 150 + status_get_int(src) );
  3871. }
  3872. }
  3873. status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER);
  3874. }
  3875. switch (skill_id) {
  3876. case LG_RAYOFGENESIS:
  3877. {
  3878. struct Damage md = battle_calc_magic_attack(src, target, skill_id, skill_lv, wd.miscflag);
  3879. wd.damage += md.damage;
  3880. }
  3881. break;
  3882. #ifndef RENEWAL
  3883. case ASC_BREAKER:
  3884. { //Breaker's int-based damage (a misc attack?)
  3885. struct Damage md = battle_calc_misc_attack(src, target, skill_id, skill_lv, wd.miscflag);
  3886. wd.damage += md.damage;
  3887. }
  3888. break;
  3889. #endif
  3890. }
  3891. return wd;
  3892. }
  3893. /*====================================================
  3894. * Basic wd init - not influenced by HIT/MISS/DEF/etc.
  3895. *----------------------------------------------------
  3896. * Credits:
  3897. * Original coder Skoltex
  3898. * Initial refactoring by Baalberith
  3899. * Refined and optimized by helvetica
  3900. */
  3901. static struct Damage initialize_weapon_data(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int wflag)
  3902. {
  3903. struct status_data *sstatus = status_get_status_data(src);
  3904. struct status_data *tstatus = status_get_status_data(target);
  3905. struct map_session_data *sd = BL_CAST(BL_PC, src);
  3906. struct Damage wd;
  3907. wd.type=0; //Normal attack
  3908. wd.div_=skill_id?skill_get_num(skill_id,skill_lv):1;
  3909. wd.amotion=(skill_id && skill_get_inf(skill_id)&INF_GROUND_SKILL)?0:sstatus->amotion; //Amotion should be 0 for ground skills.
  3910. // counter attack DOES obey ASPD delay on official, uncomment if you want the old (bad) behavior [helvetica]
  3911. /*if(skill_id == KN_AUTOCOUNTER)
  3912. wd.amotion >>= 1; */
  3913. wd.dmotion=tstatus->dmotion;
  3914. wd.blewcount=skill_get_blewcount(skill_id,skill_lv);
  3915. wd.miscflag = wflag;
  3916. wd.flag = BF_WEAPON; //Initial Flag
  3917. wd.flag |= (skill_id||wd.miscflag)?BF_SKILL:BF_NORMAL; // Baphomet card's splash damage is counted as a skill. [Inkfish]
  3918. wd.damage = wd.damage2 =
  3919. #ifdef RENEWAL
  3920. wd.statusAtk = wd.statusAtk2 = wd.equipAtk = wd.equipAtk2 = wd.weaponAtk = wd.weaponAtk2 = wd.masteryAtk = wd.masteryAtk2 =
  3921. #endif
  3922. 0;
  3923. wd.dmg_lv=ATK_DEF; //This assumption simplifies the assignation later
  3924. if(sd)
  3925. wd.blewcount += battle_blewcount_bonus(sd, skill_id);
  3926. if (skill_id) {
  3927. wd.flag |= battle_range_type(src, target, skill_id, skill_lv);
  3928. switch(skill_id)
  3929. {
  3930. case MH_SONIC_CRAW:{
  3931. TBL_HOM *hd = BL_CAST(BL_HOM,src);
  3932. wd.div_ = hd->homunculus.spiritball;
  3933. }
  3934. break;
  3935. case MO_FINGEROFFENSIVE:
  3936. if(sd) {
  3937. if (battle_config.finger_offensive_type)
  3938. wd.div_ = 1;
  3939. else
  3940. wd.div_ = sd->spiritball_old;
  3941. }
  3942. break;
  3943. case KN_PIERCE:
  3944. case ML_PIERCE:
  3945. wd.div_= (wd.div_>0?tstatus->size+1:-(tstatus->size+1));
  3946. break;
  3947. case TF_DOUBLE: //For NPC used skill.
  3948. case GS_CHAINACTION:
  3949. wd.type = 0x08;
  3950. break;
  3951. case GS_GROUNDDRIFT:
  3952. case KN_SPEARSTAB:
  3953. case KN_BOWLINGBASH:
  3954. case MS_BOWLINGBASH:
  3955. case MO_BALKYOUNG:
  3956. case TK_TURNKICK:
  3957. wd.blewcount=0;
  3958. break;
  3959. case KN_AUTOCOUNTER:
  3960. wd.flag=(wd.flag&~BF_SKILLMASK)|BF_NORMAL;
  3961. break;
  3962. case LK_SPIRALPIERCE:
  3963. if (!sd) wd.flag=(wd.flag&~(BF_RANGEMASK|BF_WEAPONMASK))|BF_LONG|BF_MISC;
  3964. break;
  3965. }
  3966. } else {
  3967. wd.flag |= is_skill_using_arrow(src, skill_id)?BF_LONG:BF_SHORT;
  3968. }
  3969. return wd;
  3970. }
  3971. /*============================================
  3972. * Calculate "weapon"-type attacks and skills
  3973. *--------------------------------------------
  3974. * Credits:
  3975. * Original coder Skoltex
  3976. * Initial refactoring by Baalberith
  3977. * Refined and optimized by helvetica
  3978. */
  3979. static struct Damage battle_calc_weapon_attack(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int wflag)
  3980. {
  3981. int i;
  3982. #ifdef ADJUST_SKILL_DAMAGE
  3983. int skill_damage;
  3984. #endif
  3985. struct map_session_data *sd, *tsd;
  3986. struct Damage wd;
  3987. struct status_change *sc = status_get_sc(src);
  3988. struct status_change *tsc = status_get_sc(target);
  3989. struct status_data *tstatus = status_get_status_data(target);
  3990. int right_element, left_element;
  3991. memset(&wd,0,sizeof(wd));
  3992. if(src==NULL || target==NULL)
  3993. {
  3994. nullpo_info(NLP_MARK);
  3995. return wd;
  3996. }
  3997. wd = initialize_weapon_data(src, target, skill_id, skill_lv, wflag);
  3998. right_element = battle_get_weapon_element(wd, src, target, skill_id, skill_lv, EQI_HAND_R, false);
  3999. left_element = battle_get_weapon_element(wd, src, target, skill_id, skill_lv, EQI_HAND_L, false);
  4000. if (sc && !sc->count)
  4001. sc = NULL; //Skip checking as there are no status changes active.
  4002. if (tsc && !tsc->count)
  4003. tsc = NULL; //Skip checking as there are no status changes active.
  4004. sd = BL_CAST(BL_PC, src);
  4005. tsd = BL_CAST(BL_PC, target);
  4006. if ( (!skill_id || skill_id == PA_SACRIFICE) && tstatus->flee2 && rnd()%1000 < tstatus->flee2 )
  4007. { //Check for Lucky Dodge
  4008. wd.type=0x0b;
  4009. wd.dmg_lv=ATK_LUCKY;
  4010. if (wd.div_ < 0) wd.div_*=-1;
  4011. return wd;
  4012. }
  4013. // on official check for multi hit first so we can override crit on double attack [helvetica]
  4014. wd = battle_calc_multi_attack(wd, src, target, skill_id, skill_lv);
  4015. // crit check is next since crits always hit on official [helvetica]
  4016. if (is_attack_critical(wd, src, target, skill_id, skill_lv, true))
  4017. wd.type = 0x0a;
  4018. // check if we're landing a hit
  4019. if(!is_attack_hitting(wd, src, target, skill_id, skill_lv, true))
  4020. wd.dmg_lv = ATK_FLEE;
  4021. else if(!target_has_infinite_defense(target, skill_id)) { //no need for math against plants
  4022. int ratio;
  4023. wd = battle_calc_skill_base_damage(wd, src, target, skill_id, skill_lv); // base skill damage
  4024. ratio = battle_calc_attack_skill_ratio(wd, src, target, skill_id, skill_lv); // skill level ratios
  4025. ATK_RATE(wd.damage, wd.damage2, ratio);
  4026. RE_ALLATK_RATE(wd, ratio);
  4027. ratio = battle_calc_skill_constant_addition(wd, src, target, skill_id, skill_lv); // other skill bonuses
  4028. ATK_ADD(wd.damage, wd.damage2, ratio);
  4029. #ifdef RENEWAL
  4030. ATK_ADD(wd.equipAtk, wd.equipAtk2, ratio); // equip ATK gets modified by skill bonuses as well [helvetica]
  4031. if(skill_id == HW_MAGICCRASHER) { // Add weapon attack for MATK onto Magic Crasher
  4032. struct status_data *sstatus = status_get_status_data(src);
  4033. if (sstatus->matk_max > sstatus->matk_min) {
  4034. ATK_ADD(wd.weaponAtk, wd.weaponAtk2, sstatus->matk_min+rnd()%(sstatus->matk_max-sstatus->matk_min));
  4035. } else {
  4036. ATK_ADD(wd.weaponAtk, wd.weaponAtk2, sstatus->matk_min);
  4037. }
  4038. }
  4039. #endif
  4040. // add any miscellaneous player ATK bonuses
  4041. if( sd && skill_id && (i = pc_skillatk_bonus(sd, skill_id))) {
  4042. ATK_ADDRATE(wd.damage, wd.damage2, i);
  4043. RE_ALLATK_ADDRATE(wd, i);
  4044. }
  4045. #ifdef RENEWAL
  4046. // In Renewal we only cardfix to the weapon and equip ATK
  4047. //Card Fix for attacker (sd), 2 is added to the "left" flag meaning "attacker cards only"
  4048. wd.weaponAtk += battle_calc_cardfix(BF_WEAPON, src, target, battle_skill_get_damage_properties(skill_id, wd.miscflag), right_element, left_element, wd.weaponAtk, 2, wd.flag);
  4049. wd.equipAtk += battle_calc_cardfix(BF_WEAPON, src, target, battle_skill_get_damage_properties(skill_id, wd.miscflag), right_element, left_element, wd.equipAtk, 2, wd.flag);
  4050. if( is_attack_left_handed(src, skill_id )) {
  4051. wd.weaponAtk2 += battle_calc_cardfix(BF_WEAPON, src, target, battle_skill_get_damage_properties(skill_id, wd.miscflag), right_element, left_element, wd.weaponAtk2, 3, wd.flag);
  4052. wd.equipAtk2 += battle_calc_cardfix(BF_WEAPON, src, target, battle_skill_get_damage_properties(skill_id, wd.miscflag), right_element, left_element, wd.equipAtk2, 3, wd.flag);
  4053. }
  4054. // final attack bonuses that aren't affected by cards
  4055. wd = battle_attack_sc_bonus(wd, src, skill_id);
  4056. if (sd) { //monsters, homuns and pets have their damage computed directly
  4057. wd.damage = wd.statusAtk + wd.weaponAtk + wd.equipAtk + wd.masteryAtk;
  4058. wd.damage2 = wd.statusAtk2 + wd.weaponAtk2 + wd.equipAtk2 + wd.masteryAtk2;
  4059. }
  4060. #else
  4061. // final attack bonuses that aren't affected by cards
  4062. wd = battle_attack_sc_bonus(wd, src, skill_id);
  4063. #endif
  4064. // check if attack ignores DEF
  4065. if (!attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_L) || !attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_R))
  4066. wd = battle_calc_defense_reduction(wd, src, target, skill_id, skill_lv);
  4067. wd = battle_calc_attack_post_defense(wd, src, target, skill_id, skill_lv);
  4068. }
  4069. else if(wd.div_ < 0) //Since the attack missed...
  4070. wd.div_ *= -1;
  4071. //WS_CARTTERMINATION never be missed because of flee, deals damage from BS_WEAPONRESEARCH [Cydh]
  4072. //NOTE: Idk the official behavior, if this damage can be reflected/adjusted or not
  4073. if (sd && skill_id == WS_CARTTERMINATION && wd.dmg_lv == ATK_FLEE && pc_checkskill(sd,BS_WEAPONRESEARCH)) {
  4074. wd.dmg_lv = ATK_DEF;
  4075. if(target_has_infinite_defense(target, skill_id))
  4076. return battle_calc_attack_plant(wd, src, target, skill_id, skill_lv);
  4077. wd.damage = pc_checkskill(sd,BS_WEAPONRESEARCH) * 2;
  4078. wd.damage2 = 0;
  4079. return wd;
  4080. }
  4081. #ifdef RENEWAL
  4082. if(!sd) // monsters only have a single ATK for element, in pre-renewal we also apply element to entire ATK on players [helvetica]
  4083. #endif
  4084. wd = battle_calc_element_damage(wd, src, target, skill_id, skill_lv);
  4085. if(skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS)
  4086. return wd; //Enough, rest is not needed.
  4087. #ifdef RENEWAL
  4088. if(is_attack_critical(wd, src, target, skill_id, skill_lv, false)) {
  4089. if(sd) // check for player so we don't crash out, monsters don't have bonus crit rates [helvetica]
  4090. wd.damage = (int)floor((double)(wd.damage * 1.4 * (100 + sd->bonus.crit_atk_rate)) / 100);
  4091. else
  4092. wd.damage = (int)floor((double)wd.damage * 1.4);
  4093. }
  4094. #endif
  4095. if(sd) {
  4096. if (skill_id != CR_SHIELDBOOMERANG) //Only Shield boomerang doesn't takes the Star Crumbs bonus.
  4097. ATK_ADD2(wd.damage, wd.damage2, wd.div_*sd->right_weapon.star, wd.div_*sd->left_weapon.star);
  4098. if (skill_id==MO_FINGEROFFENSIVE) { //The finger offensive spheres on moment of attack do count. [Skotlex]
  4099. ATK_ADD(wd.damage, wd.damage2, wd.div_*sd->spiritball_old*3);
  4100. } else {
  4101. ATK_ADD(wd.damage, wd.damage2, wd.div_*sd->spiritball*3);
  4102. }
  4103. if( skill_id == CR_SHIELDBOOMERANG || skill_id == PA_SHIELDCHAIN )
  4104. { //Refine bonus applies after cards and elements.
  4105. short index= sd->equip_index[EQI_HAND_L];
  4106. if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR )
  4107. ATK_ADD(wd.damage, wd.damage2, 10*sd->status.inventory[index].refine);
  4108. }
  4109. #ifndef RENEWAL
  4110. //Card Fix for attacker (sd), 2 is added to the "left" flag meaning "attacker cards only"
  4111. wd.damage += battle_calc_cardfix(BF_WEAPON, src, target, battle_skill_get_damage_properties(skill_id, wd.miscflag), right_element, left_element, wd.damage, 2, wd.flag);
  4112. if( is_attack_left_handed(src, skill_id ))
  4113. wd.damage2 += battle_calc_cardfix(BF_WEAPON, src, target, battle_skill_get_damage_properties(skill_id, wd.miscflag), right_element, left_element, wd.damage2, 3, wd.flag);
  4114. #endif
  4115. }
  4116. if(tsd) { // Card Fix for target (tsd), 2 is not added to the "left" flag meaning "target cards only"
  4117. switch(skill_id) { // These skills will do a card fix later
  4118. #ifdef RENEWAL
  4119. case NJ_ISSEN:
  4120. case ASC_BREAKER:
  4121. #endif
  4122. case CR_ACIDDEMONSTRATION:
  4123. case KO_HAPPOKUNAI:
  4124. break;
  4125. default:
  4126. wd.damage += battle_calc_cardfix(BF_WEAPON, src, target, battle_skill_get_damage_properties(skill_id, wd.miscflag), right_element, left_element, wd.damage, is_attack_left_handed(src, skill_id), wd.flag);
  4127. break;
  4128. }
  4129. }
  4130. // forced to neutral skills [helvetica]
  4131. // skills forced to neutral gain benefits from weapon element
  4132. // but final damage is considered "neutral" and resistances are applied again
  4133. switch (skill_id) {
  4134. case GN_CARTCANNON: // Cart Cannon gets forced to element of cannon ball (neutral or holy/shadow/ghost)
  4135. if (sd)
  4136. wd.damage = battle_attr_fix(src, target, wd.damage, sd->bonus.arrow_ele ? sd->bonus.arrow_ele : ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
  4137. else
  4138. wd.damage = battle_attr_fix(src, target, wd.damage, ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
  4139. break;
  4140. case MC_CARTREVOLUTION: // Cart Revolution gets forced to neutral element
  4141. wd.damage = battle_attr_fix(src,target,wd.damage,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv);
  4142. break;
  4143. }
  4144. // perform multihit calculations
  4145. #ifdef RENEWAL
  4146. damage_div_fix_renewal(wd, wd.div_);
  4147. #endif
  4148. damage_div_fix(wd.damage, wd.div_);
  4149. // only do 1 dmg to plant, no need to calculate rest
  4150. if(target_has_infinite_defense(target, skill_id))
  4151. return battle_calc_attack_plant(wd, src, target, skill_id, skill_lv);
  4152. wd = battle_calc_attack_left_right_hands(wd, src, target, skill_id, skill_lv);
  4153. wd = battle_calc_weapon_final_atk_modifiers(wd, src, target, skill_id, skill_lv);
  4154. switch (skill_id) { // These skills will do a GVG fix later
  4155. #ifdef RENEWAL
  4156. case NJ_ISSEN:
  4157. case ASC_BREAKER:
  4158. #endif
  4159. case CR_ACIDDEMONSTRATION:
  4160. case KO_HAPPOKUNAI:
  4161. return wd;
  4162. default:
  4163. wd = battle_calc_attack_gvg_bg(wd, src, target, skill_id, skill_lv);
  4164. break;
  4165. }
  4166. /* Skill damage adjustment */
  4167. #ifdef ADJUST_SKILL_DAMAGE
  4168. if ((skill_damage = battle_skill_damage(src, target, skill_id)) != 0)
  4169. ATK_ADDRATE(wd.damage, wd.damage2, skill_damage);
  4170. #endif
  4171. // Do reflect calculation after all atk modifier
  4172. // Don't reflect your own damage (Grand Cross)
  4173. if( wd.damage + wd.damage2 && src != target &&
  4174. (src->type != BL_SKILL ||
  4175. (src->type == BL_SKILL && ( skill_id == SG_SUN_WARM || skill_id == SG_MOON_WARM || skill_id == SG_STAR_WARM ))) )
  4176. {
  4177. int64 damage = wd.damage + wd.damage2, rdamage = 0;
  4178. struct status_data *sstatus = status_get_status_data(src);
  4179. int tick = gettick(), rdelay = 0;
  4180. rdamage = battle_calc_return_damage(target, src, &damage, wd.flag, skill_id, 0);
  4181. // Item reflect gets calculated first
  4182. if( rdamage > 0 ) {
  4183. //Use Reflect Shield to signal this kind of skill trigger. [Skotlex]
  4184. rdelay = clif_damage(src,src,tick,wd.amotion,sstatus->dmotion,rdamage,1,4,0);
  4185. if( tsd )
  4186. battle_drain(tsd,src,rdamage,rdamage,sstatus->race,is_boss(src));
  4187. battle_delay_damage(tick,wd.amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true);
  4188. skill_additional_effect(target,src,CR_REFLECTSHIELD,1,BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
  4189. }
  4190. // Calculate skill reflect damage separately
  4191. if( tsc ) {
  4192. struct status_data *tstatus = status_get_status_data(target);
  4193. rdamage = battle_calc_return_damage(target,src,&damage,wd.flag,skill_id,1);
  4194. if( rdamage > 0 ) {
  4195. if( tsc->data[SC_REFLECTDAMAGE] )
  4196. map_foreachinshootrange(battle_damage_area,target,skill_get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,wd.amotion,sstatus->dmotion,rdamage,tstatus->race);
  4197. else {
  4198. rdelay = clif_damage(src,src,tick,wd.amotion,sstatus->dmotion,rdamage,1,4,0);
  4199. if( tsd )
  4200. battle_drain(tsd,src,rdamage,rdamage,sstatus->race,is_boss(src));
  4201. // It appears that official servers give skill reflect damage a longer delay
  4202. battle_delay_damage(tick,wd.amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true);
  4203. skill_additional_effect(target,src,CR_REFLECTSHIELD,1,BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
  4204. }
  4205. }
  4206. }
  4207. }
  4208. return wd;
  4209. }
  4210. /*==========================================
  4211. * Calculate "magic"-type attacks and skills
  4212. *------------------------------------------
  4213. * Credits:
  4214. * Original coder DracoRPG
  4215. * Refined and optimized by helvetica
  4216. */
  4217. struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag)
  4218. {
  4219. int i, nk;
  4220. #ifdef ADJUST_SKILL_DAMAGE
  4221. int skill_damage;
  4222. #endif
  4223. short s_ele = 0;
  4224. unsigned int skillratio = 100; //Skill dmg modifiers.
  4225. TBL_PC *sd;
  4226. // TBL_PC *tsd;
  4227. struct status_change *sc, *tsc;
  4228. struct Damage ad;
  4229. struct status_data *sstatus = status_get_status_data(src);
  4230. struct status_data *tstatus = status_get_status_data(target);
  4231. struct {
  4232. unsigned imdef : 1;
  4233. unsigned infdef : 1;
  4234. } flag;
  4235. memset(&ad,0,sizeof(ad));
  4236. memset(&flag,0,sizeof(flag));
  4237. if(src==NULL || target==NULL)
  4238. {
  4239. nullpo_info(NLP_MARK);
  4240. return ad;
  4241. }
  4242. //Initial Values
  4243. ad.damage = 1;
  4244. ad.div_=skill_get_num(skill_id,skill_lv);
  4245. ad.amotion=skill_get_inf(skill_id)&INF_GROUND_SKILL?0:sstatus->amotion; //Amotion should be 0 for ground skills.
  4246. ad.dmotion=tstatus->dmotion;
  4247. ad.blewcount = skill_get_blewcount(skill_id,skill_lv);
  4248. ad.flag=BF_MAGIC|BF_SKILL;
  4249. ad.dmg_lv=ATK_DEF;
  4250. nk = skill_get_nk(skill_id);
  4251. flag.imdef = nk&NK_IGNORE_DEF?1:0;
  4252. sd = BL_CAST(BL_PC, src);
  4253. // tsd = BL_CAST(BL_PC, target);
  4254. sc = status_get_sc(src);
  4255. tsc = status_get_sc(target);
  4256. //Initialize variables that will be used afterwards
  4257. s_ele = skill_get_ele(skill_id, skill_lv);
  4258. if (s_ele == -1){ // pl=-1 : the skill takes the weapon's element
  4259. s_ele = sstatus->rhw.ele;
  4260. if( sd ){ //Summoning 10 talisman will endow your weapon
  4261. ARR_FIND(1, 6, i, sd->talisman[i] >= 10);
  4262. if( i < 5 ) s_ele = i;
  4263. }
  4264. }else if (s_ele == -2) //Use status element
  4265. s_ele = status_get_attack_sc_element(src,status_get_sc(src));
  4266. else if( s_ele == -3 ) //Use random element
  4267. s_ele = rnd()%ELE_MAX;
  4268. if( skill_id == SO_PSYCHIC_WAVE ) {
  4269. if( sc && sc->count ) {
  4270. if( sc->data[SC_HEATER_OPTION] ) s_ele = sc->data[SC_HEATER_OPTION]->val4;
  4271. else if( sc->data[SC_COOLER_OPTION] ) s_ele = sc->data[SC_COOLER_OPTION]->val4;
  4272. else if( sc->data[SC_BLAST_OPTION] ) s_ele = sc->data[SC_BLAST_OPTION]->val3;
  4273. else if( sc->data[SC_CURSED_SOIL_OPTION] ) s_ele = sc->data[SC_CURSED_SOIL_OPTION]->val4;
  4274. }
  4275. }
  4276. //Set miscellaneous data that needs be filled
  4277. if(sd) {
  4278. sd->state.arrow_atk = 0;
  4279. ad.blewcount += battle_blewcount_bonus(sd, skill_id);
  4280. }
  4281. //Skill Range Criteria
  4282. ad.flag |= battle_range_type(src, target, skill_id, skill_lv);
  4283. flag.infdef=(tstatus->mode&MD_PLANT?1:0);
  4284. if( target->type == BL_SKILL){
  4285. TBL_SKILL *su = (TBL_SKILL*)target;
  4286. if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) )
  4287. flag.infdef = 1;
  4288. }
  4289. switch(skill_id)
  4290. {
  4291. case MG_FIREWALL:
  4292. case NJ_KAENSIN:
  4293. ad.dmotion = 0; //No flinch animation.
  4294. if ( tstatus->def_ele == ELE_FIRE || battle_check_undead(tstatus->race, tstatus->def_ele) )
  4295. ad.blewcount = 0; //No knockback
  4296. break;
  4297. case PR_SANCTUARY:
  4298. ad.dmotion = 0; //No flinch animation.
  4299. break;
  4300. }
  4301. if(!flag.infdef && (
  4302. (tstatus->mode&MD_IGNOREMAGIC && ad.flag&(BF_MAGIC) ) //magic
  4303. )) flag.infdef = 1;
  4304. if (!flag.infdef) //No need to do the math for plants
  4305. {
  4306. #ifdef RENEWAL
  4307. ad.damage = 0; //reinitialize..
  4308. #endif
  4309. //MATK_RATE scales the damage. 100 = no change. 50 is halved, 200 is doubled, etc
  4310. #define MATK_RATE( a ) { ad.damage= ad.damage*(a)/100; }
  4311. //Adds dmg%. 100 = +100% (double) damage. 10 = +10% damage
  4312. #define MATK_ADDRATE( a ) { ad.damage+= ad.damage*(a)/100; }
  4313. //Adds an absolute value to damage. 100 = +100 damage
  4314. #define MATK_ADD( a ) { ad.damage+= a; }
  4315. switch (skill_id)
  4316. { //Calc base damage according to skill
  4317. case AL_HEAL:
  4318. case PR_BENEDICTIO:
  4319. case PR_SANCTUARY:
  4320. /**
  4321. * Arch Bishop
  4322. **/
  4323. case AB_HIGHNESSHEAL:
  4324. ad.damage = skill_calc_heal(src, target, skill_id, skill_lv, false);
  4325. break;
  4326. case PR_ASPERSIO:
  4327. ad.damage = 40;
  4328. break;
  4329. case ALL_RESURRECTION:
  4330. case PR_TURNUNDEAD:
  4331. //Undead check is on skill_castend_damageid code.
  4332. #ifdef RENEWAL
  4333. i = 10*skill_lv + sstatus->luk + sstatus->int_ + status_get_lv(src)
  4334. + 300 - 300*tstatus->hp/tstatus->max_hp;
  4335. #else
  4336. i = 20*skill_lv + sstatus->luk + sstatus->int_ + status_get_lv(src)
  4337. + 200 - 200*tstatus->hp/tstatus->max_hp;
  4338. #endif
  4339. if(i > 700) i = 700;
  4340. if(rnd()%1000 < i && !(tstatus->mode&MD_BOSS))
  4341. ad.damage = tstatus->hp;
  4342. else {
  4343. #ifdef RENEWAL
  4344. if (sstatus->matk_max > sstatus->matk_min) {
  4345. MATK_ADD(sstatus->matk_min+rnd()%(sstatus->matk_max-sstatus->matk_min));
  4346. } else {
  4347. MATK_ADD(sstatus->matk_min);
  4348. }
  4349. MATK_RATE(skill_lv);
  4350. #else
  4351. ad.damage = status_get_lv(src) + sstatus->int_ + skill_lv * 10;
  4352. #endif
  4353. }
  4354. break;
  4355. case PF_SOULBURN:
  4356. ad.damage = tstatus->sp * 2;
  4357. break;
  4358. /**
  4359. * Arch Bishop
  4360. **/
  4361. case AB_RENOVATIO:
  4362. ad.damage = status_get_lv(src) * 10 + sstatus->int_;
  4363. break;
  4364. default: {
  4365. if (sstatus->matk_max > sstatus->matk_min) {
  4366. MATK_ADD(sstatus->matk_min+rnd()%(sstatus->matk_max-sstatus->matk_min));
  4367. } else {
  4368. MATK_ADD(sstatus->matk_min);
  4369. }
  4370. if (nk&NK_SPLASHSPLIT) { // Divide MATK in case of multiple targets skill
  4371. if(mflag>0)
  4372. ad.damage/= mflag;
  4373. else
  4374. ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_id, skill_get_name(skill_id));
  4375. }
  4376. switch(skill_id){
  4377. case MG_NAPALMBEAT:
  4378. skillratio += skill_lv*10-30;
  4379. break;
  4380. case MG_FIREBALL:
  4381. #ifdef RENEWAL
  4382. skillratio += 20*skill_lv;
  4383. #else
  4384. skillratio += skill_lv*10-30;
  4385. #endif
  4386. break;
  4387. case MG_SOULSTRIKE:
  4388. if (battle_check_undead(tstatus->race,tstatus->def_ele))
  4389. skillratio += 5*skill_lv;
  4390. break;
  4391. case MG_FIREWALL:
  4392. skillratio -= 50;
  4393. break;
  4394. case MG_FIREBOLT:
  4395. case MG_COLDBOLT:
  4396. case MG_LIGHTNINGBOLT:
  4397. if ( sc && sc->data[SC_SPELLFIST] && mflag&BF_SHORT ) {
  4398. skillratio += (sc->data[SC_SPELLFIST]->val4 * 100) + (sc->data[SC_SPELLFIST]->val2 * 100) - 100;// val4 = used bolt level, val2 = used spellfist level. [Rytech]
  4399. ad.div_ = 1;// ad mods, to make it work similar to regular hits [Xazax]
  4400. ad.flag = BF_WEAPON|BF_SHORT;
  4401. ad.type = 0;
  4402. }
  4403. break;
  4404. case MG_THUNDERSTORM:
  4405. /**
  4406. * in Renewal Thunder Storm boost is 100% (in pre-re, 80%)
  4407. **/
  4408. #ifndef RENEWAL
  4409. skillratio -= 20;
  4410. #endif
  4411. break;
  4412. case MG_FROSTDIVER:
  4413. skillratio += 10*skill_lv;
  4414. break;
  4415. case AL_HOLYLIGHT:
  4416. skillratio += 25;
  4417. if (sd && sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_PRIEST)
  4418. skillratio *= 5; //Does 5x damage include bonuses from other skills?
  4419. break;
  4420. case AL_RUWACH:
  4421. skillratio += 45;
  4422. break;
  4423. case WZ_FROSTNOVA:
  4424. skillratio += (100+skill_lv*10)*2/3-100;
  4425. break;
  4426. case WZ_FIREPILLAR:
  4427. if (skill_lv > 10)
  4428. skillratio += 100;
  4429. else
  4430. skillratio -= 80;
  4431. break;
  4432. case WZ_SIGHTRASHER:
  4433. skillratio += 20*skill_lv;
  4434. break;
  4435. case WZ_WATERBALL:
  4436. skillratio += 30*skill_lv;
  4437. break;
  4438. case WZ_STORMGUST:
  4439. skillratio += 40*skill_lv;
  4440. break;
  4441. case HW_NAPALMVULCAN:
  4442. skillratio += 10*skill_lv-30;
  4443. break;
  4444. case SL_STIN:
  4445. skillratio += (tstatus->size!=SZ_SMALL?-99:10*skill_lv); //target size must be small (0) for full damage.
  4446. break;
  4447. case SL_STUN:
  4448. skillratio += (tstatus->size!=SZ_BIG?5*skill_lv:-99); //Full damage is dealt on small/medium targets
  4449. break;
  4450. case SL_SMA:
  4451. skillratio += -60 + status_get_lv(src); //Base damage is 40% + lv%
  4452. break;
  4453. case NJ_KOUENKA:
  4454. skillratio -= 10;
  4455. break;
  4456. case NJ_KAENSIN:
  4457. skillratio -= 50;
  4458. break;
  4459. case NJ_BAKUENRYU:
  4460. skillratio += 50*(skill_lv-1);
  4461. break;
  4462. case NJ_HYOUSYOURAKU:
  4463. skillratio += 50*skill_lv;
  4464. break;
  4465. case NJ_RAIGEKISAI:
  4466. skillratio += 60 + 40*skill_lv;
  4467. break;
  4468. case NJ_KAMAITACHI:
  4469. case NPC_ENERGYDRAIN:
  4470. skillratio += 100*skill_lv;
  4471. break;
  4472. case NPC_EARTHQUAKE:
  4473. skillratio += 100 +100*skill_lv +100*(skill_lv/2);
  4474. break;
  4475. #ifdef RENEWAL
  4476. case WZ_HEAVENDRIVE:
  4477. case WZ_METEOR:
  4478. skillratio += 25;
  4479. break;
  4480. case WZ_VERMILION:
  4481. {
  4482. int interval = 0, per = interval, ratio = per;
  4483. while( (per++) < skill_lv ){
  4484. ratio += interval;
  4485. if(per%3==0) interval += 20;
  4486. }
  4487. if( skill_lv > 9 )
  4488. ratio -= 10;
  4489. skillratio += ratio;
  4490. }
  4491. break;
  4492. case NJ_HUUJIN:
  4493. skillratio += 50;
  4494. break;
  4495. #else
  4496. case WZ_VERMILION:
  4497. skillratio += 20*skill_lv-20;
  4498. break;
  4499. #endif
  4500. /**
  4501. * Arch Bishop
  4502. **/
  4503. case AB_JUDEX:
  4504. skillratio += 200 + 20 * skill_lv;
  4505. RE_LVL_DMOD(100);
  4506. break;
  4507. case AB_ADORAMUS:
  4508. skillratio += 400 + 100 * skill_lv;
  4509. RE_LVL_DMOD(100);
  4510. break;
  4511. case AB_DUPLELIGHT_MAGIC:
  4512. skillratio += 100 + 20 * skill_lv;
  4513. break;
  4514. /**
  4515. * Warlock
  4516. **/
  4517. case WL_SOULEXPANSION:
  4518. skillratio += 300 + 100 * skill_lv + sstatus->int_;
  4519. RE_LVL_DMOD(100);
  4520. break;
  4521. case WL_FROSTMISTY:
  4522. skillratio += 100 + 100 * skill_lv;
  4523. RE_LVL_DMOD(100);
  4524. break;
  4525. case WL_JACKFROST:
  4526. if( tsc && tsc->data[SC_FREEZING] ){
  4527. skillratio += 900 + 300 * skill_lv;
  4528. RE_LVL_DMOD(100);
  4529. }else{
  4530. skillratio += 400 + 100 * skill_lv;
  4531. RE_LVL_DMOD(150);
  4532. }
  4533. break;
  4534. case WL_DRAINLIFE:
  4535. skillratio = 200 * skill_lv + sstatus->int_;
  4536. RE_LVL_DMOD(100);
  4537. break;
  4538. case WL_CRIMSONROCK:
  4539. skillratio += 1200 + 300 * skill_lv;
  4540. RE_LVL_DMOD(100);
  4541. break;
  4542. case WL_HELLINFERNO:
  4543. skillratio = 300 * skill_lv;
  4544. RE_LVL_DMOD(100);
  4545. // Shadow: MATK [{( Skill Level x 300 ) x ( Caster Base Level / 100 ) x 4/5 }] %
  4546. // Fire : MATK [{( Skill Level x 300 ) x ( Caster Base Level / 100 ) /5 }] %
  4547. if( mflag&ELE_DARK ){ skillratio *= 4; s_ele = ELE_DARK; }
  4548. skillratio /= 5;
  4549. break;
  4550. case WL_COMET:
  4551. i = ( sc ? distance_xy(target->x, target->y, sc->comet_x, sc->comet_y) : 8 );
  4552. if( i <= 3 )
  4553. skillratio += 2400 + 500 * skill_lv; // 7 x 7 cell
  4554. else if( i <= 5 )
  4555. skillratio += 1900 + 500 * skill_lv; // 11 x 11 cell
  4556. else if( i <= 7 )
  4557. skillratio += 1400 + 500 * skill_lv; // 15 x 15 cell
  4558. else
  4559. skillratio += 900 + 500 * skill_lv; // 19 x 19 cell
  4560. if( sd && sd->status.party_id ){
  4561. struct map_session_data* psd;
  4562. int p_sd[5] = {0, 0, 0, 0, 0}, c; // just limit it to 5
  4563. c = 0;
  4564. memset (p_sd, 0, sizeof(p_sd));
  4565. party_foreachsamemap(skill_check_condition_char_sub, sd, 3, &sd->bl, &c, &p_sd, skill_id);
  4566. c = ( c > 1 ? rand()%c : 0 );
  4567. if( (psd = map_id2sd(p_sd[c])) && pc_checkskill(psd,WL_COMET) > 0 ){
  4568. skillratio = skill_lv * 400; //MATK [{( Skill Level x 400 ) x ( Caster's Base Level / 120 )} + 2500 ] %
  4569. RE_LVL_DMOD(120);
  4570. skillratio += 2500;
  4571. status_zap(&psd->bl, 0, skill_get_sp(skill_id, skill_lv) / 2);
  4572. }
  4573. }
  4574. break;
  4575. case WL_CHAINLIGHTNING_ATK:
  4576. skillratio += 100 + 300 * skill_lv;
  4577. RE_LVL_DMOD(100);
  4578. break;
  4579. case WL_EARTHSTRAIN:
  4580. skillratio += 1900 + 100 * skill_lv;
  4581. RE_LVL_DMOD(100);
  4582. break;
  4583. case WL_TETRAVORTEX_FIRE:
  4584. case WL_TETRAVORTEX_WATER:
  4585. case WL_TETRAVORTEX_WIND:
  4586. case WL_TETRAVORTEX_GROUND:
  4587. skillratio += 400 + 500 * skill_lv;
  4588. break;
  4589. case WL_SUMMON_ATK_FIRE:
  4590. case WL_SUMMON_ATK_WATER:
  4591. case WL_SUMMON_ATK_WIND:
  4592. case WL_SUMMON_ATK_GROUND:
  4593. skillratio = skill_lv * (status_get_lv(src) + ( sd ? sd->status.job_level : 50 ));// This is close to official, but lacking a little info to finalize. [Rytech]
  4594. RE_LVL_DMOD(100);
  4595. break;
  4596. case LG_RAYOFGENESIS:
  4597. {
  4598. uint16 lv = skill_lv;
  4599. int bandingBonus = 0;
  4600. if( sc && sc->data[SC_BANDING] )
  4601. bandingBonus = 200 * (sd ? skill_check_pc_partner(sd,skill_id,&lv,skill_get_splash(skill_id,skill_lv),0) : 1);
  4602. skillratio = ((300 * skill_lv) + bandingBonus) * (sd ? sd->status.job_level : 1) / 25;
  4603. }
  4604. break;
  4605. case LG_SHIELDSPELL:// [(Casters Base Level x 4) + (Shield MDEF x 100) + (Casters INT x 2)] %
  4606. if( sd ) {
  4607. skillratio = status_get_lv(src) * 4 + sd->bonus.shieldmdef * 100 + status_get_int(src) * 2;
  4608. } else
  4609. skillratio += 1900; //2000%
  4610. break;
  4611. case WM_METALICSOUND:
  4612. skillratio += 120 * skill_lv + 60 * ( sd? pc_checkskill(sd, WM_LESSON) : 10 ) - 100;
  4613. break;
  4614. /*case WM_SEVERE_RAINSTORM:
  4615. skillratio += 50 * skill_lv;
  4616. break;
  4617. WM_SEVERE_RAINSTORM just set a unit place,
  4618. refer to WM_SEVERE_RAINSTORM_MELEE to set the formula.
  4619. */
  4620. case WM_REVERBERATION_MAGIC:
  4621. // MATK [{(Skill Level x 100) + 100} x Casters Base Level / 100] %
  4622. skillratio += 100 * (sd ? pc_checkskill(sd, WM_REVERBERATION) : 1);
  4623. RE_LVL_DMOD(100);
  4624. break;
  4625. case SO_FIREWALK:
  4626. skillratio = 300;
  4627. RE_LVL_DMOD(100);
  4628. if( sc && sc->data[SC_HEATER_OPTION] )
  4629. skillratio += sc->data[SC_HEATER_OPTION]->val3;
  4630. break;
  4631. case SO_ELECTRICWALK:
  4632. skillratio = 300;
  4633. RE_LVL_DMOD(100);
  4634. if( sc && sc->data[SC_BLAST_OPTION] )
  4635. skillratio += sd ? sd->status.job_level / 2 : 0;
  4636. break;
  4637. case SO_EARTHGRAVE:
  4638. skillratio = ( 200 * ( sd ? pc_checkskill(sd, SA_SEISMICWEAPON) : 10 ) + sstatus->int_ * skill_lv );
  4639. RE_LVL_DMOD(100);
  4640. if( sc && sc->data[SC_CURSED_SOIL_OPTION] )
  4641. skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2;
  4642. break;
  4643. case SO_DIAMONDDUST:
  4644. skillratio = ( 200 * ( sd ? pc_checkskill(sd, SA_FROSTWEAPON) : 10 ) + sstatus->int_ * skill_lv );
  4645. RE_LVL_DMOD(100);
  4646. if( sc && sc->data[SC_COOLER_OPTION] )
  4647. skillratio += sc->data[SC_COOLER_OPTION]->val3;
  4648. break;
  4649. case SO_POISON_BUSTER:
  4650. skillratio += 1100 + 300 * skill_lv;
  4651. if( sc && sc->data[SC_CURSED_SOIL_OPTION] )
  4652. skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2;
  4653. break;
  4654. case SO_PSYCHIC_WAVE:
  4655. skillratio += -100 + skill_lv * 70 + (sstatus->int_ * 3);
  4656. RE_LVL_DMOD(100);
  4657. if( sc ){
  4658. if( sc->data[SC_HEATER_OPTION] )
  4659. skillratio += sc->data[SC_HEATER_OPTION]->val3;
  4660. else if(sc->data[SC_COOLER_OPTION] )
  4661. skillratio += sc->data[SC_COOLER_OPTION]->val3;
  4662. else if(sc->data[SC_BLAST_OPTION] )
  4663. skillratio += sc->data[SC_BLAST_OPTION]->val2;
  4664. else if(sc->data[SC_CURSED_SOIL_OPTION] )
  4665. skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val3;
  4666. }
  4667. break;
  4668. case SO_VARETYR_SPEAR: //MATK [{( Endow Tornado skill level x 50 ) + ( Caster INT x Varetyr Spear Skill level )} x Caster Base Level / 100 ] %
  4669. skillratio = status_get_int(src) * skill_lv + ( sd ? pc_checkskill(sd, SA_LIGHTNINGLOADER) * 50 : 0 );
  4670. RE_LVL_DMOD(100);
  4671. if( sc && sc->data[SC_BLAST_OPTION] )
  4672. skillratio += sd ? sd->status.job_level * 5 : 0;
  4673. break;
  4674. case SO_CLOUD_KILL:
  4675. skillratio += -100 + skill_lv * 40;
  4676. RE_LVL_DMOD(100);
  4677. if( sc && sc->data[SC_CURSED_SOIL_OPTION] )
  4678. skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2;
  4679. break;
  4680. case GN_DEMONIC_FIRE:
  4681. if( skill_lv > 20)
  4682. { // Fire expansion Lv.2
  4683. skillratio += 110 + 20 * (skill_lv - 20) + status_get_int(src) * 3; // Need official INT bonus. [LimitLine]
  4684. }
  4685. else if( skill_lv > 10 )
  4686. { // Fire expansion Lv.1
  4687. skillratio += 110 + 20 * (skill_lv - 10) / 2;
  4688. }
  4689. else
  4690. skillratio += 110 + 20 * skill_lv;
  4691. break;
  4692. // Magical Elemental Spirits Attack Skills
  4693. case EL_FIRE_MANTLE:
  4694. case EL_WATER_SCREW:
  4695. skillratio += 900;
  4696. break;
  4697. case EL_FIRE_ARROW:
  4698. case EL_ROCK_CRUSHER_ATK:
  4699. skillratio += 200;
  4700. break;
  4701. case EL_FIRE_BOMB:
  4702. case EL_ICE_NEEDLE:
  4703. case EL_HURRICANE_ATK:
  4704. skillratio += 400;
  4705. break;
  4706. case EL_FIRE_WAVE:
  4707. case EL_TYPOON_MIS_ATK:
  4708. skillratio += 1100;
  4709. break;
  4710. case MH_ERASER_CUTTER:
  4711. if(skill_lv%2) skillratio += 400; //600:800:1000
  4712. else skillratio += 700; //1000:1200
  4713. skillratio += 100 * skill_lv;
  4714. break;
  4715. case MH_XENO_SLASHER:
  4716. if(skill_lv%2) skillratio += 350 + 50 * skill_lv; //500:600:700
  4717. else skillratio += 400 + 100 * skill_lv; //700:900
  4718. break;
  4719. case MH_HEILIGE_STANGE:
  4720. skillratio += 400 + 250 * skill_lv;
  4721. skillratio = (skillratio * status_get_lv(src))/150;
  4722. break;
  4723. case MH_POISON_MIST:
  4724. skillratio += -100 + 40 * skill_lv * status_get_lv(src) / 100;
  4725. break;
  4726. }
  4727. MATK_RATE(skillratio);
  4728. //Constant/misc additions from skills
  4729. if (skill_id == WZ_FIREPILLAR)
  4730. MATK_ADD(50);
  4731. }
  4732. }
  4733. #ifdef RENEWAL
  4734. switch(skill_id) { // These skills will do a card fix later
  4735. case CR_ACIDDEMONSTRATION:
  4736. case ASC_BREAKER:
  4737. break;
  4738. default:
  4739. ad.damage += battle_calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag);
  4740. }
  4741. #endif
  4742. if(sd) {
  4743. //Damage bonuses
  4744. if ((i = pc_skillatk_bonus(sd, skill_id)))
  4745. ad.damage += (int64)ad.damage*i/100;
  4746. //Ignore Defense?
  4747. if (!flag.imdef && (
  4748. sd->bonus.ignore_mdef_ele & ( 1 << tstatus->def_ele ) ||
  4749. sd->bonus.ignore_mdef_race & ( 1 << tstatus->race ) ||
  4750. sd->bonus.ignore_mdef_race & ( is_boss(target) ? 1 << RC_BOSS : 1 << RC_NONBOSS )
  4751. ))
  4752. flag.imdef = 1;
  4753. }
  4754. if(!flag.imdef){
  4755. defType mdef = tstatus->mdef;
  4756. int mdef2= tstatus->mdef2;
  4757. #ifdef RENEWAL
  4758. if(tsc && tsc->data[SC_ASSUMPTIO])
  4759. mdef <<= 1; // only eMDEF is doubled
  4760. #endif
  4761. if(sd) {
  4762. i = sd->ignore_mdef[is_boss(target)?RC_BOSS:RC_NONBOSS];
  4763. i+= sd->ignore_mdef[tstatus->race];
  4764. if (i)
  4765. {
  4766. if (i > 100) i = 100;
  4767. mdef -= mdef * i/100;
  4768. //mdef2-= mdef2* i/100;
  4769. }
  4770. }
  4771. #ifdef RENEWAL
  4772. /**
  4773. * RE MDEF Reduction
  4774. * Damage = Magic Attack * (1000+eMDEF)/(1000+eMDEF) - sMDEF
  4775. **/
  4776. if (mdef < -99)
  4777. mdef = -99; // Avoid divide by 0
  4778. ad.damage = ad.damage * (1000 + mdef) / (1000 + mdef * 10) - mdef2;
  4779. #else
  4780. if(battle_config.magic_defense_type)
  4781. ad.damage = ad.damage - mdef*battle_config.magic_defense_type - mdef2;
  4782. else
  4783. ad.damage = ad.damage * (100-mdef)/100 - mdef2;
  4784. #endif
  4785. }
  4786. if (skill_id == NPC_EARTHQUAKE)
  4787. { //Adds atk2 to the damage, should be influenced by number of hits and skill-ratio, but not mdef reductions. [Skotlex]
  4788. //Also divide the extra bonuses from atk2 based on the number in range [Kevin]
  4789. if(mflag>0)
  4790. ad.damage+= (sstatus->rhw.atk2*skillratio/100)/mflag;
  4791. else
  4792. ShowError("Zero range by %d:%s, divide per 0 avoided!\n", skill_id, skill_get_name(skill_id));
  4793. }
  4794. if(ad.damage<1)
  4795. ad.damage=1;
  4796. else if(sc){//only applies when hit
  4797. // TODO: there is another factor that contribute with the damage and need to be formulated. [malufett]
  4798. switch(skill_id){
  4799. case MG_LIGHTNINGBOLT:
  4800. case MG_THUNDERSTORM:
  4801. case MG_FIREBOLT:
  4802. case MG_FIREWALL:
  4803. case MG_COLDBOLT:
  4804. case MG_FROSTDIVER:
  4805. case WZ_EARTHSPIKE:
  4806. case WZ_HEAVENDRIVE:
  4807. if(sc->data[SC_GUST_OPTION] || sc->data[SC_PETROLOGY_OPTION]
  4808. || sc->data[SC_PYROTECHNIC_OPTION] || sc->data[SC_AQUAPLAY_OPTION])
  4809. ad.damage += (6 + sstatus->int_/4) + max(sstatus->dex-10,0)/30;
  4810. break;
  4811. }
  4812. }
  4813. if (!(nk&NK_NO_ELEFIX))
  4814. ad.damage=battle_attr_fix(src, target, ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv);
  4815. if( skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS )
  4816. { //Apply the physical part of the skill's damage. [Skotlex]
  4817. struct Damage wd = battle_calc_weapon_attack(src,target,skill_id,skill_lv,mflag);
  4818. ad.damage = battle_attr_fix(src, target, wd.damage + ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv) * (100 + 40*skill_lv)/100;
  4819. if( src == target )
  4820. {
  4821. if( src->type == BL_PC )
  4822. ad.damage = ad.damage/2;
  4823. else
  4824. ad.damage = 0;
  4825. }
  4826. }
  4827. #ifndef RENEWAL
  4828. ad.damage += battle_calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag);
  4829. #endif
  4830. }
  4831. damage_div_fix(ad.damage, ad.div_);
  4832. if (flag.infdef && ad.damage)
  4833. ad.damage = ad.damage>0?1:-1;
  4834. switch(skill_id) { // These skills will do a GVG fix later
  4835. #ifdef RENEWAL
  4836. case ASC_BREAKER:
  4837. #endif
  4838. case CR_ACIDDEMONSTRATION:
  4839. return ad;
  4840. default:
  4841. ad.damage=battle_calc_damage(src,target,&ad,ad.damage,skill_id,skill_lv);
  4842. if( map_flag_gvg2(target->m) )
  4843. ad.damage=battle_calc_gvg_damage(src,target,ad.damage,ad.div_,skill_id,skill_lv,ad.flag);
  4844. else if( map[target->m].flag.battleground )
  4845. ad.damage=battle_calc_bg_damage(src,target,ad.damage,ad.div_,skill_id,skill_lv,ad.flag);
  4846. }
  4847. switch( skill_id ) { /* post-calc modifiers */
  4848. case SO_VARETYR_SPEAR: { // Physical damage.
  4849. struct Damage wd = battle_calc_weapon_attack(src,target,skill_id,skill_lv,mflag);
  4850. if(!flag.infdef && ad.damage > 1)
  4851. ad.damage += wd.damage;
  4852. break;
  4853. }
  4854. //case HM_ERASER_CUTTER:
  4855. }
  4856. /* Skill damage adjustment */
  4857. #ifdef ADJUST_SKILL_DAMAGE
  4858. if ((skill_damage = battle_skill_damage(src,target,skill_id)) != 0)
  4859. MATK_ADDRATE(skill_damage);
  4860. #endif
  4861. return ad;
  4862. }
  4863. /*==========================================
  4864. * Calculate "misc"-type attacks and skills
  4865. *------------------------------------------
  4866. * Credits:
  4867. * Original coder Skoltex
  4868. * Refined and optimized by helvetica
  4869. */
  4870. struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag)
  4871. {
  4872. int skill;
  4873. #ifdef ADJUST_SKILL_DAMAGE
  4874. int skill_damage;
  4875. #endif
  4876. short i, nk;
  4877. short s_ele;
  4878. struct map_session_data *sd, *tsd;
  4879. struct Damage md; //DO NOT CONFUSE with md of mob_data!
  4880. struct status_data *sstatus = status_get_status_data(src);
  4881. struct status_data *tstatus = status_get_status_data(target);
  4882. memset(&md,0,sizeof(md));
  4883. if( src == NULL || target == NULL ){
  4884. nullpo_info(NLP_MARK);
  4885. return md;
  4886. }
  4887. //Some initial values
  4888. md.amotion=skill_get_inf(skill_id)&INF_GROUND_SKILL?0:sstatus->amotion;
  4889. md.dmotion=tstatus->dmotion;
  4890. md.div_=skill_get_num( skill_id,skill_lv );
  4891. md.blewcount=skill_get_blewcount(skill_id,skill_lv);
  4892. md.dmg_lv=ATK_DEF;
  4893. md.flag=BF_MISC|BF_SKILL;
  4894. nk = skill_get_nk(skill_id);
  4895. sd = BL_CAST(BL_PC, src);
  4896. tsd = BL_CAST(BL_PC, target);
  4897. if(sd) {
  4898. sd->state.arrow_atk = 0;
  4899. md.blewcount += battle_blewcount_bonus(sd, skill_id);
  4900. }
  4901. s_ele = skill_get_ele(skill_id, skill_lv);
  4902. if (s_ele < 0 && s_ele != -3) //Attack that takes weapon's element for misc attacks? Make it neutral [Skotlex]
  4903. s_ele = ELE_NEUTRAL;
  4904. else if (s_ele == -3) //Use random element
  4905. s_ele = rnd()%ELE_MAX;
  4906. //Skill Range Criteria
  4907. md.flag |= battle_range_type(src, target, skill_id, skill_lv);
  4908. switch( skill_id )
  4909. {
  4910. #ifdef RENEWAL
  4911. case HT_LANDMINE:
  4912. case MA_LANDMINE:
  4913. case HT_BLASTMINE:
  4914. case HT_CLAYMORETRAP:
  4915. md.damage = skill_lv * sstatus->dex * (3+status_get_lv(src)/100) * (1+sstatus->int_/35);
  4916. md.damage += md.damage * (rnd()%20-10) / 100;
  4917. md.damage += 40 * (sd?pc_checkskill(sd,RA_RESEARCHTRAP):0);
  4918. break;
  4919. #else
  4920. case HT_LANDMINE:
  4921. case MA_LANDMINE:
  4922. md.damage=skill_lv*(sstatus->dex+75)*(100+sstatus->int_)/100;
  4923. break;
  4924. case HT_BLASTMINE:
  4925. md.damage=skill_lv*(sstatus->dex/2+50)*(100+sstatus->int_)/100;
  4926. break;
  4927. case HT_CLAYMORETRAP:
  4928. md.damage=skill_lv*(sstatus->dex/2+75)*(100+sstatus->int_)/100;
  4929. break;
  4930. #endif
  4931. case HT_BLITZBEAT:
  4932. case SN_FALCONASSAULT:
  4933. //Blitz-beat Damage.
  4934. if(!sd || (skill = pc_checkskill(sd,HT_STEELCROW)) <= 0)
  4935. skill=0;
  4936. md.damage=(sstatus->dex/10+sstatus->int_/2+skill*3+40)*2;
  4937. if(mflag > 1) //Autocasted Blitz.
  4938. nk|=NK_SPLASHSPLIT;
  4939. if (skill_id == SN_FALCONASSAULT)
  4940. {
  4941. //Div fix of Blitzbeat
  4942. skill = skill_get_num(HT_BLITZBEAT, 5);
  4943. damage_div_fix(md.damage, skill);
  4944. //Falcon Assault Modifier
  4945. md.damage=(int64)md.damage*(150+70*skill_lv)/100;
  4946. }
  4947. break;
  4948. case TF_THROWSTONE:
  4949. md.damage=50;
  4950. break;
  4951. case BA_DISSONANCE:
  4952. md.damage=30+skill_lv*10;
  4953. if (sd)
  4954. md.damage+= 3*pc_checkskill(sd,BA_MUSICALLESSON);
  4955. break;
  4956. case NPC_SELFDESTRUCTION:
  4957. md.damage = sstatus->hp;
  4958. break;
  4959. case NPC_SMOKING:
  4960. md.damage=3;
  4961. break;
  4962. case NPC_DARKBREATH:
  4963. md.damage = 500 + (skill_lv-1)*1000 + rnd()%1000;
  4964. if(md.damage > 9999) md.damage = 9999;
  4965. break;
  4966. case PA_PRESSURE:
  4967. md.damage=500+300*skill_lv;
  4968. break;
  4969. case PA_GOSPEL:
  4970. md.damage = 1+rnd()%9999;
  4971. break;
  4972. case CR_ACIDDEMONSTRATION:
  4973. #ifdef RENEWAL
  4974. // Official Renewal formula [helvetica]
  4975. // damage = 7 * ((atk + matk)/skill level) * (target vit/100)
  4976. // skill is a "forced neutral" type skill, it benefits from weapon element but final damage
  4977. // is considered "neutral" for purposes of resistances
  4978. {
  4979. struct Damage atk = battle_calc_weapon_attack(src, target, skill_id, skill_lv, 0);
  4980. struct Damage matk = battle_calc_magic_attack(src, target, skill_id, skill_lv, 0);
  4981. md.damage = 7 * ((atk.damage/skill_lv + matk.damage/skill_lv) * tstatus->vit / 100 );
  4982. // AD benefits from endow/element but damage is forced back to neutral
  4983. battle_attr_fix(src, target, md.damage, ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
  4984. }
  4985. #else
  4986. if(tstatus->vit+sstatus->int_) //crash fix
  4987. md.damage = (int)((int64)7*tstatus->vit*sstatus->int_*sstatus->int_ / (10*(tstatus->vit+sstatus->int_)));
  4988. else
  4989. md.damage = 0;
  4990. if (tsd) md.damage>>=1;
  4991. #endif
  4992. break;
  4993. case NJ_ZENYNAGE:
  4994. case KO_MUCHANAGE:
  4995. md.damage = skill_get_zeny(skill_id ,skill_lv);
  4996. if (!md.damage) md.damage = 2;
  4997. md.damage = rand()%md.damage + md.damage / (skill_id==NJ_ZENYNAGE?1:2) ;
  4998. if (is_boss(target))
  4999. md.damage=md.damage / (skill_id==NJ_ZENYNAGE?3:2);
  5000. else if (tsd) // need confirmation for KO_MUCHANAGE
  5001. md.damage=md.damage/2;
  5002. break;
  5003. #ifdef RENEWAL
  5004. case NJ_ISSEN:
  5005. // Official Renewal formula [helvetica]
  5006. // base damage = currenthp + ((atk * currenthp * skill level) / maxhp)
  5007. // final damage = base damage + ((mirror image count + 1) / 5 * base damage) - (edef + sdef)
  5008. // modified def formula
  5009. {
  5010. short totaldef;
  5011. struct Damage atk = battle_calc_weapon_attack(src, target, skill_id, skill_lv, 0);
  5012. struct status_change *sc = status_get_sc(src);
  5013. md.damage = (int64)sstatus->hp + (atk.damage * (int64)sstatus->hp * skill_lv) / (int64)sstatus->max_hp;
  5014. if (sc && sc->data[SC_BUNSINJYUTSU] && (i=sc->data[SC_BUNSINJYUTSU]->val2) > 0) { // mirror image bonus only occurs if active
  5015. md.div_ = -( i + 2 ); // mirror image count + 2
  5016. md.damage += (md.damage * (((i + 1) * 10) / 5)) / 10;
  5017. }
  5018. // modified def reduction, final damage = base damage - (edef + sdef)
  5019. totaldef = tstatus->def2 + (short)status_get_def(target);
  5020. md.damage -= totaldef;
  5021. }
  5022. break;
  5023. #endif
  5024. case GS_FLING:
  5025. md.damage = sd?sd->status.job_level:status_get_lv(src);
  5026. break;
  5027. case GS_GROUNDDRIFT:
  5028. // Official formula [helvetica]
  5029. // damage = 50 * skill level
  5030. // fixed damage, ignores DEF and benefits from weapon +%ATK cards
  5031. md.damage = 50*skill_lv;
  5032. md.damage += battle_calc_cardfix(BF_WEAPON, src, target, nk, s_ele, 0, md.damage, 0, md.flag|NK_NO_CARDFIX_DEF); // ground drift benefits from weapon atk cards, ignore DEF cards so we don't apply twice
  5033. break;
  5034. case HVAN_EXPLOSION: //[orn]
  5035. md.damage = (int64)sstatus->max_hp * (50 + 50 * skill_lv) / 100;
  5036. break ;
  5037. case ASC_BREAKER:
  5038. #ifdef RENEWAL
  5039. // Official Renewal formula [helvetica]
  5040. // damage = ((atk + matk) * (3 + (.5 * skill level))) - (edef + sdef + emdef + smdef)
  5041. // atk part takes weapon element, matk part is non-elemental
  5042. // modified def formula
  5043. {
  5044. short totaldef, totalmdef;
  5045. struct Damage atk, matk;
  5046. atk = battle_calc_weapon_attack(src, target, skill_id, skill_lv, 0);
  5047. nk|=NK_NO_ELEFIX; // atk part takes on weapon element, matk part is non-elemental
  5048. matk = battle_calc_magic_attack(src, target, skill_id, skill_lv, 0);
  5049. // (atk + matk) * (3 + (.5 * skill level))
  5050. md.damage = ((30 + (5 * skill_lv)) * (atk.damage + matk.damage)) / 10;
  5051. // modified def reduction, final damage = base damage - (edef + sdef + emdef + smdef)
  5052. totaldef = tstatus->def2 + (short)status_get_def(target);
  5053. totalmdef = tstatus->mdef + tstatus->mdef2;
  5054. md.damage -= totaldef + totalmdef;
  5055. }
  5056. #else
  5057. md.damage = 500+rnd()%500 + 5*skill_lv * sstatus->int_;
  5058. nk|=NK_IGNORE_FLEE|NK_NO_ELEFIX; //These two are not properties of the weapon based part.
  5059. #endif
  5060. break;
  5061. case HW_GRAVITATION:
  5062. md.damage = 200+200*skill_lv;
  5063. md.dmotion = 0; //No flinch animation.
  5064. break;
  5065. case NPC_EVILLAND:
  5066. md.damage = skill_calc_heal(src,target,skill_id,skill_lv,false);
  5067. break;
  5068. case RK_DRAGONBREATH:
  5069. md.damage = ((status_get_hp(src) / 50) + (status_get_max_sp(src) / 4)) * skill_lv;
  5070. RE_LVL_MDMOD(150);
  5071. if (sd) md.damage = (int64)md.damage * (100 + 5 * (pc_checkskill(sd,RK_DRAGONTRAINING) - 1)) / 100;
  5072. md.flag |= BF_LONG|BF_WEAPON;
  5073. break;
  5074. case RA_CLUSTERBOMB:
  5075. case RA_FIRINGTRAP:
  5076. case RA_ICEBOUNDTRAP:
  5077. md.damage = skill_lv * sstatus->dex + sstatus->int_ * 5 ;
  5078. RE_LVL_TMDMOD();
  5079. if(sd)
  5080. {
  5081. int researchskill_lv = pc_checkskill(sd,RA_RESEARCHTRAP);
  5082. if(researchskill_lv)
  5083. md.damage = (int64)md.damage * 20 * researchskill_lv / (skill_id == RA_CLUSTERBOMB?50:100);
  5084. else
  5085. md.damage = 0;
  5086. }else
  5087. md.damage = (int64)md.damage * 200 / (skill_id == RA_CLUSTERBOMB?50:100);
  5088. break;
  5089. case NC_SELFDESTRUCTION:
  5090. {
  5091. short totaldef = tstatus->def2 + (short)status_get_def(target);
  5092. md.damage = ( (sd?pc_checkskill(sd,NC_MAINFRAME):10) + 8 ) * ( skill_lv + 1 ) * ( status_get_sp(src) + sstatus->vit );
  5093. RE_LVL_MDMOD(100);
  5094. md.damage += status_get_hp(src) - totaldef;
  5095. }
  5096. break;
  5097. case GN_THORNS_TRAP:
  5098. md.damage = 100 + 200 * skill_lv + sstatus->int_;
  5099. break;
  5100. case GN_HELLS_PLANT_ATK:
  5101. //[{( Hell Plant Skill Level x Casters Base Level ) x 10 } + {( Casters INT x 7 ) / 2 } x { 18 + ( Casters Job Level / 4 )] x ( 5 / ( 10 - Summon Flora Skill Level ))
  5102. md.damage = ( skill_lv * status_get_lv(src) * 10 ) + ( sstatus->int_ * 7 / 2 ) * ( 18 + (sd?sd->status.job_level:0) / 4 ) * ( 5 / (10 - (sd?pc_checkskill(sd,AM_CANNIBALIZE):0)) );
  5103. break;
  5104. case KO_HAPPOKUNAI:
  5105. {
  5106. struct Damage wd = battle_calc_weapon_attack(src,target,skill_id,skill_lv,mflag);
  5107. short totaldef = tstatus->def2 + (short)status_get_def(target);
  5108. md.damage = (int64)wd.damage * 60 * (5 + skill_lv) / 100;
  5109. md.damage -= totaldef;
  5110. }
  5111. break;
  5112. case KO_MAKIBISHI:
  5113. md.damage = 20 * skill_lv;
  5114. break;
  5115. }
  5116. if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets
  5117. if(mflag>0)
  5118. md.damage/= mflag;
  5119. else
  5120. ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_id, skill_get_name(skill_id));
  5121. }
  5122. damage_div_fix(md.damage, md.div_);
  5123. if (!(nk&NK_IGNORE_FLEE))
  5124. {
  5125. struct status_change *sc = status_get_sc(target);
  5126. i = 0; //Temp for "hit or no hit"
  5127. if(sc && sc->opt1 && sc->opt1 != OPT1_STONEWAIT && sc->opt1 != OPT1_BURNING)
  5128. i = 1;
  5129. else {
  5130. short
  5131. flee = tstatus->flee,
  5132. #ifdef RENEWAL
  5133. hitrate = 0; //Default hitrate
  5134. #else
  5135. hitrate = 80; //Default hitrate
  5136. #endif
  5137. if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) {
  5138. unsigned char attacker_count; //256 max targets should be a sane max
  5139. attacker_count = unit_counttargeted(target);
  5140. if(attacker_count >= battle_config.agi_penalty_count)
  5141. {
  5142. if (battle_config.agi_penalty_type == 1)
  5143. flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100;
  5144. else //asume type 2: absolute reduction
  5145. flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num;
  5146. if(flee < 1) flee = 1;
  5147. }
  5148. }
  5149. hitrate+= sstatus->hit - flee;
  5150. #ifdef RENEWAL
  5151. if( sd ) //in Renewal hit bonus from Vultures Eye is not anymore shown in status window
  5152. hitrate += pc_checkskill(sd,AC_VULTURE);
  5153. #endif
  5154. hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate);
  5155. if(rnd()%100 < hitrate)
  5156. i = 1;
  5157. }
  5158. if (!i) {
  5159. md.damage = 0;
  5160. md.dmg_lv=ATK_FLEE;
  5161. }
  5162. }
  5163. md.damage += battle_calc_cardfix(BF_MISC, src, target, nk, s_ele, 0, md.damage, 0, md.flag);
  5164. if (sd && (i = pc_skillatk_bonus(sd, skill_id)))
  5165. md.damage += (int64)md.damage*i/100;
  5166. if(md.damage < 0)
  5167. md.damage = 0;
  5168. else if(md.damage && tstatus->mode&MD_PLANT){
  5169. switch(skill_id){
  5170. case HT_LANDMINE:
  5171. case MA_LANDMINE:
  5172. case HT_BLASTMINE:
  5173. case HT_CLAYMORETRAP:
  5174. case RA_CLUSTERBOMB:
  5175. #ifdef RENEWAL
  5176. break;
  5177. case NJ_ISSEN: // Final Strike will MISS on "plant"-type mobs [helvetica]
  5178. md.damage = 0;
  5179. md.dmg_lv=ATK_FLEE;
  5180. break;
  5181. #endif
  5182. default:
  5183. md.damage = 1;
  5184. }
  5185. }else if( target->type == BL_SKILL ){
  5186. TBL_SKILL *su = (TBL_SKILL*)target;
  5187. if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) )
  5188. md.damage = 1;
  5189. }
  5190. if(!(nk&NK_NO_ELEFIX))
  5191. md.damage=battle_attr_fix(src, target, md.damage, s_ele, tstatus->def_ele, tstatus->ele_lv);
  5192. md.damage=battle_calc_damage(src,target,&md,md.damage,skill_id,skill_lv);
  5193. if( map_flag_gvg2(target->m) )
  5194. md.damage=battle_calc_gvg_damage(src,target,md.damage,md.div_,skill_id,skill_lv,md.flag);
  5195. else if( map[target->m].flag.battleground )
  5196. md.damage=battle_calc_bg_damage(src,target,md.damage,md.div_,skill_id,skill_lv,md.flag);
  5197. switch( skill_id ) {
  5198. case RA_FIRINGTRAP:
  5199. case RA_ICEBOUNDTRAP:
  5200. if( md.damage == 1 ) break;
  5201. case RA_CLUSTERBOMB:
  5202. {
  5203. struct Damage wd;
  5204. wd = battle_calc_weapon_attack(src,target,skill_id,skill_lv,mflag);
  5205. md.damage += wd.damage;
  5206. }
  5207. break;
  5208. case NJ_ZENYNAGE:
  5209. if( sd ) {
  5210. if ( md.damage > sd->status.zeny )
  5211. md.damage = sd->status.zeny;
  5212. pc_payzeny(sd, (int)md.damage,LOG_TYPE_STEAL,NULL);
  5213. }
  5214. break;
  5215. }
  5216. /* Skill damage adjustment */
  5217. #ifdef ADJUST_SKILL_DAMAGE
  5218. if ((skill_damage = battle_skill_damage(src,target,skill_id)) != 0)
  5219. md.damage += (int64)md.damage * skill_damage / 100;
  5220. #endif
  5221. if(tstatus->mode&MD_IGNOREMISC && md.flag&(BF_MISC) ) //misc @TODO optimize me
  5222. md.damage = md.damage2 = 1;
  5223. return md;
  5224. }
  5225. /*==========================================
  5226. * Battle main entry, from skill_attack
  5227. *------------------------------------------
  5228. * Credits:
  5229. * Original coder unknown
  5230. * Initial refactoring by Baalberith
  5231. * Refined and optimized by helvetica
  5232. */
  5233. struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct block_list *target,uint16 skill_id,uint16 skill_lv,int count)
  5234. {
  5235. struct Damage d;
  5236. switch(attack_type) {
  5237. case BF_WEAPON: d = battle_calc_weapon_attack(bl,target,skill_id,skill_lv,count); break;
  5238. case BF_MAGIC: d = battle_calc_magic_attack(bl,target,skill_id,skill_lv,count); break;
  5239. case BF_MISC: d = battle_calc_misc_attack(bl,target,skill_id,skill_lv,count); break;
  5240. default:
  5241. ShowError("battle_calc_attack: unknown attack type! %d\n",attack_type);
  5242. memset(&d,0,sizeof(d));
  5243. break;
  5244. }
  5245. if( d.damage + d.damage2 < 1 )
  5246. { //Miss/Absorbed
  5247. //Weapon attacks should go through to cause additional effects.
  5248. if (d.dmg_lv == ATK_DEF /*&& attack_type&(BF_MAGIC|BF_MISC)*/) // Isn't it that additional effects don't apply if miss?
  5249. d.dmg_lv = ATK_MISS;
  5250. d.dmotion = 0;
  5251. }
  5252. else // Some skills like Weaponry Research will cause damage even if attack is dodged
  5253. d.dmg_lv = ATK_DEF;
  5254. return d;
  5255. }
  5256. /*==========================================
  5257. * Final damage return function
  5258. *------------------------------------------
  5259. * Credits:
  5260. * Original coder unknown
  5261. * Initial refactoring by Baalberith
  5262. * Refined and optimized by helvetica
  5263. */
  5264. int64 battle_calc_return_damage(struct block_list* bl, struct block_list *src, int64 *dmg, int flag, uint16 skill_id, bool status_reflect){
  5265. struct map_session_data* sd;
  5266. int64 rdamage = 0, damage = *dmg;
  5267. int max_damage = status_get_max_hp(bl);
  5268. struct status_change* sc;
  5269. sd = BL_CAST(BL_PC, bl);
  5270. sc = status_get_sc(bl);
  5271. if (flag & BF_SHORT) {//Bounces back part of the damage.
  5272. if ( !status_reflect && sd && sd->bonus.short_weapon_damage_return ) {
  5273. rdamage += damage * sd->bonus.short_weapon_damage_return / 100;
  5274. if(rdamage < 1) rdamage = 1;
  5275. } else if( status_reflect && sc && sc->count ) {
  5276. if( sc->data[SC_REFLECTDAMAGE] && !(skill_get_inf2(skill_id)&INF2_TRAP)) {
  5277. if( rnd()%100 <= sc->data[SC_REFLECTDAMAGE]->val1*10 + 30 ){
  5278. max_damage = (int64)max_damage * status_get_lv(bl) / 100;
  5279. rdamage = (*dmg) * sc->data[SC_REFLECTDAMAGE]->val2 / 100;
  5280. if( --(sc->data[SC_REFLECTDAMAGE]->val3) < 1)
  5281. status_change_end(bl,SC_REFLECTDAMAGE,INVALID_TIMER);
  5282. }
  5283. } else {
  5284. if ( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) {
  5285. rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100;
  5286. if (rdamage < 1) rdamage = 1;
  5287. }
  5288. if(sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION && !(src->type == BL_MOB && is_boss(src)) ) {
  5289. uint8 dir = map_calc_dir(bl,src->x,src->y),
  5290. t_dir = unit_getdir(bl);
  5291. if( distance_bl(src,bl) <= 0 || !map_check_dir(dir,t_dir) ) {
  5292. int64 rd1 = 0;
  5293. rd1 = min(damage,status_get_max_hp(bl)) * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage.
  5294. *dmg = rd1 * 30 / 100; // Received damage = 30% of amplifly damage.
  5295. clif_skill_damage(src,bl,gettick(), status_get_amotion(src), 0, -30000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1,6);
  5296. status_change_end(bl,SC_DEATHBOUND,INVALID_TIMER);
  5297. rdamage += rd1 * 70 / 100; // Target receives 70% of the amplified damage. [Rytech]
  5298. }
  5299. }
  5300. }
  5301. }
  5302. } else {
  5303. if (!status_reflect && sd && sd->bonus.long_weapon_damage_return) {
  5304. rdamage += damage * sd->bonus.long_weapon_damage_return / 100;
  5305. if (rdamage < 1) rdamage = 1;
  5306. }
  5307. }
  5308. if( sc && sc->data[SC_KYOMU] ) // Nullify reflecting ability
  5309. rdamage = 0;
  5310. return cap_value(min(rdamage,max_damage),INT_MIN,INT_MAX);
  5311. }
  5312. /*===========================================
  5313. * Perform battle drain effects (HP/SP loss)
  5314. *-------------------------------------------*/
  5315. void battle_drain(TBL_PC *sd, struct block_list *tbl, int64 rdamage, int64 ldamage, int race, int boss)
  5316. {
  5317. struct weapon_data *wd;
  5318. int64 *damage;
  5319. int type, thp = 0, tsp = 0, rhp = 0, rsp = 0, hp, sp, i;
  5320. for (i = 0; i < 4; i++) {
  5321. //First two iterations: Right hand
  5322. if (i < 2) { wd = &sd->right_weapon; damage = &rdamage; }
  5323. else { wd = &sd->left_weapon; damage = &ldamage; }
  5324. if (*damage <= 0) continue;
  5325. //First and Third iterations: race, other two boss/nonboss state
  5326. if (i == 0 || i == 2)
  5327. type = race;
  5328. else
  5329. type = boss?RC_BOSS:RC_NONBOSS;
  5330. hp = wd->hp_drain[type].value;
  5331. if (wd->hp_drain[type].rate)
  5332. hp += battle_calc_drain(*damage, wd->hp_drain[type].rate, wd->hp_drain[type].per);
  5333. sp = wd->sp_drain[type].value;
  5334. if (wd->sp_drain[type].rate)
  5335. sp += battle_calc_drain(*damage, wd->sp_drain[type].rate, wd->sp_drain[type].per);
  5336. if (hp) {
  5337. if (wd->hp_drain[type].type)
  5338. rhp += hp;
  5339. thp += hp;
  5340. }
  5341. if (sp) {
  5342. if (wd->sp_drain[type].type)
  5343. rsp += sp;
  5344. tsp += sp;
  5345. }
  5346. }
  5347. if (sd->bonus.sp_vanish_rate && rnd()%1000 < sd->bonus.sp_vanish_rate)
  5348. status_percent_damage(&sd->bl, tbl, 0, (unsigned char)sd->bonus.sp_vanish_per, false);
  5349. if( sd->sp_gain_race_attack[race] )
  5350. tsp += sd->sp_gain_race_attack[race];
  5351. if( sd->hp_gain_race_attack[race] )
  5352. thp += sd->hp_gain_race_attack[race];
  5353. if (!thp && !tsp) return;
  5354. status_heal(&sd->bl, thp, tsp, battle_config.show_hp_sp_drain?3:1);
  5355. if (rhp || rsp)
  5356. status_zap(tbl, rhp, rsp);
  5357. }
  5358. /*===========================================
  5359. * Deals the same damage to targets in area.
  5360. *-------------------------------------------
  5361. * Credits:
  5362. * Original coder pakpil
  5363. */
  5364. int battle_damage_area( struct block_list *bl, va_list ap) {
  5365. unsigned int tick;
  5366. int64 damage;
  5367. int amotion, dmotion;
  5368. struct block_list *src;
  5369. nullpo_ret(bl);
  5370. tick=va_arg(ap, unsigned int);
  5371. src=va_arg(ap,struct block_list *);
  5372. amotion=va_arg(ap,int);
  5373. dmotion=va_arg(ap,int);
  5374. damage=va_arg(ap,int);
  5375. if( bl->type == BL_MOB && ((TBL_MOB*)bl)->class_ == MOBID_EMPERIUM )
  5376. return 0;
  5377. if( bl != src && battle_check_target(src,bl,BCT_ENEMY) > 0 ) {
  5378. map_freeblock_lock();
  5379. if( src->type == BL_PC )
  5380. battle_drain((TBL_PC*)src, bl, damage, damage, status_get_race(bl), is_boss(bl));
  5381. if( amotion )
  5382. battle_delay_damage(tick, amotion,src,bl,0,CR_REFLECTSHIELD,0,damage,ATK_DEF,0,true);
  5383. else
  5384. status_fix_damage(src,bl,damage,0);
  5385. clif_damage(bl,bl,tick,amotion,dmotion,damage,1,ATK_BLOCK,0);
  5386. skill_additional_effect(src, bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
  5387. map_freeblock_unlock();
  5388. }
  5389. return 0;
  5390. }
  5391. /*==========================================
  5392. * Do a basic physical attack (call trough unit_attack_timer)
  5393. *------------------------------------------*/
  5394. enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* target, unsigned int tick, int flag) {
  5395. struct map_session_data *sd = NULL, *tsd = NULL;
  5396. struct status_data *sstatus, *tstatus;
  5397. struct status_change *sc, *tsc;
  5398. int64 damage;
  5399. int skillv;
  5400. struct Damage wd;
  5401. nullpo_retr(ATK_NONE, src);
  5402. nullpo_retr(ATK_NONE, target);
  5403. if (src->prev == NULL || target->prev == NULL)
  5404. return ATK_NONE;
  5405. sd = BL_CAST(BL_PC, src);
  5406. tsd = BL_CAST(BL_PC, target);
  5407. sstatus = status_get_status_data(src);
  5408. tstatus = status_get_status_data(target);
  5409. sc = status_get_sc(src);
  5410. tsc = status_get_sc(target);
  5411. if (sc && !sc->count) //Avoid sc checks when there's none to check for. [Skotlex]
  5412. sc = NULL;
  5413. if (tsc && !tsc->count)
  5414. tsc = NULL;
  5415. if (sd)
  5416. {
  5417. sd->state.arrow_atk = (sd->status.weapon == W_BOW || (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE));
  5418. if (sd->state.arrow_atk)
  5419. {
  5420. int index = sd->equip_index[EQI_AMMO];
  5421. if (index<0) {
  5422. clif_arrow_fail(sd,0);
  5423. return ATK_NONE;
  5424. }
  5425. //Ammo check by Ishizu-chan
  5426. if (sd->inventory_data[index])
  5427. switch (sd->status.weapon) {
  5428. case W_BOW:
  5429. if (sd->inventory_data[index]->look != A_ARROW) {
  5430. clif_arrow_fail(sd,0);
  5431. return ATK_NONE;
  5432. }
  5433. break;
  5434. case W_REVOLVER:
  5435. case W_RIFLE:
  5436. case W_GATLING:
  5437. case W_SHOTGUN:
  5438. if (sd->inventory_data[index]->look != A_BULLET) {
  5439. clif_arrow_fail(sd,0);
  5440. return ATK_NONE;
  5441. }
  5442. break;
  5443. case W_GRENADE:
  5444. if (sd->inventory_data[index]->look != A_GRENADE) {
  5445. clif_arrow_fail(sd,0);
  5446. return ATK_NONE;
  5447. }
  5448. break;
  5449. }
  5450. }
  5451. }
  5452. if (sc && sc->count) {
  5453. if (sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4 & 2))
  5454. status_change_end(src, SC_CLOAKING, INVALID_TIMER);
  5455. else if (sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4 & 2))
  5456. status_change_end(src, SC_CLOAKINGEXCEED, INVALID_TIMER);
  5457. }
  5458. if( tsc && tsc->data[SC_AUTOCOUNTER] && status_check_skilluse(target, src, KN_AUTOCOUNTER, 1) )
  5459. {
  5460. uint8 dir = map_calc_dir(target,src->x,src->y);
  5461. int t_dir = unit_getdir(target);
  5462. int dist = distance_bl(src, target);
  5463. if(dist <= 0 || (!map_check_dir(dir,t_dir) && dist <= tstatus->rhw.range+1))
  5464. {
  5465. uint16 skill_lv = tsc->data[SC_AUTOCOUNTER]->val1;
  5466. clif_skillcastcancel(target); //Remove the casting bar. [Skotlex]
  5467. clif_damage(src, target, tick, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS.
  5468. status_change_end(target, SC_AUTOCOUNTER, INVALID_TIMER);
  5469. skill_attack(BF_WEAPON,target,target,src,KN_AUTOCOUNTER,skill_lv,tick,0);
  5470. return ATK_BLOCK;
  5471. }
  5472. }
  5473. if( tsc && tsc->data[SC_BLADESTOP_WAIT] && !is_boss(src) && (src->type == BL_PC || tsd == NULL || distance_bl(src, target) <= (tsd->status.weapon == W_FIST ? 1 : 2)) )
  5474. {
  5475. uint16 skill_lv = tsc->data[SC_BLADESTOP_WAIT]->val1;
  5476. int duration = skill_get_time2(MO_BLADESTOP,skill_lv);
  5477. status_change_end(target, SC_BLADESTOP_WAIT, INVALID_TIMER);
  5478. if(sc_start4(src,src, SC_BLADESTOP, 100, sd?pc_checkskill(sd, MO_BLADESTOP):5, 0, 0, target->id, duration))
  5479. { //Target locked.
  5480. clif_damage(src, target, tick, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS.
  5481. clif_bladestop(target, src->id, 1);
  5482. sc_start4(src,target, SC_BLADESTOP, 100, skill_lv, 0, 0, src->id, duration);
  5483. return ATK_BLOCK;
  5484. }
  5485. }
  5486. if(sd && (skillv = pc_checkskill(sd,MO_TRIPLEATTACK)) > 0) {
  5487. int triple_rate= 30 - skillv; //Base Rate
  5488. if (sc && sc->data[SC_SKILLRATE_UP] && sc->data[SC_SKILLRATE_UP]->val1 == MO_TRIPLEATTACK) {
  5489. triple_rate+= triple_rate*(sc->data[SC_SKILLRATE_UP]->val2)/100;
  5490. status_change_end(src, SC_SKILLRATE_UP, INVALID_TIMER);
  5491. }
  5492. if (rnd()%100 < triple_rate) {
  5493. if( skill_attack(BF_WEAPON,src,src,target,MO_TRIPLEATTACK,skillv,tick,0) )
  5494. return ATK_DEF;
  5495. return ATK_MISS;
  5496. }
  5497. }
  5498. if (sc) {
  5499. if (sc->data[SC_SACRIFICE]) {
  5500. uint16 skill_lv = sc->data[SC_SACRIFICE]->val1;
  5501. damage_lv ret_val;
  5502. if( --sc->data[SC_SACRIFICE]->val2 <= 0 )
  5503. status_change_end(src, SC_SACRIFICE, INVALID_TIMER);
  5504. /**
  5505. * We need to calculate the DMG before the hp reduction, because it can kill the source.
  5506. * For futher information: bugreport:4950
  5507. **/
  5508. ret_val = (damage_lv)skill_attack(BF_WEAPON,src,src,target,PA_SACRIFICE,skill_lv,tick,0);
  5509. status_zap(src, sstatus->max_hp*9/100, 0);//Damage to self is always 9%
  5510. if( ret_val == ATK_NONE )
  5511. return ATK_MISS;
  5512. return ret_val;
  5513. }
  5514. if (sc->data[SC_MAGICALATTACK]) {
  5515. if( skill_attack(BF_MAGIC,src,src,target,NPC_MAGICALATTACK,sc->data[SC_MAGICALATTACK]->val1,tick,0) )
  5516. return ATK_DEF;
  5517. return ATK_MISS;
  5518. }
  5519. if( sc->data[SC_GT_ENERGYGAIN] ) {
  5520. if( sd && rnd()%100 < 10 + 5 * sc->data[SC_GT_ENERGYGAIN]->val1)
  5521. pc_addspiritball(sd,
  5522. skill_get_time(MO_CALLSPIRITS, sc->data[SC_GT_ENERGYGAIN]->val1),
  5523. sc->data[SC_GT_ENERGYGAIN]->val1);
  5524. }
  5525. if( tsc && tsc->data[SC_GT_ENERGYGAIN] ) {
  5526. if( tsd && rnd()%100 < 10 + 5 * tsc->data[SC_GT_ENERGYGAIN]->val1)
  5527. pc_addspiritball(tsd,
  5528. skill_get_time(MO_CALLSPIRITS, tsc->data[SC_GT_ENERGYGAIN]->val1),
  5529. tsc->data[SC_GT_ENERGYGAIN]->val1);
  5530. }
  5531. if( sc && sc->data[SC_CRUSHSTRIKE] ){
  5532. uint16 skill_lv = sc->data[SC_CRUSHSTRIKE]->val1;
  5533. status_change_end(src, SC_CRUSHSTRIKE, INVALID_TIMER);
  5534. if( skill_attack(BF_WEAPON,src,src,target,RK_CRUSHSTRIKE,skill_lv,tick,0) )
  5535. return ATK_DEF;
  5536. return ATK_MISS;
  5537. }
  5538. }
  5539. if(tsc && tsc->data[SC_KAAHI] && tsc->data[SC_KAAHI]->val4 == INVALID_TIMER && tstatus->hp < tstatus->max_hp)
  5540. tsc->data[SC_KAAHI]->val4 = add_timer(tick + skill_get_time2(SL_KAAHI,tsc->data[SC_KAAHI]->val1), kaahi_heal_timer, target->id, SC_KAAHI); //Activate heal.
  5541. wd = battle_calc_attack(BF_WEAPON, src, target, 0, 0, flag);
  5542. if( sc && sc->count ) {
  5543. if (sc->data[SC_EXEEDBREAK]) {
  5544. ATK_RATER(wd.damage, sc->data[SC_EXEEDBREAK]->val1)
  5545. status_change_end(src, SC_EXEEDBREAK, INVALID_TIMER);
  5546. }
  5547. if( sc->data[SC_SPELLFIST] ) {
  5548. if( --(sc->data[SC_SPELLFIST]->val1) >= 0 ){
  5549. struct Damage ad = battle_calc_attack(BF_MAGIC,src,target,sc->data[SC_SPELLFIST]->val3,sc->data[SC_SPELLFIST]->val4,flag|BF_SHORT);
  5550. wd.damage = ad.damage;
  5551. }else
  5552. status_change_end(src,SC_SPELLFIST,INVALID_TIMER);
  5553. }
  5554. if( sc->data[SC_GIANTGROWTH] && (wd.flag&BF_SHORT) && rnd()%100 < sc->data[SC_GIANTGROWTH]->val2 )
  5555. wd.damage *= 3; // Triple Damage
  5556. if( sd && sc->data[SC_FEARBREEZE] && sc->data[SC_FEARBREEZE]->val4 > 0 && sd->status.inventory[sd->equip_index[EQI_AMMO]].amount >= sc->data[SC_FEARBREEZE]->val4 && battle_config.arrow_decrement){
  5557. pc_delitem(sd,sd->equip_index[EQI_AMMO],sc->data[SC_FEARBREEZE]->val4,0,1,LOG_TYPE_CONSUME);
  5558. sc->data[SC_FEARBREEZE]->val4 = 0;
  5559. }
  5560. }
  5561. if (sd && sd->state.arrow_atk) //Consume arrow.
  5562. battle_consume_ammo(sd, 0, 0);
  5563. damage = wd.damage + wd.damage2;
  5564. if( damage > 0 && src != target )
  5565. {
  5566. if( sc && sc->data[SC_DUPLELIGHT] && (wd.flag&BF_SHORT) && rnd()%100 <= 10+2*sc->data[SC_DUPLELIGHT]->val1 )
  5567. { // Activates it only from melee damage
  5568. uint16 skill_id;
  5569. if( rnd()%2 == 1 )
  5570. skill_id = AB_DUPLELIGHT_MELEE;
  5571. else
  5572. skill_id = AB_DUPLELIGHT_MAGIC;
  5573. skill_attack(skill_get_type(skill_id), src, src, target, skill_id, sc->data[SC_DUPLELIGHT]->val1, tick, SD_LEVEL);
  5574. }
  5575. }
  5576. wd.dmotion = clif_damage(src, target, tick, wd.amotion, wd.dmotion, wd.damage, wd.div_ , wd.type, wd.damage2);
  5577. if (sd && sd->bonus.splash_range > 0 && damage > 0)
  5578. skill_castend_damage_id(src, target, 0, 1, tick, 0);
  5579. if ( target->type == BL_SKILL && damage > 0 ){
  5580. TBL_SKILL *su = (TBL_SKILL*)target;
  5581. if( su->group && su->group->skill_id == HT_BLASTMINE)
  5582. skill_blown(src, target, 3, -1, 0);
  5583. }
  5584. map_freeblock_lock();
  5585. battle_delay_damage(tick, wd.amotion, src, target, wd.flag, 0, 0, damage, wd.dmg_lv, wd.dmotion, true);
  5586. if( tsc ) {
  5587. if( tsc->data[SC_DEVOTION] ) {
  5588. struct status_change_entry *sce = tsc->data[SC_DEVOTION];
  5589. struct block_list *d_bl = map_id2bl(sce->val1);
  5590. if( d_bl && (
  5591. (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == target->id) ||
  5592. (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id)
  5593. ) && check_distance_bl(target, d_bl, sce->val3) )
  5594. {
  5595. clif_damage(d_bl, d_bl, gettick(), 0, 0, damage, 0, 0, 0);
  5596. status_fix_damage(NULL, d_bl, damage, 0);
  5597. }
  5598. else
  5599. status_change_end(target, SC_DEVOTION, INVALID_TIMER);
  5600. } else if( tsc->data[SC_CIRCLE_OF_FIRE_OPTION] && (wd.flag&BF_SHORT) && target->type == BL_PC ) {
  5601. struct elemental_data *ed = ((TBL_PC*)target)->ed;
  5602. if( ed ) {
  5603. clif_skill_damage(&ed->bl, target, tick, status_get_amotion(src), 0, -30000, 1, EL_CIRCLE_OF_FIRE, tsc->data[SC_CIRCLE_OF_FIRE_OPTION]->val1, 6);
  5604. skill_attack(BF_MAGIC,&ed->bl,&ed->bl,src,EL_CIRCLE_OF_FIRE,tsc->data[SC_CIRCLE_OF_FIRE_OPTION]->val1,tick,wd.flag);
  5605. }
  5606. } else if( tsc->data[SC_WATER_SCREEN_OPTION] && tsc->data[SC_WATER_SCREEN_OPTION]->val1 ) {
  5607. struct block_list *e_bl = map_id2bl(tsc->data[SC_WATER_SCREEN_OPTION]->val1);
  5608. if( e_bl && !status_isdead(e_bl) ) {
  5609. clif_damage(e_bl,e_bl,tick,wd.amotion,wd.dmotion,damage,wd.div_,wd.type,wd.damage2);
  5610. status_damage(target,e_bl,damage,0,0,0);
  5611. // Just show damage in target.
  5612. clif_damage(src, target, tick, wd.amotion, wd.dmotion, damage, wd.div_, wd.type, wd.damage2 );
  5613. map_freeblock_unlock();
  5614. return ATK_NONE;
  5615. }
  5616. }
  5617. }
  5618. if (sc && sc->data[SC_AUTOSPELL] && rnd()%100 < sc->data[SC_AUTOSPELL]->val4) {
  5619. int sp = 0;
  5620. uint16 skill_id = sc->data[SC_AUTOSPELL]->val2;
  5621. uint16 skill_lv = sc->data[SC_AUTOSPELL]->val3;
  5622. int i = rnd()%100;
  5623. if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_SAGE)
  5624. i = 0; //Max chance, no skill_lv reduction. [Skotlex]
  5625. //reduction only for skill_lv > 1
  5626. if (skill_lv > 1) {
  5627. if (i >= 50) skill_lv -= 2;
  5628. else if (i >= 15) skill_lv--;
  5629. }
  5630. sp = skill_get_sp(skill_id,skill_lv) * 2 / 3;
  5631. if (status_charge(src, 0, sp)) {
  5632. switch (skill_get_casttype(skill_id)) {
  5633. case CAST_GROUND:
  5634. skill_castend_pos2(src, target->x, target->y, skill_id, skill_lv, tick, flag);
  5635. break;
  5636. case CAST_NODAMAGE:
  5637. skill_castend_nodamage_id(src, target, skill_id, skill_lv, tick, flag);
  5638. break;
  5639. case CAST_DAMAGE:
  5640. skill_castend_damage_id(src, target, skill_id, skill_lv, tick, flag);
  5641. break;
  5642. }
  5643. }
  5644. }
  5645. if (sd) {
  5646. if( wd.flag&BF_SHORT && sc && sc->data[SC__AUTOSHADOWSPELL] && rnd()%100 < sc->data[SC__AUTOSHADOWSPELL]->val3 &&
  5647. sd->status.skill[sc->data[SC__AUTOSHADOWSPELL]->val1].id != 0 && sd->status.skill[sc->data[SC__AUTOSHADOWSPELL]->val1].flag == SKILL_FLAG_PLAGIARIZED )
  5648. {
  5649. int r_skill = sd->status.skill[sc->data[SC__AUTOSHADOWSPELL]->val1].id,
  5650. r_lv = sc->data[SC__AUTOSHADOWSPELL]->val2;
  5651. if (r_skill != AL_HOLYLIGHT && r_skill != PR_MAGNUS) {
  5652. int type;
  5653. if( (type = skill_get_casttype(r_skill)) == CAST_GROUND ) {
  5654. int maxcount = 0;
  5655. if( !(BL_PC&battle_config.skill_reiteration) &&
  5656. skill_get_unit_flag(r_skill)&UF_NOREITERATION )
  5657. type = -1;
  5658. if( BL_PC&battle_config.skill_nofootset &&
  5659. skill_get_unit_flag(r_skill)&UF_NOFOOTSET )
  5660. type = -1;
  5661. if( BL_PC&battle_config.land_skill_limit &&
  5662. (maxcount = skill_get_maxcount(r_skill, r_lv)) > 0
  5663. ) {
  5664. int v;
  5665. for(v=0;v<MAX_SKILLUNITGROUP && sd->ud.skillunit[v] && maxcount;v++) {
  5666. if(sd->ud.skillunit[v]->skill_id == r_skill)
  5667. maxcount--;
  5668. }
  5669. if( maxcount == 0 )
  5670. type = -1;
  5671. }
  5672. if( type != CAST_GROUND ){
  5673. clif_skill_fail(sd,r_skill,USESKILL_FAIL_LEVEL,0);
  5674. map_freeblock_unlock();
  5675. return wd.dmg_lv;
  5676. }
  5677. }
  5678. sd->state.autocast = 1;
  5679. skill_consume_requirement(sd,r_skill,r_lv,3);
  5680. switch( type ) {
  5681. case CAST_GROUND:
  5682. skill_castend_pos2(src, target->x, target->y, r_skill, r_lv, tick, flag);
  5683. break;
  5684. case CAST_NODAMAGE:
  5685. skill_castend_nodamage_id(src, target, r_skill, r_lv, tick, flag);
  5686. break;
  5687. case CAST_DAMAGE:
  5688. skill_castend_damage_id(src, target, r_skill, r_lv, tick, flag);
  5689. break;
  5690. }
  5691. sd->state.autocast = 0;
  5692. sd->ud.canact_tick = tick + skill_delayfix(src, r_skill, r_lv);
  5693. clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, r_skill, r_lv), 0, 0, 1);
  5694. }
  5695. }
  5696. if (wd.flag & BF_WEAPON && src != target && damage > 0) {
  5697. if (battle_config.left_cardfix_to_right)
  5698. battle_drain(sd, target, wd.damage, wd.damage, tstatus->race, is_boss(target));
  5699. else
  5700. battle_drain(sd, target, wd.damage, wd.damage2, tstatus->race, is_boss(target));
  5701. }
  5702. }
  5703. if (tsc) {
  5704. if (damage > 0 && tsc->data[SC_POISONREACT] &&
  5705. (rnd()%100 < tsc->data[SC_POISONREACT]->val3
  5706. || sstatus->def_ele == ELE_POISON) &&
  5707. // check_distance_bl(src, target, tstatus->rhw.range+1) && Doesn't checks range! o.O;
  5708. status_check_skilluse(target, src, TF_POISON, 0)
  5709. ) { //Poison React
  5710. struct status_change_entry *sce = tsc->data[SC_POISONREACT];
  5711. if (sstatus->def_ele == ELE_POISON) {
  5712. sce->val2 = 0;
  5713. skill_attack(BF_WEAPON,target,target,src,AS_POISONREACT,sce->val1,tick,0);
  5714. } else {
  5715. skill_attack(BF_WEAPON,target,target,src,TF_POISON, 5, tick, 0);
  5716. --sce->val2;
  5717. }
  5718. if (sce->val2 <= 0)
  5719. status_change_end(target, SC_POISONREACT, INVALID_TIMER);
  5720. }
  5721. }
  5722. map_freeblock_unlock();
  5723. return wd.dmg_lv;
  5724. }
  5725. /*=========================
  5726. * Check for undead status
  5727. *-------------------------
  5728. * Credits:
  5729. * Original coder Skoltex
  5730. * Refactored by Baalberith
  5731. */
  5732. int battle_check_undead(int race,int element)
  5733. {
  5734. if(battle_config.undead_detect_type == 0) {
  5735. if(element == ELE_UNDEAD)
  5736. return 1;
  5737. }
  5738. else if(battle_config.undead_detect_type == 1) {
  5739. if(race == RC_UNDEAD)
  5740. return 1;
  5741. }
  5742. else {
  5743. if(element == ELE_UNDEAD || race == RC_UNDEAD)
  5744. return 1;
  5745. }
  5746. return 0;
  5747. }
  5748. /*================================================================
  5749. * Returns the upmost level master starting with the given object
  5750. *----------------------------------------------------------------*/
  5751. struct block_list* battle_get_master(struct block_list *src)
  5752. {
  5753. struct block_list *prev; //Used for infinite loop check (master of yourself?)
  5754. do {
  5755. prev = src;
  5756. switch (src->type) {
  5757. case BL_PET:
  5758. if (((TBL_PET*)src)->master)
  5759. src = (struct block_list*)((TBL_PET*)src)->master;
  5760. break;
  5761. case BL_MOB:
  5762. if (((TBL_MOB*)src)->master_id)
  5763. src = map_id2bl(((TBL_MOB*)src)->master_id);
  5764. break;
  5765. case BL_HOM:
  5766. if (((TBL_HOM*)src)->master)
  5767. src = (struct block_list*)((TBL_HOM*)src)->master;
  5768. break;
  5769. case BL_MER:
  5770. if (((TBL_MER*)src)->master)
  5771. src = (struct block_list*)((TBL_MER*)src)->master;
  5772. break;
  5773. case BL_ELEM:
  5774. if (((TBL_ELEM*)src)->master)
  5775. src = (struct block_list*)((TBL_ELEM*)src)->master;
  5776. break;
  5777. case BL_SKILL:
  5778. if (((TBL_SKILL*)src)->group && ((TBL_SKILL*)src)->group->src_id)
  5779. src = map_id2bl(((TBL_SKILL*)src)->group->src_id);
  5780. break;
  5781. }
  5782. } while (src && src != prev);
  5783. return prev;
  5784. }
  5785. /*==========================================
  5786. * Checks the state between two targets
  5787. * (enemy, friend, party, guild, etc)
  5788. *------------------------------------------
  5789. * Usage:
  5790. * See battle.h for possible values/combinations
  5791. * to be used here (BCT_* constants)
  5792. * Return value is:
  5793. * 1: flag holds true (is enemy, party, etc)
  5794. * -1: flag fails
  5795. * 0: Invalid target (non-targetable ever)
  5796. *
  5797. * Credits:
  5798. * Original coder unknown
  5799. * Rewritten by Skoltex
  5800. */
  5801. int battle_check_target( struct block_list *src, struct block_list *target,int flag)
  5802. {
  5803. int16 m; //map
  5804. int state = 0; //Initial state none
  5805. int strip_enemy = 1; //Flag which marks whether to remove the BCT_ENEMY status if it's also friend/ally.
  5806. struct block_list *s_bl = src, *t_bl = target;
  5807. nullpo_ret(src);
  5808. nullpo_ret(target);
  5809. m = target->m;
  5810. //t_bl/s_bl hold the 'master' of the attack, while src/target are the actual
  5811. //objects involved.
  5812. if( (t_bl = battle_get_master(target)) == NULL )
  5813. t_bl = target;
  5814. if( (s_bl = battle_get_master(src)) == NULL )
  5815. s_bl = src;
  5816. if ( s_bl->type == BL_PC ) {
  5817. switch( t_bl->type ) {
  5818. case BL_MOB: // Source => PC, Target => MOB
  5819. if ( pc_has_permission((TBL_PC*)s_bl, PC_PERM_DISABLE_PVM) )
  5820. return 0;
  5821. break;
  5822. case BL_PC:
  5823. if (pc_has_permission((TBL_PC*)s_bl, PC_PERM_DISABLE_PVP))
  5824. return 0;
  5825. break;
  5826. default:/* anything else goes */
  5827. break;
  5828. }
  5829. }
  5830. switch( target->type ) { // Checks on actual target
  5831. case BL_PC: {
  5832. struct status_change* sc = status_get_sc(src);
  5833. if (((TBL_PC*)target)->invincible_timer != INVALID_TIMER || pc_isinvisible((TBL_PC*)target))
  5834. return -1; //Cannot be targeted yet.
  5835. if( sc && sc->count ) {
  5836. if( sc->data[SC_VOICEOFSIREN] && sc->data[SC_VOICEOFSIREN]->val2 == target->id )
  5837. return -1;
  5838. }
  5839. }
  5840. break;
  5841. case BL_MOB:
  5842. {
  5843. struct mob_data *md = ((TBL_MOB*)target);
  5844. if(((md->special_state.ai == AI_SPHERE || //Marine Spheres
  5845. (md->special_state.ai == AI_FLORA && battle_config.summon_flora&1)) && s_bl->type == BL_PC && src->type != BL_MOB) || //Floras
  5846. (md->special_state.ai == AI_ZANZOU && t_bl->id != s_bl->id) || //Zanzoe
  5847. (md->special_state.ai == AI_FAW && (t_bl->id != s_bl->id || (s_bl->type == BL_PC && src->type != BL_MOB)))
  5848. ){ //Targettable by players
  5849. state |= BCT_ENEMY;
  5850. strip_enemy = 0;
  5851. }
  5852. break;
  5853. }
  5854. case BL_SKILL:
  5855. {
  5856. TBL_SKILL *su = (TBL_SKILL*)target;
  5857. if( !su->group )
  5858. return 0;
  5859. if( skill_get_inf2(su->group->skill_id)&INF2_TRAP ) { //Only a few skills can target traps...
  5860. switch( battle_getcurrentskill(src) ) {
  5861. case RK_DRAGONBREATH:// it can only hit traps in pvp/gvg maps
  5862. if( !map[m].flag.pvp && !map[m].flag.gvg )
  5863. break;
  5864. case 0://you can hit them without skills
  5865. case MA_REMOVETRAP:
  5866. case HT_REMOVETRAP:
  5867. case AC_SHOWER:
  5868. case MA_SHOWER:
  5869. case WZ_SIGHTRASHER:
  5870. case WZ_SIGHTBLASTER:
  5871. case SM_MAGNUM:
  5872. case MS_MAGNUM:
  5873. case RA_DETONATOR:
  5874. case RA_SENSITIVEKEEN:
  5875. case GN_CRAZYWEED_ATK:
  5876. case RK_STORMBLAST:
  5877. case SR_RAMPAGEBLASTER:
  5878. case NC_COLDSLOWER:
  5879. case NC_SELFDESTRUCTION:
  5880. #ifdef RENEWAL
  5881. case KN_BOWLINGBASH:
  5882. case KN_SPEARSTAB:
  5883. case LK_SPIRALPIERCE:
  5884. case ML_SPIRALPIERCE:
  5885. case MO_FINGEROFFENSIVE:
  5886. case MO_INVESTIGATE:
  5887. case MO_TRIPLEATTACK:
  5888. case MO_EXTREMITYFIST:
  5889. case CR_HOLYCROSS:
  5890. case ASC_METEORASSAULT:
  5891. case RG_RAID:
  5892. case MC_CARTREVOLUTION:
  5893. #endif
  5894. state |= BCT_ENEMY;
  5895. strip_enemy = 0;
  5896. break;
  5897. default:
  5898. if(su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD){
  5899. state |= BCT_ENEMY;
  5900. strip_enemy = 0;
  5901. }else
  5902. return 0;
  5903. }
  5904. } else if (su->group->skill_id==WZ_ICEWALL ||
  5905. su->group->skill_id == GN_WALLOFTHORN) {
  5906. state |= BCT_ENEMY;
  5907. strip_enemy = 0;
  5908. } else //Excepting traps and icewall, you should not be able to target skills.
  5909. return 0;
  5910. }
  5911. break;
  5912. //Valid targets with no special checks here.
  5913. case BL_MER:
  5914. case BL_HOM:
  5915. case BL_ELEM:
  5916. break;
  5917. //All else not specified is an invalid target.
  5918. default:
  5919. return 0;
  5920. } //end switch actual target
  5921. switch( t_bl->type )
  5922. { //Checks on target master
  5923. case BL_PC:
  5924. {
  5925. struct map_session_data *sd;
  5926. if( t_bl == s_bl ) break;
  5927. sd = BL_CAST(BL_PC, t_bl);
  5928. if( sd->state.monster_ignore && flag&BCT_ENEMY )
  5929. return 0; // Global inminuty only to Attacks
  5930. if( sd->status.karma && s_bl->type == BL_PC && ((TBL_PC*)s_bl)->status.karma )
  5931. state |= BCT_ENEMY; // Characters with bad karma may fight amongst them
  5932. if( sd->state.killable ) {
  5933. state |= BCT_ENEMY; // Everything can kill it
  5934. strip_enemy = 0;
  5935. }
  5936. break;
  5937. }
  5938. case BL_MOB:
  5939. {
  5940. struct mob_data *md = BL_CAST(BL_MOB, t_bl);
  5941. if( !((agit_flag || agit2_flag) && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id )
  5942. return 0; // Disable guardians/emperiums owned by Guilds on non-woe times.
  5943. break;
  5944. }
  5945. default: break; //other type doesn't have slave yet
  5946. } //end switch master target
  5947. switch( src->type ) { //Checks on actual src type
  5948. case BL_PET:
  5949. if (t_bl->type != BL_MOB && flag&BCT_ENEMY)
  5950. return 0; //Pet may not attack non-mobs.
  5951. if (t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->guardian_data && flag&BCT_ENEMY)
  5952. return 0; //pet may not attack Guardians/Emperium
  5953. break;
  5954. case BL_SKILL: {
  5955. struct skill_unit *su = (struct skill_unit *)src;
  5956. if (!su->group)
  5957. return 0;
  5958. if (su->group->src_id == target->id) {
  5959. int inf2 = skill_get_inf2(su->group->skill_id);
  5960. if (inf2&INF2_NO_TARGET_SELF)
  5961. return -1;
  5962. if (inf2&INF2_TARGET_SELF)
  5963. return 1;
  5964. }
  5965. }
  5966. break;
  5967. case BL_MER:
  5968. if (t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->class_ == MOBID_EMPERIUM && flag&BCT_ENEMY)
  5969. return 0; //mercenary may not attack Emperium
  5970. break;
  5971. } //end switch actual src
  5972. switch( s_bl->type )
  5973. { //Checks on source master
  5974. case BL_PC:
  5975. {
  5976. struct map_session_data *sd = BL_CAST(BL_PC, s_bl);
  5977. if( s_bl != t_bl )
  5978. {
  5979. if( sd->state.killer )
  5980. {
  5981. state |= BCT_ENEMY; // Can kill anything
  5982. strip_enemy = 0;
  5983. }
  5984. else if( sd->duel_group && !((!battle_config.duel_allow_pvp && map[m].flag.pvp) || (!battle_config.duel_allow_gvg && map_flag_gvg(m))) )
  5985. {
  5986. if( t_bl->type == BL_PC && (sd->duel_group == ((TBL_PC*)t_bl)->duel_group) )
  5987. return (BCT_ENEMY&flag)?1:-1; // Duel targets can ONLY be your enemy, nothing else.
  5988. else
  5989. return 0; // You can't target anything out of your duel
  5990. }
  5991. }
  5992. if( map_flag_gvg(m) && !sd->status.guild_id && t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->class_ == MOBID_EMPERIUM )
  5993. return 0; //If you don't belong to a guild, can't target emperium.
  5994. if( t_bl->type != BL_PC )
  5995. state |= BCT_ENEMY; //Natural enemy.
  5996. break;
  5997. }
  5998. case BL_MOB:
  5999. {
  6000. struct mob_data *md = BL_CAST(BL_MOB, s_bl);
  6001. if( !((agit_flag || agit2_flag) && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id )
  6002. return 0; // Disable guardians/emperium owned by Guilds on non-woe times.
  6003. if( !md->special_state.ai )
  6004. { //Normal mobs
  6005. if(
  6006. ( target->type == BL_MOB && t_bl->type == BL_PC && ( ((TBL_MOB*)target)->special_state.ai != AI_ZANZOU && ((TBL_MOB*)target)->special_state.ai != AI_ATTACK ) ) ||
  6007. ( t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai )
  6008. )
  6009. state |= BCT_PARTY; //Normal mobs with no ai are friends.
  6010. else
  6011. state |= BCT_ENEMY; //However, all else are enemies.
  6012. }
  6013. else
  6014. {
  6015. if( t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai )
  6016. state |= BCT_ENEMY; //Natural enemy for AI mobs are normal mobs.
  6017. }
  6018. break;
  6019. }
  6020. default:
  6021. //Need some sort of default behaviour for unhandled types.
  6022. if (t_bl->type != s_bl->type)
  6023. state |= BCT_ENEMY;
  6024. break;
  6025. } //end switch on src master
  6026. if( (flag&BCT_ALL) == BCT_ALL )
  6027. { //All actually stands for all attackable chars
  6028. if( target->type&BL_CHAR )
  6029. return 1;
  6030. else
  6031. return -1;
  6032. }
  6033. if( flag == BCT_NOONE ) //Why would someone use this? no clue.
  6034. return -1;
  6035. if( t_bl == s_bl )
  6036. { //No need for further testing.
  6037. state |= BCT_SELF|BCT_PARTY|BCT_GUILD;
  6038. if( state&BCT_ENEMY && strip_enemy )
  6039. state&=~BCT_ENEMY;
  6040. return (flag&state)?1:-1;
  6041. }
  6042. if( map_flag_vs(m) )
  6043. { //Check rivalry settings.
  6044. int sbg_id = 0, tbg_id = 0;
  6045. if( map[m].flag.battleground )
  6046. {
  6047. sbg_id = bg_team_get_id(s_bl);
  6048. tbg_id = bg_team_get_id(t_bl);
  6049. }
  6050. if( flag&(BCT_PARTY|BCT_ENEMY) )
  6051. {
  6052. int s_party = status_get_party_id(s_bl);
  6053. if( s_party && s_party == status_get_party_id(t_bl) && !(map[m].flag.pvp && map[m].flag.pvp_noparty) && !(map_flag_gvg(m) && map[m].flag.gvg_noparty) && (!map[m].flag.battleground || sbg_id == tbg_id) )
  6054. state |= BCT_PARTY;
  6055. else
  6056. state |= BCT_ENEMY;
  6057. }
  6058. if( flag&(BCT_GUILD|BCT_ENEMY) )
  6059. {
  6060. int s_guild = status_get_guild_id(s_bl);
  6061. int t_guild = status_get_guild_id(t_bl);
  6062. if( !(map[m].flag.pvp && map[m].flag.pvp_noguild) && s_guild && t_guild && (s_guild == t_guild || guild_isallied(s_guild, t_guild)) && (!map[m].flag.battleground || sbg_id == tbg_id) )
  6063. state |= BCT_GUILD;
  6064. else
  6065. state |= BCT_ENEMY;
  6066. }
  6067. if( state&BCT_ENEMY && map[m].flag.battleground && sbg_id && sbg_id == tbg_id )
  6068. state &= ~BCT_ENEMY;
  6069. if( state&BCT_ENEMY && battle_config.pk_mode && !map_flag_gvg(m) && s_bl->type == BL_PC && t_bl->type == BL_PC )
  6070. { // Prevent novice engagement on pk_mode (feature by Valaris)
  6071. TBL_PC *sd = (TBL_PC*)s_bl, *sd2 = (TBL_PC*)t_bl;
  6072. if (
  6073. (sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE ||
  6074. (sd2->class_&MAPID_UPPERMASK) == MAPID_NOVICE ||
  6075. (int)sd->status.base_level < battle_config.pk_min_level ||
  6076. (int)sd2->status.base_level < battle_config.pk_min_level ||
  6077. (battle_config.pk_level_range && abs((int)sd->status.base_level - (int)sd2->status.base_level) > battle_config.pk_level_range)
  6078. )
  6079. state &= ~BCT_ENEMY;
  6080. }
  6081. }//end map_flag_vs chk rivality
  6082. else
  6083. { //Non pvp/gvg, check party/guild settings.
  6084. if( flag&BCT_PARTY || state&BCT_ENEMY )
  6085. {
  6086. int s_party = status_get_party_id(s_bl);
  6087. if(s_party && s_party == status_get_party_id(t_bl))
  6088. state |= BCT_PARTY;
  6089. }
  6090. if( flag&BCT_GUILD || state&BCT_ENEMY )
  6091. {
  6092. int s_guild = status_get_guild_id(s_bl);
  6093. int t_guild = status_get_guild_id(t_bl);
  6094. if(s_guild && t_guild && (s_guild == t_guild || guild_isallied(s_guild, t_guild)))
  6095. state |= BCT_GUILD;
  6096. }
  6097. } //end non pvp/gvg chk rivality
  6098. if( !state ) //If not an enemy, nor a guild, nor party, nor yourself, it's neutral.
  6099. state = BCT_NEUTRAL;
  6100. //Alliance state takes precedence over enemy one.
  6101. else if( state&BCT_ENEMY && strip_enemy && state&(BCT_SELF|BCT_PARTY|BCT_GUILD) )
  6102. state&=~BCT_ENEMY;
  6103. return (flag&state)?1:-1;
  6104. }
  6105. /*==========================================
  6106. * Check if can attack from this range
  6107. * Basic check then calling path_search for obstacle etc..
  6108. *------------------------------------------
  6109. */
  6110. bool battle_check_range(struct block_list *src, struct block_list *bl, int range)
  6111. {
  6112. int d;
  6113. nullpo_retr(false, src);
  6114. nullpo_retr(false, bl);
  6115. if( src->m != bl->m )
  6116. return false;
  6117. #ifndef CIRCULAR_AREA
  6118. if( src->type == BL_PC ) { // Range for players' attacks and skills should always have a circular check. [Angezerus]
  6119. int dx = src->x - bl->x, dy = src->y - bl->y;
  6120. if( !check_distance(dx, dy, range) )
  6121. return false;
  6122. } else
  6123. #endif
  6124. if( !check_distance_bl(src, bl, range) )
  6125. return false;
  6126. if( (d = distance_bl(src, bl)) < 2 )
  6127. return true; // No need for path checking.
  6128. if( d > AREA_SIZE )
  6129. return false; // Avoid targetting objects beyond your range of sight.
  6130. return path_search_long(NULL,src->m,src->x,src->y,bl->x,bl->y,CELL_CHKWALL);
  6131. }
  6132. /*=============================================
  6133. * Battle.conf settings and default/max values
  6134. *---------------------------------------------
  6135. */
  6136. static const struct _battle_data {
  6137. const char* str;
  6138. int* val;
  6139. int defval;
  6140. int min;
  6141. int max;
  6142. } battle_data[] = {
  6143. { "warp_point_debug", &battle_config.warp_point_debug, 0, 0, 1, },
  6144. { "enable_critical", &battle_config.enable_critical, BL_PC, BL_NUL, BL_ALL, },
  6145. { "mob_critical_rate", &battle_config.mob_critical_rate, 100, 0, INT_MAX, },
  6146. { "critical_rate", &battle_config.critical_rate, 100, 0, INT_MAX, },
  6147. { "enable_baseatk", &battle_config.enable_baseatk, BL_PC|BL_HOM, BL_NUL, BL_ALL, },
  6148. { "enable_perfect_flee", &battle_config.enable_perfect_flee, BL_PC|BL_PET, BL_NUL, BL_ALL, },
  6149. { "casting_rate", &battle_config.cast_rate, 100, 0, INT_MAX, },
  6150. { "delay_rate", &battle_config.delay_rate, 100, 0, INT_MAX, },
  6151. { "delay_dependon_dex", &battle_config.delay_dependon_dex, 0, 0, 1, },
  6152. { "delay_dependon_agi", &battle_config.delay_dependon_agi, 0, 0, 1, },
  6153. { "skill_delay_attack_enable", &battle_config.sdelay_attack_enable, 0, 0, 1, },
  6154. { "left_cardfix_to_right", &battle_config.left_cardfix_to_right, 0, 0, 1, },
  6155. { "skill_add_range", &battle_config.skill_add_range, 0, 0, INT_MAX, },
  6156. { "skill_out_range_consume", &battle_config.skill_out_range_consume, 1, 0, 1, },
  6157. { "skillrange_by_distance", &battle_config.skillrange_by_distance, ~BL_PC, BL_NUL, BL_ALL, },
  6158. { "skillrange_from_weapon", &battle_config.use_weapon_skill_range, ~BL_PC, BL_NUL, BL_ALL, },
  6159. { "player_damage_delay_rate", &battle_config.pc_damage_delay_rate, 100, 0, INT_MAX, },
  6160. { "defunit_not_enemy", &battle_config.defnotenemy, 0, 0, 1, },
  6161. { "gvg_traps_target_all", &battle_config.vs_traps_bctall, BL_PC, BL_NUL, BL_ALL, },
  6162. { "traps_setting", &battle_config.traps_setting, 0, 0, 1, },
  6163. { "summon_flora_setting", &battle_config.summon_flora, 1|2, 0, 1|2, },
  6164. { "clear_skills_on_death", &battle_config.clear_unit_ondeath, BL_NUL, BL_NUL, BL_ALL, },
  6165. { "clear_skills_on_warp", &battle_config.clear_unit_onwarp, BL_ALL, BL_NUL, BL_ALL, },
  6166. { "random_monster_checklv", &battle_config.random_monster_checklv, 0, 0, 1, },
  6167. { "attribute_recover", &battle_config.attr_recover, 1, 0, 1, },
  6168. { "flooritem_lifetime", &battle_config.flooritem_lifetime, 60000, 1000, INT_MAX, },
  6169. { "item_auto_get", &battle_config.item_auto_get, 0, 0, 1, },
  6170. { "item_first_get_time", &battle_config.item_first_get_time, 3000, 0, INT_MAX, },
  6171. { "item_second_get_time", &battle_config.item_second_get_time, 1000, 0, INT_MAX, },
  6172. { "item_third_get_time", &battle_config.item_third_get_time, 1000, 0, INT_MAX, },
  6173. { "mvp_item_first_get_time", &battle_config.mvp_item_first_get_time, 10000, 0, INT_MAX, },
  6174. { "mvp_item_second_get_time", &battle_config.mvp_item_second_get_time, 10000, 0, INT_MAX, },
  6175. { "mvp_item_third_get_time", &battle_config.mvp_item_third_get_time, 2000, 0, INT_MAX, },
  6176. { "drop_rate0item", &battle_config.drop_rate0item, 0, 0, 1, },
  6177. { "base_exp_rate", &battle_config.base_exp_rate, 100, 0, INT_MAX, },
  6178. { "job_exp_rate", &battle_config.job_exp_rate, 100, 0, INT_MAX, },
  6179. { "pvp_exp", &battle_config.pvp_exp, 1, 0, 1, },
  6180. { "death_penalty_type", &battle_config.death_penalty_type, 0, 0, 2, },
  6181. { "death_penalty_base", &battle_config.death_penalty_base, 0, 0, INT_MAX, },
  6182. { "death_penalty_job", &battle_config.death_penalty_job, 0, 0, INT_MAX, },
  6183. { "zeny_penalty", &battle_config.zeny_penalty, 0, 0, INT_MAX, },
  6184. { "hp_rate", &battle_config.hp_rate, 100, 1, INT_MAX, },
  6185. { "sp_rate", &battle_config.sp_rate, 100, 1, INT_MAX, },
  6186. { "restart_hp_rate", &battle_config.restart_hp_rate, 0, 0, 100, },
  6187. { "restart_sp_rate", &battle_config.restart_sp_rate, 0, 0, 100, },
  6188. { "guild_aura", &battle_config.guild_aura, 31, 0, 31, },
  6189. { "mvp_hp_rate", &battle_config.mvp_hp_rate, 100, 1, INT_MAX, },
  6190. { "mvp_exp_rate", &battle_config.mvp_exp_rate, 100, 0, INT_MAX, },
  6191. { "monster_hp_rate", &battle_config.monster_hp_rate, 100, 1, INT_MAX, },
  6192. { "monster_max_aspd", &battle_config.monster_max_aspd, 199, 100, 199, },
  6193. { "view_range_rate", &battle_config.view_range_rate, 100, 0, INT_MAX, },
  6194. { "chase_range_rate", &battle_config.chase_range_rate, 100, 0, INT_MAX, },
  6195. { "gtb_sc_immunity", &battle_config.gtb_sc_immunity, 50, 0, INT_MAX, },
  6196. { "guild_max_castles", &battle_config.guild_max_castles, 0, 0, INT_MAX, },
  6197. { "guild_skill_relog_delay", &battle_config.guild_skill_relog_delay, 300000, 0, INT_MAX, },
  6198. { "emergency_call", &battle_config.emergency_call, 11, 0, 31, },
  6199. { "atcommand_spawn_quantity_limit", &battle_config.atc_spawn_quantity_limit, 100, 0, INT_MAX, },
  6200. { "atcommand_slave_clone_limit", &battle_config.atc_slave_clone_limit, 25, 0, INT_MAX, },
  6201. { "partial_name_scan", &battle_config.partial_name_scan, 0, 0, 1, },
  6202. { "player_skillfree", &battle_config.skillfree, 0, 0, 1, },
  6203. { "player_skillup_limit", &battle_config.skillup_limit, 1, 0, 1, },
  6204. { "weapon_produce_rate", &battle_config.wp_rate, 100, 0, INT_MAX, },
  6205. { "potion_produce_rate", &battle_config.pp_rate, 100, 0, INT_MAX, },
  6206. { "monster_active_enable", &battle_config.monster_active_enable, 1, 0, 1, },
  6207. { "monster_damage_delay_rate", &battle_config.monster_damage_delay_rate, 100, 0, INT_MAX, },
  6208. { "monster_loot_type", &battle_config.monster_loot_type, 0, 0, 1, },
  6209. // { "mob_skill_use", &battle_config.mob_skill_use, 1, 0, 1, }, //Deprecated
  6210. { "mob_skill_rate", &battle_config.mob_skill_rate, 100, 0, INT_MAX, },
  6211. { "mob_skill_delay", &battle_config.mob_skill_delay, 100, 0, INT_MAX, },
  6212. { "mob_count_rate", &battle_config.mob_count_rate, 100, 0, INT_MAX, },
  6213. { "mob_spawn_delay", &battle_config.mob_spawn_delay, 100, 0, INT_MAX, },
  6214. { "plant_spawn_delay", &battle_config.plant_spawn_delay, 100, 0, INT_MAX, },
  6215. { "boss_spawn_delay", &battle_config.boss_spawn_delay, 100, 0, INT_MAX, },
  6216. { "no_spawn_on_player", &battle_config.no_spawn_on_player, 0, 0, 100, },
  6217. { "force_random_spawn", &battle_config.force_random_spawn, 0, 0, 1, },
  6218. { "slaves_inherit_mode", &battle_config.slaves_inherit_mode, 2, 0, 3, },
  6219. { "slaves_inherit_speed", &battle_config.slaves_inherit_speed, 3, 0, 3, },
  6220. { "summons_trigger_autospells", &battle_config.summons_trigger_autospells, 1, 0, 1, },
  6221. { "pc_damage_walk_delay_rate", &battle_config.pc_walk_delay_rate, 20, 0, INT_MAX, },
  6222. { "damage_walk_delay_rate", &battle_config.walk_delay_rate, 100, 0, INT_MAX, },
  6223. { "multihit_delay", &battle_config.multihit_delay, 80, 0, INT_MAX, },
  6224. { "quest_skill_learn", &battle_config.quest_skill_learn, 0, 0, 1, },
  6225. { "quest_skill_reset", &battle_config.quest_skill_reset, 0, 0, 1, },
  6226. { "basic_skill_check", &battle_config.basic_skill_check, 1, 0, 1, },
  6227. { "guild_emperium_check", &battle_config.guild_emperium_check, 1, 0, 1, },
  6228. { "guild_exp_limit", &battle_config.guild_exp_limit, 50, 0, 99, },
  6229. { "player_invincible_time", &battle_config.pc_invincible_time, 5000, 0, INT_MAX, },
  6230. { "pet_catch_rate", &battle_config.pet_catch_rate, 100, 0, INT_MAX, },
  6231. { "pet_rename", &battle_config.pet_rename, 0, 0, 1, },
  6232. { "pet_friendly_rate", &battle_config.pet_friendly_rate, 100, 0, INT_MAX, },
  6233. { "pet_hungry_delay_rate", &battle_config.pet_hungry_delay_rate, 100, 10, INT_MAX, },
  6234. { "pet_hungry_friendly_decrease", &battle_config.pet_hungry_friendly_decrease, 5, 0, INT_MAX, },
  6235. { "pet_status_support", &battle_config.pet_status_support, 0, 0, 1, },
  6236. { "pet_attack_support", &battle_config.pet_attack_support, 0, 0, 1, },
  6237. { "pet_damage_support", &battle_config.pet_damage_support, 0, 0, 1, },
  6238. { "pet_support_min_friendly", &battle_config.pet_support_min_friendly, 900, 0, 950, },
  6239. { "pet_equip_min_friendly", &battle_config.pet_equip_min_friendly, 900, 0, 950, },
  6240. { "pet_support_rate", &battle_config.pet_support_rate, 100, 0, INT_MAX, },
  6241. { "pet_attack_exp_to_master", &battle_config.pet_attack_exp_to_master, 0, 0, 1, },
  6242. { "pet_attack_exp_rate", &battle_config.pet_attack_exp_rate, 100, 0, INT_MAX, },
  6243. { "pet_lv_rate", &battle_config.pet_lv_rate, 0, 0, INT_MAX, },
  6244. { "pet_max_stats", &battle_config.pet_max_stats, 99, 0, INT_MAX, },
  6245. { "pet_max_atk1", &battle_config.pet_max_atk1, 750, 0, INT_MAX, },
  6246. { "pet_max_atk2", &battle_config.pet_max_atk2, 1000, 0, INT_MAX, },
  6247. { "pet_disable_in_gvg", &battle_config.pet_no_gvg, 0, 0, 1, },
  6248. { "skill_min_damage", &battle_config.skill_min_damage, 2|4, 0, 1|2|4, },
  6249. { "finger_offensive_type", &battle_config.finger_offensive_type, 0, 0, 1, },
  6250. { "heal_exp", &battle_config.heal_exp, 0, 0, INT_MAX, },
  6251. { "resurrection_exp", &battle_config.resurrection_exp, 0, 0, INT_MAX, },
  6252. { "shop_exp", &battle_config.shop_exp, 0, 0, INT_MAX, },
  6253. { "max_heal_lv", &battle_config.max_heal_lv, 11, 1, INT_MAX, },
  6254. { "max_heal", &battle_config.max_heal, 9999, 0, INT_MAX, },
  6255. { "combo_delay_rate", &battle_config.combo_delay_rate, 100, 0, INT_MAX, },
  6256. { "item_check", &battle_config.item_check, 0, 0, 1, },
  6257. { "item_use_interval", &battle_config.item_use_interval, 100, 0, INT_MAX, },
  6258. { "cashfood_use_interval", &battle_config.cashfood_use_interval, 60000, 0, INT_MAX, },
  6259. { "wedding_modifydisplay", &battle_config.wedding_modifydisplay, 0, 0, 1, },
  6260. { "wedding_ignorepalette", &battle_config.wedding_ignorepalette, 0, 0, 1, },
  6261. { "xmas_ignorepalette", &battle_config.xmas_ignorepalette, 0, 0, 1, },
  6262. { "summer_ignorepalette", &battle_config.summer_ignorepalette, 0, 0, 1, },
  6263. { "hanbok_ignorepalette", &battle_config.hanbok_ignorepalette, 0, 0, 1, },
  6264. { "natural_healhp_interval", &battle_config.natural_healhp_interval, 6000, NATURAL_HEAL_INTERVAL, INT_MAX, },
  6265. { "natural_healsp_interval", &battle_config.natural_healsp_interval, 8000, NATURAL_HEAL_INTERVAL, INT_MAX, },
  6266. { "natural_heal_skill_interval", &battle_config.natural_heal_skill_interval, 10000, NATURAL_HEAL_INTERVAL, INT_MAX, },
  6267. { "natural_heal_weight_rate", &battle_config.natural_heal_weight_rate, 50, 50, 101 },
  6268. { "arrow_decrement", &battle_config.arrow_decrement, 1, 0, 2, },
  6269. { "max_aspd", &battle_config.max_aspd, 190, 100, 199, },
  6270. { "max_third_aspd", &battle_config.max_third_aspd, 193, 100, 199, },
  6271. { "max_walk_speed", &battle_config.max_walk_speed, 300, 100, 100*DEFAULT_WALK_SPEED, },
  6272. { "max_lv", &battle_config.max_lv, 99, 0, MAX_LEVEL, },
  6273. { "aura_lv", &battle_config.aura_lv, 99, 0, INT_MAX, },
  6274. { "max_hp", &battle_config.max_hp, 32500, 100, 1000000000, },
  6275. { "max_sp", &battle_config.max_sp, 32500, 100, 1000000000, },
  6276. { "max_cart_weight", &battle_config.max_cart_weight, 8000, 100, 1000000, },
  6277. { "max_parameter", &battle_config.max_parameter, 99, 10, 10000, },
  6278. { "max_baby_parameter", &battle_config.max_baby_parameter, 80, 10, 10000, },
  6279. { "max_def", &battle_config.max_def, 99, 0, INT_MAX, },
  6280. { "over_def_bonus", &battle_config.over_def_bonus, 0, 0, 1000, },
  6281. { "skill_log", &battle_config.skill_log, BL_NUL, BL_NUL, BL_ALL, },
  6282. { "battle_log", &battle_config.battle_log, 0, 0, 1, },
  6283. { "etc_log", &battle_config.etc_log, 1, 0, 1, },
  6284. { "save_clothcolor", &battle_config.save_clothcolor, 1, 0, 1, },
  6285. { "undead_detect_type", &battle_config.undead_detect_type, 0, 0, 2, },
  6286. { "auto_counter_type", &battle_config.auto_counter_type, BL_ALL, BL_NUL, BL_ALL, },
  6287. { "min_hitrate", &battle_config.min_hitrate, 5, 0, 100, },
  6288. { "max_hitrate", &battle_config.max_hitrate, 100, 0, 100, },
  6289. { "agi_penalty_target", &battle_config.agi_penalty_target, BL_PC, BL_NUL, BL_ALL, },
  6290. { "agi_penalty_type", &battle_config.agi_penalty_type, 1, 0, 2, },
  6291. { "agi_penalty_count", &battle_config.agi_penalty_count, 3, 2, INT_MAX, },
  6292. { "agi_penalty_num", &battle_config.agi_penalty_num, 10, 0, INT_MAX, },
  6293. { "vit_penalty_target", &battle_config.vit_penalty_target, BL_PC, BL_NUL, BL_ALL, },
  6294. { "vit_penalty_type", &battle_config.vit_penalty_type, 1, 0, 2, },
  6295. { "vit_penalty_count", &battle_config.vit_penalty_count, 3, 2, INT_MAX, },
  6296. { "vit_penalty_num", &battle_config.vit_penalty_num, 5, 0, INT_MAX, },
  6297. { "weapon_defense_type", &battle_config.weapon_defense_type, 0, 0, INT_MAX, },
  6298. { "magic_defense_type", &battle_config.magic_defense_type, 0, 0, INT_MAX, },
  6299. { "skill_reiteration", &battle_config.skill_reiteration, BL_NUL, BL_NUL, BL_ALL, },
  6300. { "skill_nofootset", &battle_config.skill_nofootset, BL_PC, BL_NUL, BL_ALL, },
  6301. { "player_cloak_check_type", &battle_config.pc_cloak_check_type, 1, 0, 1|2|4, },
  6302. { "monster_cloak_check_type", &battle_config.monster_cloak_check_type, 4, 0, 1|2|4, },
  6303. { "sense_type", &battle_config.estimation_type, 1|2, 0, 1|2, },
  6304. { "gvg_short_attack_damage_rate", &battle_config.gvg_short_damage_rate, 80, 0, INT_MAX, },
  6305. { "gvg_long_attack_damage_rate", &battle_config.gvg_long_damage_rate, 80, 0, INT_MAX, },
  6306. { "gvg_weapon_attack_damage_rate", &battle_config.gvg_weapon_damage_rate, 60, 0, INT_MAX, },
  6307. { "gvg_magic_attack_damage_rate", &battle_config.gvg_magic_damage_rate, 60, 0, INT_MAX, },
  6308. { "gvg_misc_attack_damage_rate", &battle_config.gvg_misc_damage_rate, 60, 0, INT_MAX, },
  6309. { "gvg_flee_penalty", &battle_config.gvg_flee_penalty, 20, 0, INT_MAX, },
  6310. { "pk_short_attack_damage_rate", &battle_config.pk_short_damage_rate, 80, 0, INT_MAX, },
  6311. { "pk_long_attack_damage_rate", &battle_config.pk_long_damage_rate, 70, 0, INT_MAX, },
  6312. { "pk_weapon_attack_damage_rate", &battle_config.pk_weapon_damage_rate, 60, 0, INT_MAX, },
  6313. { "pk_magic_attack_damage_rate", &battle_config.pk_magic_damage_rate, 60, 0, INT_MAX, },
  6314. { "pk_misc_attack_damage_rate", &battle_config.pk_misc_damage_rate, 60, 0, INT_MAX, },
  6315. { "mob_changetarget_byskill", &battle_config.mob_changetarget_byskill, 0, 0, 1, },
  6316. { "attack_direction_change", &battle_config.attack_direction_change, BL_ALL, BL_NUL, BL_ALL, },
  6317. { "land_skill_limit", &battle_config.land_skill_limit, BL_ALL, BL_NUL, BL_ALL, },
  6318. { "monster_class_change_full_recover", &battle_config.monster_class_change_recover, 1, 0, 1, },
  6319. { "produce_item_name_input", &battle_config.produce_item_name_input, 0x1|0x2, 0, 0x9F, },
  6320. { "display_skill_fail", &battle_config.display_skill_fail, 2, 0, 1|2|4|8, },
  6321. { "chat_warpportal", &battle_config.chat_warpportal, 0, 0, 1, },
  6322. { "mob_warp", &battle_config.mob_warp, 0, 0, 1|2|4, },
  6323. { "dead_branch_active", &battle_config.dead_branch_active, 1, 0, 1, },
  6324. { "vending_max_value", &battle_config.vending_max_value, 10000000, 1, MAX_ZENY, },
  6325. { "vending_over_max", &battle_config.vending_over_max, 1, 0, 1, },
  6326. { "show_steal_in_same_party", &battle_config.show_steal_in_same_party, 0, 0, 1, },
  6327. { "party_hp_mode", &battle_config.party_hp_mode, 0, 0, 1, },
  6328. { "show_party_share_picker", &battle_config.party_show_share_picker, 1, 0, 1, },
  6329. { "show_picker.item_type", &battle_config.show_picker_item_type, 112, 0, INT_MAX, },
  6330. { "party_update_interval", &battle_config.party_update_interval, 1000, 100, INT_MAX, },
  6331. { "party_item_share_type", &battle_config.party_share_type, 0, 0, 1|2|3, },
  6332. { "attack_attr_none", &battle_config.attack_attr_none, ~BL_PC, BL_NUL, BL_ALL, },
  6333. { "gx_allhit", &battle_config.gx_allhit, 0, 0, 1, },
  6334. { "gx_disptype", &battle_config.gx_disptype, 1, 0, 1, },
  6335. { "devotion_level_difference", &battle_config.devotion_level_difference, 10, 0, INT_MAX, },
  6336. { "player_skill_partner_check", &battle_config.player_skill_partner_check, 1, 0, 1, },
  6337. { "invite_request_check", &battle_config.invite_request_check, 1, 0, 1, },
  6338. { "skill_removetrap_type", &battle_config.skill_removetrap_type, 0, 0, 1, },
  6339. { "disp_experience", &battle_config.disp_experience, 0, 0, 1, },
  6340. { "disp_zeny", &battle_config.disp_zeny, 0, 0, 1, },
  6341. { "castle_defense_rate", &battle_config.castle_defense_rate, 100, 0, 100, },
  6342. { "bone_drop", &battle_config.bone_drop, 0, 0, 2, },
  6343. { "buyer_name", &battle_config.buyer_name, 1, 0, 1, },
  6344. { "skill_wall_check", &battle_config.skill_wall_check, 1, 0, 1, },
  6345. { "cell_stack_limit", &battle_config.cell_stack_limit, 1, 1, 255, },
  6346. { "dancing_weaponswitch_fix", &battle_config.dancing_weaponswitch_fix, 1, 0, 1, },
  6347. // eAthena additions
  6348. { "item_logarithmic_drops", &battle_config.logarithmic_drops, 0, 0, 1, },
  6349. { "item_drop_common_min", &battle_config.item_drop_common_min, 1, 1, 10000, },
  6350. { "item_drop_common_max", &battle_config.item_drop_common_max, 10000, 1, 10000, },
  6351. { "item_drop_equip_min", &battle_config.item_drop_equip_min, 1, 1, 10000, },
  6352. { "item_drop_equip_max", &battle_config.item_drop_equip_max, 10000, 1, 10000, },
  6353. { "item_drop_card_min", &battle_config.item_drop_card_min, 1, 1, 10000, },
  6354. { "item_drop_card_max", &battle_config.item_drop_card_max, 10000, 1, 10000, },
  6355. { "item_drop_mvp_min", &battle_config.item_drop_mvp_min, 1, 1, 10000, },
  6356. { "item_drop_mvp_max", &battle_config.item_drop_mvp_max, 10000, 1, 10000, },
  6357. { "item_drop_heal_min", &battle_config.item_drop_heal_min, 1, 1, 10000, },
  6358. { "item_drop_heal_max", &battle_config.item_drop_heal_max, 10000, 1, 10000, },
  6359. { "item_drop_use_min", &battle_config.item_drop_use_min, 1, 1, 10000, },
  6360. { "item_drop_use_max", &battle_config.item_drop_use_max, 10000, 1, 10000, },
  6361. { "item_drop_add_min", &battle_config.item_drop_adddrop_min, 1, 1, 10000, },
  6362. { "item_drop_add_max", &battle_config.item_drop_adddrop_max, 10000, 1, 10000, },
  6363. { "item_drop_treasure_min", &battle_config.item_drop_treasure_min, 1, 1, 10000, },
  6364. { "item_drop_treasure_max", &battle_config.item_drop_treasure_max, 10000, 1, 10000, },
  6365. { "item_rate_mvp", &battle_config.item_rate_mvp, 100, 0, 1000000, },
  6366. { "item_rate_common", &battle_config.item_rate_common, 100, 0, 1000000, },
  6367. { "item_rate_common_boss", &battle_config.item_rate_common_boss, 100, 0, 1000000, },
  6368. { "item_rate_equip", &battle_config.item_rate_equip, 100, 0, 1000000, },
  6369. { "item_rate_equip_boss", &battle_config.item_rate_equip_boss, 100, 0, 1000000, },
  6370. { "item_rate_card", &battle_config.item_rate_card, 100, 0, 1000000, },
  6371. { "item_rate_card_boss", &battle_config.item_rate_card_boss, 100, 0, 1000000, },
  6372. { "item_rate_heal", &battle_config.item_rate_heal, 100, 0, 1000000, },
  6373. { "item_rate_heal_boss", &battle_config.item_rate_heal_boss, 100, 0, 1000000, },
  6374. { "item_rate_use", &battle_config.item_rate_use, 100, 0, 1000000, },
  6375. { "item_rate_use_boss", &battle_config.item_rate_use_boss, 100, 0, 1000000, },
  6376. { "item_rate_adddrop", &battle_config.item_rate_adddrop, 100, 0, 1000000, },
  6377. { "item_rate_treasure", &battle_config.item_rate_treasure, 100, 0, 1000000, },
  6378. { "prevent_logout", &battle_config.prevent_logout, 10000, 0, 60000, },
  6379. { "alchemist_summon_reward", &battle_config.alchemist_summon_reward, 1, 0, 2, },
  6380. { "drops_by_luk", &battle_config.drops_by_luk, 0, 0, INT_MAX, },
  6381. { "drops_by_luk2", &battle_config.drops_by_luk2, 0, 0, INT_MAX, },
  6382. { "equip_natural_break_rate", &battle_config.equip_natural_break_rate, 0, 0, INT_MAX, },
  6383. { "equip_self_break_rate", &battle_config.equip_self_break_rate, 100, 0, INT_MAX, },
  6384. { "equip_skill_break_rate", &battle_config.equip_skill_break_rate, 100, 0, INT_MAX, },
  6385. { "pk_mode", &battle_config.pk_mode, 0, 0, 2, },
  6386. { "pk_level_range", &battle_config.pk_level_range, 0, 0, INT_MAX, },
  6387. { "manner_system", &battle_config.manner_system, 0xFFF, 0, 0xFFF, },
  6388. { "pet_equip_required", &battle_config.pet_equip_required, 0, 0, 1, },
  6389. { "multi_level_up", &battle_config.multi_level_up, 0, 0, 1, },
  6390. { "max_exp_gain_rate", &battle_config.max_exp_gain_rate, 0, 0, INT_MAX, },
  6391. { "backstab_bow_penalty", &battle_config.backstab_bow_penalty, 0, 0, 1, },
  6392. { "night_at_start", &battle_config.night_at_start, 0, 0, 1, },
  6393. { "show_mob_info", &battle_config.show_mob_info, 0, 0, 1|2|4, },
  6394. { "ban_hack_trade", &battle_config.ban_hack_trade, 0, 0, INT_MAX, },
  6395. { "packet_ver_flag", &battle_config.packet_ver_flag, 0x7FFFFFFF,0, INT_MAX, },
  6396. { "packet_ver_flag2", &battle_config.packet_ver_flag2, 0x7FFFFFFF,0, INT_MAX, },
  6397. { "min_hair_style", &battle_config.min_hair_style, 0, 0, INT_MAX, },
  6398. { "max_hair_style", &battle_config.max_hair_style, 23, 0, INT_MAX, },
  6399. { "min_hair_color", &battle_config.min_hair_color, 0, 0, INT_MAX, },
  6400. { "max_hair_color", &battle_config.max_hair_color, 9, 0, INT_MAX, },
  6401. { "min_cloth_color", &battle_config.min_cloth_color, 0, 0, INT_MAX, },
  6402. { "max_cloth_color", &battle_config.max_cloth_color, 4, 0, INT_MAX, },
  6403. { "pet_hair_style", &battle_config.pet_hair_style, 100, 0, INT_MAX, },
  6404. { "castrate_dex_scale", &battle_config.castrate_dex_scale, 150, 1, INT_MAX, },
  6405. { "vcast_stat_scale", &battle_config.vcast_stat_scale, 530, 1, INT_MAX, },
  6406. { "area_size", &battle_config.area_size, 14, 0, INT_MAX, },
  6407. { "zeny_from_mobs", &battle_config.zeny_from_mobs, 0, 0, 1, },
  6408. { "mobs_level_up", &battle_config.mobs_level_up, 0, 0, 1, },
  6409. { "mobs_level_up_exp_rate", &battle_config.mobs_level_up_exp_rate, 1, 1, INT_MAX, },
  6410. { "pk_min_level", &battle_config.pk_min_level, 55, 1, INT_MAX, },
  6411. { "skill_steal_max_tries", &battle_config.skill_steal_max_tries, 0, 0, UCHAR_MAX, },
  6412. { "motd_type", &battle_config.motd_type, 0, 0, 1, },
  6413. { "finding_ore_rate", &battle_config.finding_ore_rate, 100, 0, INT_MAX, },
  6414. { "exp_calc_type", &battle_config.exp_calc_type, 0, 0, 1, },
  6415. { "exp_bonus_attacker", &battle_config.exp_bonus_attacker, 25, 0, INT_MAX, },
  6416. { "exp_bonus_max_attacker", &battle_config.exp_bonus_max_attacker, 12, 2, INT_MAX, },
  6417. { "min_skill_delay_limit", &battle_config.min_skill_delay_limit, 100, 10, INT_MAX, },
  6418. { "default_walk_delay", &battle_config.default_walk_delay, 300, 0, INT_MAX, },
  6419. { "no_skill_delay", &battle_config.no_skill_delay, BL_MOB, BL_NUL, BL_ALL, },
  6420. { "attack_walk_delay", &battle_config.attack_walk_delay, BL_ALL, BL_NUL, BL_ALL, },
  6421. { "require_glory_guild", &battle_config.require_glory_guild, 0, 0, 1, },
  6422. { "idle_no_share", &battle_config.idle_no_share, 0, 0, INT_MAX, },
  6423. { "party_even_share_bonus", &battle_config.party_even_share_bonus, 0, 0, INT_MAX, },
  6424. { "delay_battle_damage", &battle_config.delay_battle_damage, 1, 0, 1, },
  6425. { "hide_woe_damage", &battle_config.hide_woe_damage, 0, 0, 1, },
  6426. { "display_version", &battle_config.display_version, 1, 0, 1, },
  6427. { "display_hallucination", &battle_config.display_hallucination, 1, 0, 1, },
  6428. { "use_statpoint_table", &battle_config.use_statpoint_table, 1, 0, 1, },
  6429. { "ignore_items_gender", &battle_config.ignore_items_gender, 1, 0, 1, },
  6430. { "berserk_cancels_buffs", &battle_config.berserk_cancels_buffs, 0, 0, 1, },
  6431. { "debuff_on_logout", &battle_config.debuff_on_logout, 1|2, 0, 1|2, },
  6432. { "monster_ai", &battle_config.mob_ai, 0x000, 0x000, 0x77F, },
  6433. { "hom_setting", &battle_config.hom_setting, 0xFFFF, 0x0000, 0xFFFF, },
  6434. { "dynamic_mobs", &battle_config.dynamic_mobs, 1, 0, 1, },
  6435. { "mob_remove_damaged", &battle_config.mob_remove_damaged, 1, 0, 1, },
  6436. { "show_hp_sp_drain", &battle_config.show_hp_sp_drain, 0, 0, 1, },
  6437. { "show_hp_sp_gain", &battle_config.show_hp_sp_gain, 1, 0, 1, },
  6438. { "mob_npc_event_type", &battle_config.mob_npc_event_type, 1, 0, 1, },
  6439. { "character_size", &battle_config.character_size, 1|2, 0, 1|2, },
  6440. { "mob_max_skilllvl", &battle_config.mob_max_skilllvl, MAX_SKILL_LEVEL, 1, MAX_SKILL_LEVEL, },
  6441. { "retaliate_to_master", &battle_config.retaliate_to_master, 1, 0, 1, },
  6442. { "rare_drop_announce", &battle_config.rare_drop_announce, 0, 0, 10000, },
  6443. { "duel_allow_pvp", &battle_config.duel_allow_pvp, 0, 0, 1, },
  6444. { "duel_allow_gvg", &battle_config.duel_allow_gvg, 0, 0, 1, },
  6445. { "duel_allow_teleport", &battle_config.duel_allow_teleport, 0, 0, 1, },
  6446. { "duel_autoleave_when_die", &battle_config.duel_autoleave_when_die, 1, 0, 1, },
  6447. { "duel_time_interval", &battle_config.duel_time_interval, 60, 0, INT_MAX, },
  6448. { "duel_only_on_same_map", &battle_config.duel_only_on_same_map, 0, 0, 1, },
  6449. { "skip_teleport_lv1_menu", &battle_config.skip_teleport_lv1_menu, 0, 0, 1, },
  6450. { "allow_skill_without_day", &battle_config.allow_skill_without_day, 0, 0, 1, },
  6451. { "allow_es_magic_player", &battle_config.allow_es_magic_pc, 0, 0, 1, },
  6452. { "skill_caster_check", &battle_config.skill_caster_check, 1, 0, 1, },
  6453. { "status_cast_cancel", &battle_config.sc_castcancel, BL_NUL, BL_NUL, BL_ALL, },
  6454. { "pc_status_def_rate", &battle_config.pc_sc_def_rate, 100, 0, INT_MAX, },
  6455. { "mob_status_def_rate", &battle_config.mob_sc_def_rate, 100, 0, INT_MAX, },
  6456. { "pc_max_status_def", &battle_config.pc_max_sc_def, 100, 0, INT_MAX, },
  6457. { "mob_max_status_def", &battle_config.mob_max_sc_def, 100, 0, INT_MAX, },
  6458. { "sg_miracle_skill_ratio", &battle_config.sg_miracle_skill_ratio, 1, 0, 10000, },
  6459. { "sg_angel_skill_ratio", &battle_config.sg_angel_skill_ratio, 10, 0, 10000, },
  6460. { "autospell_stacking", &battle_config.autospell_stacking, 0, 0, 1, },
  6461. { "override_mob_names", &battle_config.override_mob_names, 0, 0, 2, },
  6462. { "min_chat_delay", &battle_config.min_chat_delay, 0, 0, INT_MAX, },
  6463. { "friend_auto_add", &battle_config.friend_auto_add, 1, 0, 1, },
  6464. { "hom_rename", &battle_config.hom_rename, 0, 0, 1, },
  6465. { "homunculus_show_growth", &battle_config.homunculus_show_growth, 0, 0, 1, },
  6466. { "homunculus_friendly_rate", &battle_config.homunculus_friendly_rate, 100, 0, INT_MAX, },
  6467. { "vending_tax", &battle_config.vending_tax, 0, 0, 10000, },
  6468. { "day_duration", &battle_config.day_duration, 0, 0, INT_MAX, },
  6469. { "night_duration", &battle_config.night_duration, 0, 0, INT_MAX, },
  6470. { "mob_remove_delay", &battle_config.mob_remove_delay, 60000, 1000, INT_MAX, },
  6471. { "mob_active_time", &battle_config.mob_active_time, 0, 0, INT_MAX, },
  6472. { "boss_active_time", &battle_config.boss_active_time, 0, 0, INT_MAX, },
  6473. { "sg_miracle_skill_duration", &battle_config.sg_miracle_skill_duration, 3600000, 0, INT_MAX, },
  6474. { "hvan_explosion_intimate", &battle_config.hvan_explosion_intimate, 45000, 0, 100000, },
  6475. { "quest_exp_rate", &battle_config.quest_exp_rate, 100, 0, INT_MAX, },
  6476. { "at_mapflag", &battle_config.autotrade_mapflag, 0, 0, 1, },
  6477. { "at_timeout", &battle_config.at_timeout, 0, 0, INT_MAX, },
  6478. { "homunculus_autoloot", &battle_config.homunculus_autoloot, 0, 0, 1, },
  6479. { "idle_no_autoloot", &battle_config.idle_no_autoloot, 0, 0, INT_MAX, },
  6480. { "max_guild_alliance", &battle_config.max_guild_alliance, 3, 0, 3, },
  6481. { "ksprotection", &battle_config.ksprotection, 5000, 0, INT_MAX, },
  6482. { "auction_feeperhour", &battle_config.auction_feeperhour, 12000, 0, INT_MAX, },
  6483. { "auction_maximumprice", &battle_config.auction_maximumprice, 500000000, 0, MAX_ZENY, },
  6484. { "homunculus_auto_vapor", &battle_config.homunculus_auto_vapor, 1, 0, 1, },
  6485. { "display_status_timers", &battle_config.display_status_timers, 1, 0, 1, },
  6486. { "skill_add_heal_rate", &battle_config.skill_add_heal_rate, 7, 0, INT_MAX, },
  6487. { "eq_single_target_reflectable", &battle_config.eq_single_target_reflectable, 1, 0, 1, },
  6488. { "invincible.nodamage", &battle_config.invincible_nodamage, 0, 0, 1, },
  6489. { "mob_slave_keep_target", &battle_config.mob_slave_keep_target, 0, 0, 1, },
  6490. { "autospell_check_range", &battle_config.autospell_check_range, 0, 0, 1, },
  6491. { "client_reshuffle_dice", &battle_config.client_reshuffle_dice, 0, 0, 1, },
  6492. { "client_sort_storage", &battle_config.client_sort_storage, 0, 0, 1, },
  6493. { "feature.buying_store", &battle_config.feature_buying_store, 1, 0, 1, },
  6494. { "feature.search_stores", &battle_config.feature_search_stores, 1, 0, 1, },
  6495. { "searchstore_querydelay", &battle_config.searchstore_querydelay, 10, 0, INT_MAX, },
  6496. { "searchstore_maxresults", &battle_config.searchstore_maxresults, 30, 1, INT_MAX, },
  6497. { "display_party_name", &battle_config.display_party_name, 0, 0, 1, },
  6498. { "cashshop_show_points", &battle_config.cashshop_show_points, 0, 0, 1, },
  6499. { "mail_show_status", &battle_config.mail_show_status, 0, 0, 2, },
  6500. { "client_limit_unit_lv", &battle_config.client_limit_unit_lv, 0, 0, BL_ALL, },
  6501. // BattleGround Settings
  6502. { "bg_update_interval", &battle_config.bg_update_interval, 1000, 100, INT_MAX, },
  6503. { "bg_short_attack_damage_rate", &battle_config.bg_short_damage_rate, 80, 0, INT_MAX, },
  6504. { "bg_long_attack_damage_rate", &battle_config.bg_long_damage_rate, 80, 0, INT_MAX, },
  6505. { "bg_weapon_attack_damage_rate", &battle_config.bg_weapon_damage_rate, 60, 0, INT_MAX, },
  6506. { "bg_magic_attack_damage_rate", &battle_config.bg_magic_damage_rate, 60, 0, INT_MAX, },
  6507. { "bg_misc_attack_damage_rate", &battle_config.bg_misc_damage_rate, 60, 0, INT_MAX, },
  6508. { "bg_flee_penalty", &battle_config.bg_flee_penalty, 20, 0, INT_MAX, },
  6509. /**
  6510. * rAthena
  6511. **/
  6512. { "max_third_parameter", &battle_config.max_third_parameter, 120, 10, 10000, },
  6513. { "max_baby_third_parameter", &battle_config.max_baby_third_parameter, 108, 10, 10000, },
  6514. { "atcommand_max_stat_bypass", &battle_config.atcommand_max_stat_bypass, 0, 0, 100, },
  6515. { "skill_amotion_leniency", &battle_config.skill_amotion_leniency, 90, 0, 300 },
  6516. { "mvp_tomb_enabled", &battle_config.mvp_tomb_enabled, 1, 0, 1 },
  6517. { "feature.atcommand_suggestions", &battle_config.atcommand_suggestions_enabled, 0, 0, 1 },
  6518. { "min_npc_vendchat_distance", &battle_config.min_npc_vendchat_distance, 3, 0, 100 },
  6519. { "atcommand_mobinfo_type", &battle_config.atcommand_mobinfo_type, 0, 0, 1 },
  6520. { "homunculus_max_level", &battle_config.hom_max_level, 99, 0, MAX_LEVEL, },
  6521. { "homunculus_S_max_level", &battle_config.hom_S_max_level, 150, 0, MAX_LEVEL, },
  6522. { "mob_size_influence", &battle_config.mob_size_influence, 0, 0, 1, },
  6523. { "skill_trap_type", &battle_config.skill_trap_type, 0, 0, 1, },
  6524. { "allow_consume_restricted_item", &battle_config.allow_consume_restricted_item, 1, 0, 1, },
  6525. { "allow_equip_restricted_item", &battle_config.allow_equip_restricted_item, 1, 0, 1, },
  6526. { "max_walk_path", &battle_config.max_walk_path, 17, 1, MAX_WALKPATH, },
  6527. { "item_enabled_npc", &battle_config.item_enabled_npc, 1, 0, 1, },
  6528. { "item_flooritem_check", &battle_config.item_onfloor, 1, 0, 1, },
  6529. { "bowling_bash_area", &battle_config.bowling_bash_area, 0, 0, 20, },
  6530. { "drop_rateincrease", &battle_config.drop_rateincrease, 0, 0, 1, },
  6531. };
  6532. #ifndef STATS_OPT_OUT
  6533. /**
  6534. * rAthena anonymous statistic usage report -- packet is built here, and sent to char server to report.
  6535. **/
  6536. void rAthena_report(char* date, char *time_c) {
  6537. int i, rev = 0, bd_size = ARRAYLENGTH(battle_data);
  6538. unsigned int config = 0;
  6539. const char* rev_str;
  6540. char timestring[25];
  6541. time_t curtime;
  6542. char* buf;
  6543. enum config_table {
  6544. C_CIRCULAR_AREA = 0x0001,
  6545. C_CELLNOSTACK = 0x0002,
  6546. C_BETA_THREAD_TEST = 0x0004,
  6547. C_SCRIPT_CALLFUNC_CHECK = 0x0008,
  6548. C_OFFICIAL_WALKPATH = 0x0010,
  6549. C_RENEWAL = 0x0020,
  6550. C_RENEWAL_CAST = 0x0040,
  6551. C_RENEWAL_DROP = 0x0080,
  6552. C_RENEWAL_EXP = 0x0100,
  6553. C_RENEWAL_LVDMG = 0x0200,
  6554. C_RENEWAL_ASPD = 0x0400,
  6555. C_SECURE_NPCTIMEOUT = 0x0800,
  6556. C_SQL_DBS = 0x1000,
  6557. C_SQL_LOGS = 0x2000,
  6558. };
  6559. if( (rev_str = get_svn_revision()) != 0 )
  6560. rev = atoi(rev_str);
  6561. /* we get the current time */
  6562. time(&curtime);
  6563. strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", localtime(&curtime));
  6564. // Various compile-time options
  6565. #ifdef CIRCULAR_AREA
  6566. config |= C_CIRCULAR_AREA;
  6567. #endif
  6568. #ifdef CELL_NOSTACK
  6569. config |= C_CELLNOSTACK;
  6570. #endif
  6571. #ifdef BETA_THREAD_TEST
  6572. config |= C_BETA_THREAD_TEST;
  6573. #endif
  6574. #ifdef SCRIPT_CALLFUNC_CHECK
  6575. config |= C_SCRIPT_CALLFUNC_CHECK;
  6576. #endif
  6577. #ifdef OFFICIAL_WALKPATH
  6578. config |= C_OFFICIAL_WALKPATH;
  6579. #endif
  6580. #ifdef RENEWAL
  6581. config |= C_RENEWAL;
  6582. #endif
  6583. #ifdef RENEWAL_CAST
  6584. config |= C_RENEWAL_CAST;
  6585. #endif
  6586. #ifdef RENEWAL_DROP
  6587. config |= C_RENEWAL_DROP;
  6588. #endif
  6589. #ifdef RENEWAL_EXP
  6590. config |= C_RENEWAL_EXP;
  6591. #endif
  6592. #ifdef RENEWAL_LVDMG
  6593. config |= C_RENEWAL_LVDMG;
  6594. #endif
  6595. #ifdef RENEWAL_ASPD
  6596. config |= C_RENEWAL_ASPD;
  6597. #endif
  6598. #ifdef SECURE_NPCTIMEOUT
  6599. config |= C_SECURE_NPCTIMEOUT;
  6600. #endif
  6601. /* non-define part */
  6602. if( db_use_sqldbs )
  6603. config |= C_SQL_DBS;
  6604. if( log_config.sql_logs )
  6605. config |= C_SQL_LOGS;
  6606. #define BFLAG_LENGTH 35
  6607. CREATE(buf, char, 6 + 12 + 9 + 24 + 4 + 4 + 4 + 4 + ( bd_size * ( BFLAG_LENGTH + 4 ) ) + 1 );
  6608. /* build packet */
  6609. WBUFW(buf,0) = 0x3000;
  6610. WBUFW(buf,2) = 6 + 12 + 9 + 24 + 4 + 4 + 4 + 4 + ( bd_size * ( BFLAG_LENGTH + 4 ) );
  6611. WBUFW(buf,4) = 0x9c;
  6612. safestrncpy((char*)WBUFP(buf,6), date, 12);
  6613. safestrncpy((char*)WBUFP(buf,6 + 12), time_c, 9);
  6614. safestrncpy((char*)WBUFP(buf,6 + 12 + 9), timestring, 24);
  6615. WBUFL(buf,6 + 12 + 9 + 24) = rev;
  6616. WBUFL(buf,6 + 12 + 9 + 24 + 4) = map_getusers();
  6617. WBUFL(buf,6 + 12 + 9 + 24 + 4 + 4) = config;
  6618. WBUFL(buf,6 + 12 + 9 + 24 + 4 + 4 + 4) = bd_size;
  6619. for( i = 0; i < bd_size; i++ ) {
  6620. safestrncpy((char*)WBUFP(buf,6 + 12 + 9+ 24 + 4 + 4 + 4 + 4 + ( i * ( BFLAG_LENGTH + 4 ) ) ), battle_data[i].str, 35);
  6621. WBUFL(buf,6 + 12 + 9 + 24 + 4 + 4 + 4 + 4 + BFLAG_LENGTH + ( i * ( BFLAG_LENGTH + 4 ) ) ) = *battle_data[i].val;
  6622. }
  6623. chrif_send_report(buf, 6 + 12 + 9 + 24 + 4 + 4 + 4 + 4 + ( bd_size * ( BFLAG_LENGTH + 4 ) ) );
  6624. aFree(buf);
  6625. #undef BFLAG_LENGTH
  6626. }
  6627. static int rAthena_report_timer(int tid, unsigned int tick, int id, intptr_t data) {
  6628. if( chrif_isconnected() ) {/* char server relays it, so it must be online. */
  6629. rAthena_report(__DATE__,__TIME__);
  6630. }
  6631. return 0;
  6632. }
  6633. #endif
  6634. /*==========================
  6635. * Set battle settings
  6636. *--------------------------*/
  6637. int battle_set_value(const char* w1, const char* w2)
  6638. {
  6639. int val = config_switch(w2);
  6640. int i;
  6641. ARR_FIND(0, ARRAYLENGTH(battle_data), i, strcmpi(w1, battle_data[i].str) == 0);
  6642. if (i == ARRAYLENGTH(battle_data))
  6643. return 0; // not found
  6644. if (val < battle_data[i].min || val > battle_data[i].max)
  6645. {
  6646. ShowWarning("Value for setting '%s': %s is invalid (min:%i max:%i)! Defaulting to %i...\n", w1, w2, battle_data[i].min, battle_data[i].max, battle_data[i].defval);
  6647. val = battle_data[i].defval;
  6648. }
  6649. *battle_data[i].val = val;
  6650. return 1;
  6651. }
  6652. /*===========================
  6653. * Get battle settings
  6654. *---------------------------*/
  6655. int battle_get_value(const char* w1)
  6656. {
  6657. int i;
  6658. ARR_FIND(0, ARRAYLENGTH(battle_data), i, strcmpi(w1, battle_data[i].str) == 0);
  6659. if (i == ARRAYLENGTH(battle_data))
  6660. return 0; // not found
  6661. else
  6662. return *battle_data[i].val;
  6663. }
  6664. /*======================
  6665. * Set default settings
  6666. *----------------------*/
  6667. void battle_set_defaults()
  6668. {
  6669. int i;
  6670. for (i = 0; i < ARRAYLENGTH(battle_data); i++)
  6671. *battle_data[i].val = battle_data[i].defval;
  6672. }
  6673. /*==================================
  6674. * Cap certain battle.conf settings
  6675. *----------------------------------*/
  6676. void battle_adjust_conf()
  6677. {
  6678. battle_config.monster_max_aspd = 2000 - battle_config.monster_max_aspd*10;
  6679. battle_config.max_aspd = 2000 - battle_config.max_aspd*10;
  6680. battle_config.max_third_aspd = 2000 - battle_config.max_third_aspd*10;
  6681. battle_config.max_walk_speed = 100*DEFAULT_WALK_SPEED/battle_config.max_walk_speed;
  6682. battle_config.max_cart_weight *= 10;
  6683. if(battle_config.max_def > 100 && !battle_config.weapon_defense_type) // added by [Skotlex]
  6684. battle_config.max_def = 100;
  6685. if(battle_config.min_hitrate > battle_config.max_hitrate)
  6686. battle_config.min_hitrate = battle_config.max_hitrate;
  6687. if(battle_config.pet_max_atk1 > battle_config.pet_max_atk2) //Skotlex
  6688. battle_config.pet_max_atk1 = battle_config.pet_max_atk2;
  6689. if (battle_config.day_duration && battle_config.day_duration < 60000) // added by [Yor]
  6690. battle_config.day_duration = 60000;
  6691. if (battle_config.night_duration && battle_config.night_duration < 60000) // added by [Yor]
  6692. battle_config.night_duration = 60000;
  6693. #if PACKETVER < 20100427
  6694. if( battle_config.feature_buying_store ) {
  6695. ShowWarning("conf/battle/feature.conf buying_store is enabled but it requires PACKETVER 2010-04-27 or newer, disabling...\n");
  6696. battle_config.feature_buying_store = 0;
  6697. }
  6698. #endif
  6699. #if PACKETVER < 20100803
  6700. if( battle_config.feature_search_stores ) {
  6701. ShowWarning("conf/battle/feature.conf search_stores is enabled but it requires PACKETVER 2010-08-03 or newer, disabling...\n");
  6702. battle_config.feature_search_stores = 0;
  6703. }
  6704. #endif
  6705. #ifndef CELL_NOSTACK
  6706. if (battle_config.cell_stack_limit != 1)
  6707. ShowWarning("Battle setting 'cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n");
  6708. #endif
  6709. }
  6710. /*=====================================
  6711. * Read battle.conf settings from file
  6712. *-------------------------------------*/
  6713. int battle_config_read(const char* cfgName)
  6714. {
  6715. FILE* fp;
  6716. static int count = 0;
  6717. if (count == 0)
  6718. battle_set_defaults();
  6719. count++;
  6720. fp = fopen(cfgName,"r");
  6721. if (fp == NULL)
  6722. ShowError("File not found: %s\n", cfgName);
  6723. else
  6724. {
  6725. char line[1024], w1[1024], w2[1024];
  6726. while(fgets(line, sizeof(line), fp))
  6727. {
  6728. if (line[0] == '/' && line[1] == '/')
  6729. continue;
  6730. if (sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2)
  6731. continue;
  6732. if (strcmpi(w1, "import") == 0)
  6733. battle_config_read(w2);
  6734. else
  6735. if (battle_set_value(w1, w2) == 0)
  6736. ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName);
  6737. }
  6738. fclose(fp);
  6739. }
  6740. count--;
  6741. if (count == 0)
  6742. battle_adjust_conf();
  6743. return 0;
  6744. }
  6745. /*==========================
  6746. * initialize battle timer
  6747. *--------------------------*/
  6748. void do_init_battle(void)
  6749. {
  6750. delay_damage_ers = ers_new(sizeof(struct delay_damage),"battle.c::delay_damage_ers",ERS_OPT_CLEAR);
  6751. add_timer_func_list(battle_delay_damage_sub, "battle_delay_damage_sub");
  6752. #ifndef STATS_OPT_OUT
  6753. add_timer_func_list(rAthena_report_timer, "rAthena_report_timer");
  6754. add_timer_interval(gettick()+30000, rAthena_report_timer, 0, 0, 60000 * 30);
  6755. #endif
  6756. }
  6757. /*==================
  6758. * end battle timer
  6759. *------------------*/
  6760. void do_final_battle(void)
  6761. {
  6762. ers_destroy(delay_damage_ers);
  6763. }