status.cpp 479 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "status.hpp"
  4. #include <cmath>
  5. #include <cstdlib>
  6. #include <functional>
  7. #include <string>
  8. #include <common/cbasetypes.hpp>
  9. #include <common/ers.hpp>
  10. #include <common/malloc.hpp>
  11. #include <common/nullpo.hpp>
  12. #include <common/random.hpp>
  13. #include <common/showmsg.hpp>
  14. #include <common/strlib.hpp>
  15. #include <common/timer.hpp>
  16. #include <common/utilities.hpp>
  17. #include <common/utils.hpp>
  18. #include "battle.hpp"
  19. #include "battleground.hpp"
  20. #include "clif.hpp"
  21. #include "elemental.hpp"
  22. #include "guild.hpp"
  23. #include "homunculus.hpp"
  24. #include "itemdb.hpp"
  25. #include "map.hpp"
  26. #include "mercenary.hpp"
  27. #include "mob.hpp"
  28. #include "npc.hpp"
  29. #include "path.hpp"
  30. #include "pc.hpp"
  31. #include "pc_groups.hpp"
  32. #include "pet.hpp"
  33. #include "script.hpp"
  34. using namespace rathena;
  35. // Regen related flags.
  36. enum e_regen {
  37. RGN_NONE = 0x00,
  38. RGN_HP = 0x01,
  39. RGN_SP = 0x02,
  40. RGN_SHP = 0x04,
  41. RGN_SSP = 0x08,
  42. };
  43. static struct eri *sc_data_ers; /// For sc_data entries
  44. static struct status_data dummy_status;
  45. int16 current_equip_item_index; /// Contains inventory index of an equipped item. To pass it into the EQUP_SCRIPT [Lupus]
  46. uint32 current_equip_combo_pos; /// For combo items we need to save the position of all involved items here
  47. int32 current_equip_card_id; /// To prevent card-stacking (from jA) [Skotlex]
  48. // We need it for new cards 15 Feb 2005, to check if the combo cards are insrerted into the CURRENT weapon only to avoid cards exploits
  49. int16 current_equip_opt_index; /// Contains random option index of an equipped item. [Secret]
  50. uint16 SCDisabled[SC_MAX]; ///< List of disabled SC on map zones. [Cydh]
  51. static uint16 status_calc_str(struct block_list *,status_change *,int32);
  52. static uint16 status_calc_agi(struct block_list *,status_change *,int32);
  53. static uint16 status_calc_vit(struct block_list *,status_change *,int32);
  54. static uint16 status_calc_int(struct block_list *,status_change *,int32);
  55. static uint16 status_calc_dex(struct block_list *,status_change *,int32);
  56. static uint16 status_calc_luk(struct block_list *,status_change *,int32);
  57. static uint16 status_calc_pow(struct block_list *, status_change *, int32);
  58. static uint16 status_calc_sta(struct block_list *, status_change *, int32);
  59. static uint16 status_calc_wis(struct block_list *, status_change *, int32);
  60. static uint16 status_calc_spl(struct block_list *, status_change *, int32);
  61. static uint16 status_calc_con(struct block_list *, status_change *, int32);
  62. static uint16 status_calc_crt(struct block_list *, status_change *, int32);
  63. static uint16 status_calc_batk(struct block_list *,status_change *,int32);
  64. static uint16 status_calc_watk(struct block_list *,status_change *,int32);
  65. static int16 status_calc_hit(struct block_list *,status_change *,int32);
  66. static int16 status_calc_critical(struct block_list *,status_change *,int32);
  67. static int16 status_calc_flee(struct block_list *,status_change *,int32);
  68. static int16 status_calc_flee2(struct block_list *,status_change *,int32);
  69. static defType status_calc_def(struct block_list *bl, status_change *sc, int32);
  70. static int16 status_calc_def2(struct block_list *,status_change *,int32);
  71. static defType status_calc_mdef(struct block_list *bl, status_change *sc, int32);
  72. static int16 status_calc_mdef2(struct block_list *,status_change *,int32);
  73. static uint16 status_calc_speed(struct block_list *,status_change *,int32);
  74. static int16 status_calc_aspd_rate(struct block_list *,status_change *,int32);
  75. static uint16 status_calc_dmotion(struct block_list *bl, status_change *sc, int32 dmotion);
  76. #ifdef RENEWAL_ASPD
  77. static int16 status_calc_aspd(struct block_list *bl, status_change *sc, bool fixed);
  78. #endif
  79. static int16 status_calc_fix_aspd(struct block_list *bl, status_change *sc, int32);
  80. static int16 status_calc_patk(struct block_list *, status_change *, int32);
  81. static int16 status_calc_smatk(struct block_list *, status_change *, int32);
  82. static int16 status_calc_res(struct block_list *, status_change *, int32);
  83. static int16 status_calc_mres(struct block_list *, status_change *, int32);
  84. static int16 status_calc_hplus(struct block_list *, status_change *, int32);
  85. static int16 status_calc_crate(struct block_list *, status_change *, int32);
  86. static uint32 status_calc_maxhp(struct block_list *bl, uint64 maxhp);
  87. static uint32 status_calc_maxsp(struct block_list *bl, uint64 maxsp);
  88. static uint32 status_calc_maxap(struct block_list *bl, uint64 maxap);
  89. static unsigned char status_calc_element(struct block_list *bl, status_change *sc, int32 element);
  90. static unsigned char status_calc_element_lv(struct block_list *bl, status_change *sc, int32 lv);
  91. static int32 status_calc_mode(struct block_list *bl, status_change *sc, int32 mode);
  92. static int32 status_get_hpbonus(struct block_list *bl, enum e_status_bonus type);
  93. static int32 status_get_spbonus(struct block_list *bl, enum e_status_bonus type);
  94. static int32 status_get_apbonus(struct block_list *bl, enum e_status_bonus type);
  95. static uint32 status_calc_maxhpsp_pc(map_session_data* sd, uint32 stat, bool isHP);
  96. static uint32 status_calc_maxap_pc(map_session_data* sd);
  97. static int32 status_get_sc_interval(enum sc_type type);
  98. static bool status_change_isDisabledOnMap_(sc_type type, bool mapIsVS, bool mapIsPVP, bool mapIsGVG, bool mapIsBG, uint32 mapZone, bool mapIsTE);
  99. #define status_change_isDisabledOnMap(type, m) ( status_change_isDisabledOnMap_((type), mapdata_flag_vs2((m)), m->getMapFlag(MF_PVP) != 0, mapdata_flag_gvg2_no_te((m)), m->getMapFlag(MF_BATTLEGROUND) != 0, (m->zone << 3) != 0, mapdata_flag_gvg2_te((m))) )
  100. const std::string RefineDatabase::getDefaultLocation(){
  101. return std::string( db_path ) + "/refine.yml";
  102. }
  103. uint64 RefineDatabase::parseBodyNode( const ryml::NodeRef& node ){
  104. std::string group_name;
  105. if( !this->asString( node, "Group", group_name ) ){
  106. return 0;
  107. }
  108. std::string group_name_constant = "REFINE_TYPE_" + group_name;
  109. int64 constant;
  110. if( !script_get_constant( group_name_constant.c_str(), &constant ) ){
  111. this->invalidWarning(node["Group"], "Unknown refine group %s, skipping.\n", group_name.c_str() );
  112. return 0;
  113. }
  114. uint16 group_id = static_cast<uint16>( constant );
  115. std::shared_ptr<s_refine_info> info = this->find( group_id );
  116. bool exists = info != nullptr;
  117. if( !exists ){
  118. info = std::make_shared<s_refine_info>();
  119. }
  120. if( this->nodeExists( node, "Levels" ) ){
  121. const auto& levelsNode = node["Levels"];
  122. for( const auto& levelNode : levelsNode ){
  123. uint16 level;
  124. if( !this->asUInt16( levelNode, "Level", level ) ){
  125. return 0;
  126. }
  127. std::shared_ptr<s_refine_levels_info> levels_info = util::umap_find( info->levels, level );
  128. bool levels_exists = levels_info != nullptr;
  129. if( !levels_exists ){
  130. levels_info = std::make_shared<s_refine_levels_info>();
  131. levels_info->level = level;
  132. }
  133. if( this->nodeExists( levelNode, "RefineLevels" ) ){
  134. const auto& refineLevelsNode = levelNode["RefineLevels"];
  135. for( const auto& refineLevelNode : refineLevelsNode ){
  136. uint16 refine_level;
  137. if( !this->asUInt16( refineLevelNode, "Level", refine_level ) ){
  138. return 0;
  139. }
  140. if( refine_level == 0 || refine_level > MAX_REFINE ){
  141. this->invalidWarning( refineLevelNode["Level"], "Refine level %hu is invalid, skipping.\n", refine_level );
  142. return 0;
  143. }
  144. // Database is 1 based, code is 0 based
  145. refine_level -= 1;
  146. std::shared_ptr<s_refine_level_info> level_info = util::umap_find( levels_info->levels, refine_level );
  147. bool level_exists = level_info != nullptr;
  148. if( !level_exists ){
  149. level_info = std::make_shared<s_refine_level_info>();
  150. level_info->level = refine_level;
  151. }
  152. if( this->nodeExists( refineLevelNode, "Bonus" ) ){
  153. uint32 bonus;
  154. if( !this->asUInt32( refineLevelNode, "Bonus", bonus ) ){
  155. return 0;
  156. }
  157. level_info->bonus = bonus;
  158. }else{
  159. if( !level_exists ){
  160. level_info->bonus = 0;
  161. }
  162. }
  163. if( this->nodeExists( refineLevelNode, "RandomBonus" ) ){
  164. uint32 bonus;
  165. if( !this->asUInt32( refineLevelNode, "RandomBonus", bonus ) ){
  166. return 0;
  167. }
  168. level_info->randombonus_max = bonus;
  169. }else{
  170. if( !level_exists ){
  171. level_info->randombonus_max = 0;
  172. }
  173. }
  174. if( this->nodeExists( refineLevelNode, "BlacksmithBlessingAmount" ) ){
  175. uint16 amount;
  176. if( !this->asUInt16( refineLevelNode, "BlacksmithBlessingAmount", amount ) ){
  177. return 0;
  178. }
  179. if( amount > MAX_AMOUNT ){
  180. this->invalidWarning( refineLevelNode["BlacksmithBlessingAmount"], "Blacksmith Blessing amount %hu too high, capping to MAX_AMOUNT.\n", amount );
  181. amount = MAX_AMOUNT;
  182. }
  183. level_info->blessing_amount = amount;
  184. }else{
  185. if( !level_exists ){
  186. level_info->blessing_amount = 0;
  187. }
  188. }
  189. if (this->nodeExists(refineLevelNode, "BroadcastSuccess")) {
  190. bool bcast;
  191. if (!this->asBool(refineLevelNode, "BroadcastSuccess", bcast)) {
  192. return 0;
  193. }
  194. level_info->broadcast_success = bcast;
  195. }
  196. else {
  197. if (!level_exists) {
  198. level_info->broadcast_success = false;
  199. }
  200. }
  201. if (this->nodeExists(refineLevelNode, "BroadcastFailure")) {
  202. bool bcast;
  203. if (!this->asBool(refineLevelNode, "BroadcastFailure", bcast)) {
  204. return 0;
  205. }
  206. level_info->broadcast_failure = bcast;
  207. }
  208. else {
  209. if (!level_exists) {
  210. level_info->broadcast_failure = false;
  211. }
  212. }
  213. if( this->nodeExists( refineLevelNode, "Chances" ) ){
  214. const auto& chancesNode = refineLevelNode["Chances"];
  215. for( const auto& chanceNode : chancesNode ){
  216. std::string cost_name;
  217. if( !this->asString( chanceNode, "Type", cost_name ) ){
  218. return 0;
  219. }
  220. std::string cost_name_constant = "REFINE_COST_" + cost_name;
  221. if( !script_get_constant( cost_name_constant.c_str(), &constant ) ){
  222. this->invalidWarning( chanceNode["Type"], "Unknown refine cost type %s, skipping.\n", cost_name.c_str() );
  223. return 0;
  224. }
  225. if( constant >= REFINE_COST_MAX ){
  226. this->invalidWarning( chanceNode["Type"], "Refine cost type %s is unsupported, skipping.\n", cost_name.c_str() );
  227. return 0;
  228. }
  229. uint16 index = (uint16)constant;
  230. std::shared_ptr<s_refine_cost> cost = util::umap_find( level_info->costs, index );
  231. bool cost_exists = cost != nullptr;
  232. if( !cost_exists ){
  233. cost = std::make_shared<s_refine_cost>();
  234. cost->index = index;
  235. }
  236. if( this->nodeExists( chanceNode, "Rate" ) ){
  237. uint16 rate;
  238. if( !this->asUInt16Rate( chanceNode, "Rate", rate ) ){
  239. return 0;
  240. }
  241. cost->chance = rate;
  242. }else{
  243. if( !cost_exists ){
  244. cost->chance = 0;
  245. }
  246. }
  247. if( this->nodeExists( chanceNode, "Price" ) ){
  248. uint32 price;
  249. if( !this->asUInt32( chanceNode, "Price", price ) ){
  250. return 0;
  251. }
  252. if( price > MAX_ZENY ){
  253. this->invalidWarning( chanceNode["Price"], "Price is above MAX_ZENY, capping...\n" );
  254. price = MAX_ZENY;
  255. }
  256. cost->zeny = price;
  257. }else{
  258. if( !cost_exists ){
  259. cost->zeny = 0;
  260. }
  261. }
  262. if( this->nodeExists( chanceNode, "Material" ) ){
  263. std::string item_name;
  264. if( !this->asString( chanceNode, "Material", item_name ) ){
  265. return 0;
  266. }
  267. std::shared_ptr<item_data> id = item_db.search_aegisname( item_name.c_str() );
  268. if( id == nullptr ){
  269. this->invalidWarning( chanceNode["Material"], "Unknown refine material %s, skipping.\n", item_name.c_str() );
  270. return 0;
  271. }
  272. cost->nameid = id->nameid;
  273. }else{
  274. if( !cost_exists ){
  275. cost->nameid = 0;
  276. }
  277. }
  278. if( this->nodeExists( chanceNode, "BreakingRate" ) ){
  279. uint16 breaking_rate;
  280. if( !this->asUInt16Rate( chanceNode, "BreakingRate", breaking_rate ) ){
  281. return 0;
  282. }
  283. cost->breaking_rate = breaking_rate;
  284. }else{
  285. if( !cost_exists ){
  286. cost->breaking_rate = 0;
  287. }
  288. }
  289. if( this->nodeExists( chanceNode, "DowngradeAmount" ) ){
  290. uint16 downgrade_amount;
  291. if( !this->asUInt16( chanceNode, "DowngradeAmount", downgrade_amount ) ){
  292. return 0;
  293. }
  294. if( downgrade_amount > MAX_REFINE ){
  295. this->invalidWarning( chanceNode["DowngradeAmount"], "Downgrade amount %hu is invalid, skipping.\n", downgrade_amount );
  296. return 0;
  297. }
  298. cost->downgrade_amount = downgrade_amount;
  299. }else{
  300. if( !cost_exists ){
  301. cost->downgrade_amount = 0;
  302. }
  303. }
  304. if( !cost_exists ){
  305. level_info->costs[index] = cost;
  306. }
  307. }
  308. }
  309. if( !level_exists ){
  310. levels_info->levels[refine_level] = level_info;
  311. }
  312. }
  313. }
  314. if( !levels_exists ){
  315. info->levels[level] = levels_info;
  316. }
  317. }
  318. }
  319. if( !exists ){
  320. this->put( group_id, info );
  321. }
  322. return 1;
  323. }
  324. std::shared_ptr<s_refine_level_info> RefineDatabase::findLevelInfoSub( const struct item_data& data, struct item& item, uint16 refine ){
  325. // Check if the item can be refined
  326. if( data.flag.no_refine ){
  327. return nullptr;
  328. }
  329. // Cap the refine level
  330. if( refine > MAX_REFINE ){
  331. refine = MAX_REFINE;
  332. }
  333. e_refine_type type;
  334. uint16 level;
  335. if( !this->calculate_refine_info( data, type, level ) ){
  336. return nullptr;
  337. }
  338. std::shared_ptr<s_refine_info> info = this->find( type );
  339. if( info == nullptr ){
  340. return nullptr;
  341. }
  342. std::shared_ptr<s_refine_levels_info> levels_info = util::umap_find( info->levels, level );
  343. if( levels_info == nullptr ){
  344. return nullptr;
  345. }
  346. return util::umap_find( levels_info->levels, refine );
  347. }
  348. std::shared_ptr<s_refine_level_info> RefineDatabase::findLevelInfo( const struct item_data& data, struct item& item ){
  349. // Check the current refine level
  350. if( item.refine >= MAX_REFINE ){
  351. return nullptr;
  352. }
  353. return this->findLevelInfoSub( data, item, item.refine );
  354. }
  355. std::shared_ptr<s_refine_level_info> RefineDatabase::findCurrentLevelInfo( const struct item_data& data, struct item& item ){
  356. if( item.refine > 0 ){
  357. return this->findLevelInfoSub( data, item, item.refine - 1 );
  358. }else{
  359. return nullptr;
  360. }
  361. }
  362. bool RefineDatabase::calculate_refine_info( const struct item_data& data, e_refine_type& refine_type, uint16& level ){
  363. if( data.type == IT_WEAPON ){
  364. refine_type = REFINE_TYPE_WEAPON;
  365. level = data.weapon_level;
  366. return true;
  367. }else if( data.type == IT_ARMOR ){
  368. refine_type = REFINE_TYPE_ARMOR;
  369. level = data.armor_level;
  370. return true;
  371. }else if( data.type == IT_SHADOWGEAR ){
  372. if( data.equip == EQP_SHADOW_WEAPON ){
  373. refine_type = REFINE_TYPE_SHADOW_WEAPON;
  374. }else{
  375. refine_type = REFINE_TYPE_SHADOW_ARMOR;
  376. }
  377. level = 1;
  378. return true;
  379. }else{
  380. return false;
  381. }
  382. }
  383. RefineDatabase refine_db;
  384. const std::string SizeFixDatabase::getDefaultLocation() {
  385. return std::string(db_path) + "/size_fix.yml";
  386. }
  387. /**
  388. * Reads and parses an entry from size_fix.
  389. * @param node: YAML node containing the entry.
  390. * @return count of successfully parsed rows
  391. */
  392. uint64 SizeFixDatabase::parseBodyNode(const ryml::NodeRef& node) {
  393. std::string weapon_name;
  394. if (!this->asString(node, "Weapon", weapon_name))
  395. return 0;
  396. std::string weapon_name_constant = "W_" + weapon_name;
  397. int64 constant;
  398. if (!script_get_constant(weapon_name_constant.c_str(), &constant)) {
  399. this->invalidWarning(node["Weapon"], "Size Fix unknown weapon %s, skipping.\n", weapon_name.c_str());
  400. return 0;
  401. }
  402. if (constant < W_FIST || constant > W_2HSTAFF) {
  403. this->invalidWarning(node["Weapon"], "Size Fix weapon %s is an invalid weapon, skipping.\n", weapon_name.c_str());
  404. return 0;
  405. }
  406. int32 weapon_id = static_cast<int32>(constant);
  407. std::shared_ptr<s_sizefix_db> size = this->find(weapon_id);
  408. bool exists = size != nullptr;
  409. if (!exists)
  410. size = std::make_shared<s_sizefix_db>();
  411. if (this->nodeExists(node, "Small")) {
  412. uint16 small;
  413. if (!this->asUInt16(node, "Small", small))
  414. return 0;
  415. if (small > 100) {
  416. this->invalidWarning(node["Small"], "Small Size Fix %d for %s is out of bounds, defaulting to 100.\n", small, weapon_name.c_str());
  417. small = 100;
  418. }
  419. size->small = small;
  420. } else {
  421. if (!exists)
  422. size->small = 100;
  423. }
  424. if (this->nodeExists(node, "Medium")) {
  425. uint16 medium;
  426. if (!this->asUInt16(node, "Medium", medium))
  427. return 0;
  428. if (medium > 100) {
  429. this->invalidWarning(node["Medium"], "Medium Size Fix %d for %s is out of bounds, defaulting to 100.\n", medium, weapon_name.c_str());
  430. medium = 100;
  431. }
  432. size->medium = medium;
  433. } else {
  434. if (!exists)
  435. size->medium = 100;
  436. }
  437. if (this->nodeExists(node, "Large")) {
  438. uint16 large;
  439. if (!this->asUInt16(node, "Large", large))
  440. return 0;
  441. if (large > 100) {
  442. this->invalidWarning(node["Large"], "Large Size Fix %d for %s is out of bounds, defaulting to 100.\n", large, weapon_name.c_str());
  443. large = 100;
  444. }
  445. size->large = large;
  446. } else {
  447. if (!exists)
  448. size->large = 100;
  449. }
  450. if (!exists)
  451. this->put(weapon_id, size);
  452. return 1;
  453. }
  454. SizeFixDatabase size_fix_db;
  455. const std::string EnchantgradeDatabase::getDefaultLocation(){
  456. return std::string(db_path) + "/enchantgrade.yml";
  457. }
  458. uint64 EnchantgradeDatabase::parseBodyNode( const ryml::NodeRef& node ){
  459. if( !this->nodesExist( node, { "Type", "Levels" } ) ){
  460. return 0;
  461. }
  462. std::string itemtype_constant;
  463. if( !this->asString( node, "Type", itemtype_constant ) ){
  464. return 0;
  465. }
  466. int64 constant_value;
  467. if( !script_get_constant( ( "IT_" + itemtype_constant ).c_str(), &constant_value ) ){
  468. this->invalidWarning( node["Type"], "Unknown item type \"%s\".\n", itemtype_constant.c_str() );
  469. return 0;
  470. }
  471. uint16 itemtype = static_cast<uint16>( constant_value );
  472. uint16 itemtype_maxlevel;
  473. if( itemtype == IT_WEAPON ){
  474. itemtype_maxlevel = MAX_WEAPON_LEVEL;
  475. }else if( itemtype == IT_ARMOR ){
  476. itemtype_maxlevel = MAX_ARMOR_LEVEL;
  477. }else{
  478. this->invalidWarning( node["Type"], "Item type \"%s\" is not supported.\n", itemtype_constant.c_str() );
  479. return 0;
  480. }
  481. std::shared_ptr<s_enchantgrade> enchantgrade = this->find( itemtype );
  482. bool exists = enchantgrade != nullptr;
  483. if( !exists ){
  484. enchantgrade = std::make_shared<s_enchantgrade>();
  485. enchantgrade->itemtype = itemtype;
  486. }
  487. for( const ryml::NodeRef& levelNode : node["Levels"] ){
  488. if( !this->nodesExist( levelNode, { "Level", "Grades" } ) ){
  489. return 0;
  490. }
  491. uint16 level;
  492. if( !this->asUInt16( levelNode, "Level", level ) ){
  493. return 0;
  494. }
  495. if( level == 0 || level > itemtype_maxlevel ){
  496. this->invalidWarning( levelNode["Level"], "Level %hu is invalid for item type %s[1~%hu].\n", level, itemtype_constant.c_str(), itemtype_maxlevel );
  497. return 0;
  498. }
  499. std::map<e_enchantgrade, std::shared_ptr<s_enchantgradelevel>>& grades = enchantgrade->levels[level];
  500. for( const ryml::NodeRef& gradeNode : levelNode["Grades"] ){
  501. std::string gradeConstant;
  502. if( !this->asString( gradeNode, "Grade", gradeConstant ) ){
  503. return 0;
  504. }
  505. if( !script_get_constant( ( "ENCHANTGRADE_" + gradeConstant ).c_str(), &constant_value ) ){
  506. this->invalidWarning( node["Grade"], "Unknown grade \"%s\".\n", gradeConstant.c_str() );
  507. return 0;
  508. }
  509. if( constant_value >= MAX_ENCHANTGRADE ){
  510. this->invalidWarning( gradeNode["Grade"], "Grade %" PRId64 " is too high. Maximum: %hu.\n", constant_value, MAX_ENCHANTGRADE - 1 );
  511. return 0;
  512. }
  513. e_enchantgrade gradeLevel = (e_enchantgrade)constant_value;
  514. std::shared_ptr<s_enchantgradelevel> grade = util::map_find( grades, gradeLevel );
  515. bool gradeExists = grade != nullptr;
  516. if( !gradeExists ){
  517. if( !this->nodesExist( gradeNode, { "Chances", "Options" } ) ){
  518. return 0;
  519. }
  520. grade = std::make_shared<s_enchantgradelevel>();
  521. grade->grade = gradeLevel;
  522. for( int32 i = 0; i < ARRAYLENGTH( grade->chances ); i++ ){
  523. grade->chances[i] = 0;
  524. }
  525. }
  526. if( this->nodeExists( gradeNode, "Chances" ) ){
  527. for( const ryml::NodeRef& chanceNode : gradeNode["Chances"] ){
  528. uint16 refine;
  529. if( !this->asUInt16( chanceNode, "Refine", refine ) ){
  530. return 0;
  531. }
  532. if( refine > MAX_REFINE ){
  533. this->invalidWarning( chanceNode["Refine"], "Refine %hu is too high. Maximum: %hu.\n", refine, MAX_REFINE );
  534. return 0;
  535. }
  536. uint16 chance;
  537. if( !this->asUInt16Rate( chanceNode, "Chance", chance ) ){
  538. return 0;
  539. }
  540. grade->chances[refine] = chance;
  541. }
  542. }
  543. if( this->nodeExists( gradeNode, "Bonus" ) ){
  544. uint16 bonus;
  545. if( !this->asUInt16( gradeNode, "Bonus", bonus ) ){
  546. return 0;
  547. }
  548. grade->bonus = bonus;
  549. }else{
  550. if( !gradeExists ){
  551. grade->bonus = 0;
  552. }
  553. }
  554. if( this->nodeExists( gradeNode, "AnnounceSuccess" ) ){
  555. bool announce;
  556. if( !this->asBool( gradeNode, "AnnounceSuccess", announce ) ){
  557. return 0;
  558. }
  559. grade->announceSuccess = announce;
  560. }else{
  561. if( !gradeExists ){
  562. grade->announceSuccess = true;
  563. }
  564. }
  565. if( this->nodeExists( gradeNode, "AnnounceFail" ) ){
  566. bool announce;
  567. if( !this->asBool( gradeNode, "AnnounceFail", announce) ){
  568. return 0;
  569. }
  570. grade->announceFail = announce;
  571. }else{
  572. if( !gradeExists ){
  573. grade->announceFail = false;
  574. }
  575. }
  576. if( this->nodeExists( gradeNode, "Announce" ) ){
  577. bool announce;
  578. if( !this->asBool( gradeNode, "Announce", announce ) ){
  579. return 0;
  580. }
  581. grade->announceSuccess = announce;
  582. grade->announceFail = announce;
  583. }
  584. if( this->nodeExists( gradeNode, "Catalyst") ){
  585. const ryml::NodeRef& catalystNode = gradeNode["Catalyst"];
  586. if( this->nodeExists( catalystNode, "Item" ) ){
  587. std::string itemName;
  588. if( !this->asString( catalystNode, "Item", itemName ) ){
  589. return 0;
  590. }
  591. std::shared_ptr<item_data> id = item_db.search_aegisname( itemName.c_str() );
  592. if( id == nullptr ){
  593. this->invalidWarning( catalystNode["Item"], "Unknown item \"%s\".\n", itemName.c_str() );
  594. return 0;
  595. }
  596. grade->catalyst.item = id->nameid;
  597. }else{
  598. if( !gradeExists ){
  599. grade->catalyst.item = 0;
  600. }
  601. }
  602. if( this->nodeExists( catalystNode, "AmountPerStep" ) ){
  603. uint16 amountPerStep;
  604. if( !this->asUInt16( catalystNode, "AmountPerStep", amountPerStep ) ){
  605. return 0;
  606. }
  607. grade->catalyst.amountPerStep = amountPerStep;
  608. }else{
  609. if( !gradeExists ){
  610. grade->catalyst.amountPerStep = 0;
  611. }
  612. }
  613. if( this->nodeExists( catalystNode, "MaximumSteps" ) ){
  614. uint16 maximumSteps;
  615. if( !this->asUInt16( catalystNode, "MaximumSteps", maximumSteps ) ){
  616. return 0;
  617. }
  618. grade->catalyst.maximumSteps = maximumSteps;
  619. }else{
  620. if( !gradeExists ){
  621. grade->catalyst.maximumSteps = 0;
  622. }
  623. }
  624. if( this->nodeExists( catalystNode, "ChanceIncrease" ) ){
  625. uint16 chanceIncrease;
  626. if( !this->asUInt16Rate( catalystNode, "ChanceIncrease", chanceIncrease ) ){
  627. return 0;
  628. }
  629. grade->catalyst.chanceIncrease = chanceIncrease;
  630. }else{
  631. if( !gradeExists ){
  632. grade->catalyst.chanceIncrease = 0;
  633. }
  634. }
  635. }else{
  636. if( !gradeExists ){
  637. grade->catalyst.item = 0;
  638. grade->catalyst.amountPerStep = 0;
  639. grade->catalyst.maximumSteps = 0;
  640. grade->catalyst.chanceIncrease = 0;
  641. }
  642. }
  643. if( this->nodeExists( gradeNode, "Options" ) ){
  644. for( const ryml::NodeRef& optionNode : gradeNode["Options"] ){
  645. uint16 optionIndex;
  646. if( !this->asUInt16( optionNode, "Option", optionIndex ) ){
  647. return 0;
  648. }
  649. std::shared_ptr<s_enchantgradeoption> option = util::map_find( grade->options, optionIndex );
  650. bool optionExists = option != nullptr;
  651. if( !optionExists ){
  652. option = std::make_shared<s_enchantgradeoption>();
  653. option->id = optionIndex;
  654. }
  655. if( this->nodeExists( optionNode, "Amount" ) ){
  656. uint16 amount;
  657. if( !this->asUInt16( optionNode, "Amount", amount ) ){
  658. return 0;
  659. }
  660. if( amount > MAX_AMOUNT ){
  661. this->invalidWarning( optionNode["Amount"], "Amount %hu is too high, capping to %hu...\n", amount, MAX_AMOUNT );
  662. amount = MAX_AMOUNT;
  663. }
  664. if( amount == 0 ){
  665. if( grade->options.erase( optionIndex ) > 0 ){
  666. continue;
  667. }else{
  668. this->invalidWarning( optionNode["Amount"], "Trying to remove invalid option %hu...\n", optionIndex );
  669. return 0;
  670. }
  671. }
  672. option->amount = amount;
  673. }else{
  674. if( !optionExists ){
  675. option->amount = 1;
  676. }
  677. }
  678. if( this->nodeExists( optionNode, "Item" ) ){
  679. std::string itemName;
  680. if( !this->asString( optionNode, "Item", itemName ) ){
  681. return 0;
  682. }
  683. std::shared_ptr<item_data> id = item_db.search_aegisname( itemName.c_str() );
  684. if( id == nullptr ){
  685. this->invalidWarning( optionNode["Item"], "Unknown item \"%s\".\n", itemName.c_str() );
  686. return 0;
  687. }
  688. option->item = id->nameid;
  689. }else{
  690. if( !optionExists ){
  691. option->item = 0;
  692. }
  693. }
  694. if( this->nodeExists( optionNode, "Zeny" ) ){
  695. uint32 zeny;
  696. if( !this->asUInt32( optionNode, "Zeny", zeny ) ){
  697. return 0;
  698. }
  699. option->zeny = zeny;
  700. }else{
  701. if( !optionExists ){
  702. option->zeny = 0;
  703. }
  704. }
  705. if( this->nodeExists( optionNode, "BreakingRate" ) ){
  706. uint16 breaking_rate;
  707. if( !this->asUInt16Rate( optionNode, "BreakingRate", breaking_rate ) ){
  708. return 0;
  709. }
  710. option->breaking_rate = breaking_rate;
  711. }else{
  712. if( !optionExists ){
  713. option->breaking_rate = 0;
  714. }
  715. }
  716. if( this->nodeExists( optionNode, "DowngradeAmount" ) ){
  717. uint16 downgrade_amount;
  718. if( !this->asUInt16( optionNode, "DowngradeAmount", downgrade_amount ) ){
  719. return 0;
  720. }
  721. if( downgrade_amount > MAX_REFINE ){
  722. this->invalidWarning( optionNode["DowngradeAmount"], "Downgrade amount %hu is invalid, skipping.\n", downgrade_amount );
  723. return 0;
  724. }
  725. option->downgrade_amount = downgrade_amount;
  726. }else{
  727. if( !optionExists ){
  728. option->downgrade_amount = 0;
  729. }
  730. }
  731. if( !optionExists ){
  732. grade->options[optionIndex] = option;
  733. }
  734. }
  735. }
  736. if( !gradeExists ){
  737. grades[gradeLevel] = grade;
  738. }
  739. }
  740. }
  741. if( !exists ){
  742. this->put( itemtype, enchantgrade );
  743. }
  744. return 1;
  745. }
  746. std::shared_ptr<s_enchantgradelevel> EnchantgradeDatabase::findCurrentLevelInfo( const struct item_data& data, struct item& item ){
  747. std::shared_ptr<s_enchantgrade> enchantgrade = enchantgrade_db.find( data.type );
  748. // Unsupported item type - no answer
  749. if( enchantgrade == nullptr ){
  750. return nullptr;
  751. }
  752. uint16 level = 0;
  753. if( data.type == IT_WEAPON ){
  754. level = data.weapon_level;
  755. }else if( data.type == IT_ARMOR ){
  756. level = data.armor_level;
  757. }
  758. const auto& enchantgradelevels = enchantgrade->levels.find( level );
  759. // Cannot upgrade this weapon or armor level - no answer
  760. if( enchantgradelevels == enchantgrade->levels.end() ){
  761. return nullptr;
  762. }
  763. return util::map_find( enchantgradelevels->second, (e_enchantgrade)( item.enchantgrade - 1 ) );
  764. }
  765. void EnchantgradeDatabase::loadingFinished(){
  766. for( const auto& it_itemTypes : *this ){
  767. for( const auto& it_itemLevels : it_itemTypes.second->levels ){
  768. for( const auto& it_enchantgrades : it_itemLevels.second ){
  769. std::shared_ptr<s_enchantgradelevel> enchantgradelevel = it_enchantgrades.second;
  770. if( enchantgradelevel->catalyst.amountPerStep == 0 ){
  771. enchantgradelevel->catalyst.item = 0;
  772. enchantgradelevel->catalyst.chanceIncrease = 0;
  773. enchantgradelevel->catalyst.maximumSteps = 0;
  774. }
  775. }
  776. }
  777. }
  778. TypesafeYamlDatabase::loadingFinished();
  779. }
  780. EnchantgradeDatabase enchantgrade_db;
  781. /**
  782. * Get icon ID of SC
  783. * @param type: SC type
  784. * @return EFST ID
  785. **/
  786. efst_type StatusDatabase::getIcon(sc_type type) {
  787. std::shared_ptr<s_status_change_db> status = status_db.find(type);
  788. return status ? status->icon : EFST_BLANK;
  789. }
  790. /**
  791. * Get flag of SC (SCB value) for status_calc_ flag
  792. * @param type: SC type
  793. * @return cal_flag: Calc value
  794. **/
  795. std::bitset<SCB_MAX> StatusDatabase::getCalcFlag(sc_type type) {
  796. std::shared_ptr<s_status_change_db> status = status_db.find(type);
  797. return status ? status->calc_flag : std::bitset<SCB_MAX> {};
  798. }
  799. /**
  800. * Get SC's EndOnStart list
  801. * @param sc: SC type
  802. * @return End list
  803. **/
  804. std::vector<sc_type> StatusDatabase::getEndOnStart(sc_type type) {
  805. std::shared_ptr<s_status_change_db> status = status_db.find(type);
  806. return status ? status->endonstart : std::vector<sc_type> {};
  807. }
  808. /**
  809. * Get BL type to display proper effect
  810. * @param efst: EFST type
  811. * @return BL types
  812. **/
  813. uint16 status_efst_get_bl_type(enum efst_type efst) {
  814. if (efst <= EFST_BLANK || efst >= EFST_MAX)
  815. return BL_PC;
  816. return status_db.StatusRelevantBLTypes[efst];
  817. }
  818. /**
  819. * Returns the FIRST skill (in order of definition in initChangeTables) to use a given status change.
  820. * Utilized for various duration lookups. Use with caution!
  821. * @param sc The status to look up
  822. * @return A skill associated with the status
  823. **/
  824. uint16 StatusDatabase::getSkill(sc_type type) {
  825. std::shared_ptr<s_status_change_db> status = status_db.find(type);
  826. return status ? status->skill_id : 0;
  827. }
  828. /**
  829. * Returns if a status change flag is active or not for a SC.
  830. * @param sc: Status changes active on target
  831. * @param flag: Flag to check for
  832. * @return True if flag is set or false otherwise
  833. */
  834. bool StatusDatabase::hasSCF(status_change *sc, e_status_change_flag flag) {
  835. if (sc == nullptr || sc->empty() || flag == SCF_NONE)
  836. return false;
  837. for (const auto &status_it : *this) {
  838. std::shared_ptr<s_status_change_db> status = status_it.second;
  839. if (sc->getSCE(status->type) && status->flag[flag])
  840. return true;
  841. }
  842. return false;
  843. }
  844. /**
  845. * Returns the SCB_BATTLE constant.
  846. * return SCB_BATTLE
  847. */
  848. std::bitset<SCB_MAX> StatusDatabase::getSCB_BATTLE() {
  849. return this->SCB_BATTLE;
  850. }
  851. /**
  852. * Returns the SCB_ALL constant.
  853. * @return SCB_ALL
  854. */
  855. std::bitset<SCB_MAX> StatusDatabase::getSCB_ALL() {
  856. return this->SCB_ALL;
  857. }
  858. /**
  859. * Removes statuses from skills that aren't part of the new class skill tree.
  860. * @param sd: Player data
  861. */
  862. void StatusDatabase::changeSkillTree(map_session_data *sd, int32 class_) {
  863. if (sd == nullptr)
  864. return;
  865. std::shared_ptr<s_skill_tree> tree = skill_tree_db.find(class_ > 0 ? class_ : sd->status.class_);
  866. if (tree == nullptr)
  867. return;
  868. for (const auto &it : tree->skills) {
  869. uint16 skill_id = it.first;
  870. sc_type sc = skill_get_sc(skill_id);
  871. if (sc > SC_COMMON_MAX && sc < SC_MAX && sd->sc.getSCE(sc))
  872. status_change_end(&sd->bl, sc);
  873. }
  874. }
  875. /**
  876. * Validates if type is in SC ranges
  877. * @param type: SC type
  878. * @return True if type is in range, false otherwise
  879. */
  880. bool StatusDatabase::validateStatus(sc_type type) {
  881. if (type > SC_NONE && type < SC_MAX)
  882. return true;
  883. return false;
  884. }
  885. /**
  886. * Removes a status based on the provided flag(s).
  887. * @param bl: Target to remove status from
  888. * @param flag: List of flags to check for removing
  889. */
  890. void StatusDatabase::removeByStatusFlag(block_list *bl, std::vector<e_status_change_flag> flag) {
  891. if (bl == nullptr || flag.empty())
  892. return;
  893. status_change *sc = status_get_sc(bl);
  894. if (sc == nullptr || sc->empty())
  895. return;
  896. for (const auto &status_it : *this) {
  897. std::shared_ptr<s_status_change_db> status = status_it.second;
  898. sc_type type = status->type;
  899. if (sc->getSCE(type)) {
  900. for (const auto &flag_it : flag) {
  901. if (status->flag[flag_it])
  902. status_change_end(bl, type);
  903. }
  904. }
  905. }
  906. }
  907. status_change::status_change(){
  908. this->option = OPTION_NOTHING;
  909. this->opt3 = OPT3_NORMAL;
  910. this->opt1 = OPT1_NONE;
  911. this->opt2 = OPT2_NONE;
  912. this->count = 0;
  913. this->lastEffect = SC_NONE;
  914. this->lastEffectTimer = INVALID_TIMER;
  915. this->cant = {};
  916. this->comet_x = 0;
  917. this->comet_y = 0;
  918. #ifndef RENEWAL
  919. this->sg_counter = 0;
  920. #endif
  921. std::fill( std::begin( this->data ), std::end( this->data ), nullptr );
  922. this->lastStatus = { SC_NONE, nullptr };
  923. }
  924. /**
  925. * Accessor for a status_change_entry in a status_change
  926. */
  927. status_change_entry * status_change::getSCE(enum sc_type type) {
  928. // TODO: bounds check
  929. if (type == lastStatus.first)
  930. return lastStatus.second;
  931. lastStatus = {type, data[type]};
  932. return lastStatus.second;
  933. }
  934. status_change_entry * status_change::getSCE(uint32 type) {
  935. return getSCE(static_cast<sc_type>(type));
  936. }
  937. status_change_entry * status_change::createSCE(enum sc_type type) {
  938. data[type] = ers_alloc(sc_data_ers, struct status_change_entry);
  939. lastStatus = {type, data[type]};
  940. return data[type];
  941. }
  942. /**
  943. * free the sce, then clear it
  944. */
  945. void status_change::deleteSCE(enum sc_type type) {
  946. ers_free(sc_data_ers, data[type]);
  947. data[type] = nullptr;
  948. lastStatus = {type, data[type]};
  949. }
  950. /**
  951. * For when we only want to clear the sce without freeing.
  952. */
  953. void status_change::clearSCE(enum sc_type type) {
  954. data[type] = nullptr;
  955. lastStatus = {type, data[type]};
  956. }
  957. bool status_change::empty(){
  958. return this->count == 0;
  959. }
  960. /** Creates dummy status */
  961. static void initDummyData(void) {
  962. memset(&dummy_status, 0, sizeof(dummy_status));
  963. dummy_status.hp =
  964. dummy_status.max_hp =
  965. dummy_status.max_sp =
  966. dummy_status.str =
  967. dummy_status.agi =
  968. dummy_status.vit =
  969. dummy_status.int_ =
  970. dummy_status.dex =
  971. dummy_status.luk =
  972. dummy_status.hit = 1;
  973. dummy_status.speed = 2000;
  974. dummy_status.adelay = 4000;
  975. dummy_status.amotion = 2000;
  976. dummy_status.dmotion = 2000;
  977. dummy_status.ele_lv = 1; // Min elemental level.
  978. dummy_status.mode = MD_CANMOVE;
  979. }
  980. /**
  981. * For copying a status_data structure from b to a, without overwriting current Hp, Sp, and Ap.
  982. * @param a: Status data structure to copy from
  983. * @param b: Status data structure to copy to
  984. */
  985. static inline void status_cpy(struct status_data* a, const struct status_data* b)
  986. {
  987. memcpy((void*)&a->max_hp, (const void*)&b->max_hp, sizeof(struct status_data)-(sizeof(a->hp)+sizeof(a->sp)+sizeof(a->ap)));
  988. }
  989. /**
  990. * Sets HP to a given value
  991. * Will always succeed (overrides heal impediment statuses) but can't kill an object
  992. * @param bl: Object whose HP will be set [PC|MOB|HOM|MER|ELEM|NPC]
  993. * @param hp: What the HP is to be set as
  994. * @param flag: Used in case final value is higher than current
  995. * Use 2 to display healing effect
  996. * @return heal or zapped HP if valid
  997. */
  998. int32 status_set_hp(struct block_list *bl, uint32 hp, int32 flag)
  999. {
  1000. if (hp < 1)
  1001. return 0;
  1002. status_data* status = status_get_status_data(*bl);
  1003. if (status == &dummy_status)
  1004. return 0;
  1005. if (hp > status->max_hp)
  1006. hp = status->max_hp;
  1007. if (hp == status->hp)
  1008. return 0;
  1009. if (hp > status->hp)
  1010. return status_heal(bl, hp - status->hp, 0, 1|flag);
  1011. return status_zap(bl, status->hp - hp, 0);
  1012. }
  1013. /**
  1014. * Sets Max HP to a given value
  1015. * @param bl: Object whose Max HP will be set [PC|MOB|HOM|MER|ELEM|NPC]
  1016. * @param maxhp: What the Max HP is to be set as
  1017. * @param flag: Used in case final value is higher than current
  1018. * Use 2 to display healing effect
  1019. * @return heal or zapped HP if valid
  1020. */
  1021. int32 status_set_maxhp(struct block_list *bl, uint32 maxhp, int32 flag)
  1022. {
  1023. int64 heal;
  1024. if (maxhp < 1)
  1025. return 0;
  1026. status_data* status = status_get_status_data(*bl);
  1027. if (status == &dummy_status)
  1028. return 0;
  1029. if (maxhp == status->max_hp)
  1030. return 0;
  1031. heal = maxhp - status->max_hp;
  1032. status->max_hp = maxhp;
  1033. if (heal > 0)
  1034. status_heal(bl, heal, 0, 1|flag);
  1035. else
  1036. status_zap(bl, -heal, 0);
  1037. return maxhp;
  1038. }
  1039. /**
  1040. * Sets SP to a given value
  1041. * @param bl: Object whose SP will be set [PC|HOM|MER|ELEM]
  1042. * @param sp: What the SP is to be set as
  1043. * @param flag: Used in case final value is higher than current
  1044. * Use 2 to display healing effect
  1045. * @return heal or zapped SP if valid
  1046. */
  1047. int32 status_set_sp(struct block_list *bl, uint32 sp, int32 flag)
  1048. {
  1049. status_data* status = status_get_status_data(*bl);
  1050. if (status == &dummy_status)
  1051. return 0;
  1052. if (sp > status->max_sp)
  1053. sp = status->max_sp;
  1054. if (sp == status->sp)
  1055. return 0;
  1056. if (sp > status->sp)
  1057. return status_heal(bl, 0, sp - status->sp, 1|flag);
  1058. return status_zap(bl, 0, status->sp - sp);
  1059. }
  1060. /**
  1061. * Sets Max SP to a given value
  1062. * @param bl: Object whose Max SP will be set [PC|HOM|MER|ELEM]
  1063. * @param maxsp: What the Max SP is to be set as
  1064. * @param flag: Used in case final value is higher than current
  1065. * Use 2 to display healing effect
  1066. * @return heal or zapped HP if valid
  1067. */
  1068. int32 status_set_maxsp(struct block_list *bl, uint32 maxsp, int32 flag)
  1069. {
  1070. if (maxsp < 1)
  1071. return 0;
  1072. status_data* status = status_get_status_data(*bl);
  1073. if (status == &dummy_status)
  1074. return 0;
  1075. if (maxsp == status->max_sp)
  1076. return 0;
  1077. if (maxsp > status->max_sp)
  1078. status_heal(bl, maxsp - status->max_sp, 0, 1|flag);
  1079. else
  1080. status_zap(bl, status->max_sp - maxsp, 0);
  1081. status->max_sp = maxsp;
  1082. return maxsp;
  1083. }
  1084. /**
  1085. * Sets AP to a given value
  1086. * @param bl: Object whose AP will be set [PC|HOM|MER|ELEM]
  1087. * @param ap: What the AP is to be set as
  1088. * @param flag: Used in case final value is higher than current
  1089. * Use 2 to display healing effect
  1090. * @return heal or zapped AP if valid
  1091. */
  1092. int32 status_set_ap(struct block_list *bl, uint32 ap, int32 flag)
  1093. {
  1094. status_data *status = status_get_status_data(*bl);
  1095. if (status == &dummy_status)
  1096. return 0;
  1097. if (ap > status->max_ap)
  1098. ap = status->max_ap;
  1099. if (ap == status->ap)
  1100. return 0;
  1101. if (ap > status->ap)
  1102. return status_heal(bl, 0, 0, ap - status->ap, 1 | flag);
  1103. return status_zap(bl, 0, 0, status->ap - ap);
  1104. }
  1105. /**
  1106. * Sets Max AP to a given value
  1107. * @param bl: Object whose Max AP will be set [PC|HOM|MER|ELEM]
  1108. * @param maxap: What the Max AP is to be set as
  1109. * @param flag: Used in case final value is higher than current
  1110. * Use 2 to display healing effect
  1111. * @return heal or zapped AP if valid
  1112. */
  1113. int32 status_set_maxap(struct block_list *bl, uint32 maxap, int32 flag)
  1114. {
  1115. if (maxap < 1)
  1116. return 0;
  1117. status_data *status = status_get_status_data(*bl);
  1118. if (status == &dummy_status)
  1119. return 0;
  1120. if (maxap == status->max_ap)
  1121. return 0;
  1122. if (maxap > status->max_ap)
  1123. status_heal(bl, 0, 0, maxap - status->max_ap, 1 | flag);
  1124. else
  1125. status_zap(bl, 0, 0, status->max_ap - maxap);
  1126. status->max_ap = maxap;
  1127. return maxap;
  1128. }
  1129. /**
  1130. * Takes HP/SP from an Object
  1131. * @param bl: Object who will have HP/SP taken [PC|MOB|HOM|MER|ELEM]
  1132. * @param hp: How much HP to charge
  1133. * @param sp: How much SP to charge
  1134. * @return hp+sp through status_damage()
  1135. * Note: HP/SP are integer values, not percentages. Values should be
  1136. * calculated either within function call or before
  1137. */
  1138. int64 status_charge(struct block_list* bl, int64 hp, int64 sp)
  1139. {
  1140. if(!(bl->type&BL_CONSUME))
  1141. return (int32)hp+sp; // Assume all was charged so there are no 'not enough' fails.
  1142. return status_damage(nullptr, bl, hp, sp, 0, 3, 0);
  1143. }
  1144. /**
  1145. * Inflicts damage on the target with the according walkdelay.
  1146. * @param src: Source object giving damage [PC|MOB|PET|HOM|MER|ELEM]
  1147. * @param target: Target of the damage
  1148. * @param dhp: How much damage to HP
  1149. * @param dsp: How much damage to SP
  1150. * @param dap: How much damage to AP
  1151. * @param walkdelay: Amount of time before object can walk again
  1152. * @param flag: Damage flag decides various options
  1153. * flag&1: Passive damage - Does not trigger cancelling status changes
  1154. * flag&2: Fail if there is not enough to subtract
  1155. * flag&4: Mob does not give EXP/Loot if killed
  1156. * flag&8: Used to damage SP of a dead character
  1157. * flag&16: Coma damage - Log it as normal damage, but actually set HP/SP to 1
  1158. * @return hp+sp+ap
  1159. * Note: HP/SP/AP are integer values, not percentages. Values should be
  1160. * calculated either within function call or before
  1161. */
  1162. int32 status_damage(struct block_list *src,struct block_list *target,int64 dhp, int64 dsp, int64 dap, t_tick walkdelay, int32 flag, uint16 skill_id)
  1163. {
  1164. status_change *sc;
  1165. int32 hp = (int32)cap_value(dhp,INT_MIN,INT_MAX);
  1166. int32 sp = (int32)cap_value(dsp,INT_MIN,INT_MAX);
  1167. int32 ap = (int32)cap_value(dap,INT_MIN,INT_MAX);
  1168. nullpo_ret(target);
  1169. if(sp && !(target->type&BL_CONSUME))
  1170. sp = 0; // Not a valid SP target.
  1171. if (ap && !(target->type&BL_CONSUME))
  1172. ap = 0; // Not a valid AP target.
  1173. if (hp < 0) { // Assume absorbed damage.
  1174. status_heal(target, -hp, 0, 1);
  1175. hp = 0;
  1176. }
  1177. if (sp < 0) {
  1178. status_heal(target, 0, -sp, 1);
  1179. sp = 0;
  1180. }
  1181. if (ap < 0) {
  1182. status_heal(target, 0, 0, -ap, 1);
  1183. ap = 0;
  1184. }
  1185. if (target->type == BL_SKILL) {
  1186. if (!src || src->type&battle_config.can_damage_skill)
  1187. return (int32)skill_unit_ondamaged((struct skill_unit *)target, hp);
  1188. return 0;
  1189. }
  1190. status_data* status = status_get_status_data(*target);
  1191. if( status == &dummy_status )
  1192. return 0;
  1193. if ((uint32)hp >= status->hp) {
  1194. if (flag&2) return 0;
  1195. hp = status->hp;
  1196. }
  1197. if ((uint32)sp > status->sp) {
  1198. if (flag&2) return 0;
  1199. sp = status->sp;
  1200. }
  1201. if ((uint32)ap > status->ap) {
  1202. if (flag & 2) return 0;
  1203. ap = status->ap;
  1204. }
  1205. if (!hp && !sp && !ap)
  1206. return 0;
  1207. if( !status->hp )
  1208. flag |= 8;
  1209. sc = status_get_sc(target);
  1210. if (hp && battle_config.invincible_nodamage && src && sc && sc->getSCE(SC_INVINCIBLE))
  1211. hp = 1;
  1212. if( hp && !(flag&1) ) {
  1213. if( sc ) {
  1214. struct status_change_entry *sce;
  1215. for (const auto &it : status_db) {
  1216. sc_type type = static_cast<sc_type>(it.first);
  1217. if (sc->getSCE(type) && it.second->flag[SCF_REMOVEONDAMAGED]) {
  1218. // A status change that gets broken by damage should still be considered when calculating if a status change can be applied or not (for the same attack).
  1219. // !TODO: This is a temporary solution until we refactor the code so that the calculation of an SC is done at the start of an attack rather than after the damage was applied.
  1220. if (sc->opt1 > OPT1_NONE && sc->lastEffectTimer == INVALID_TIMER) {
  1221. sc->lastEffectTimer = add_timer(gettick() + 10, status_clear_lastEffect_timer, target->id, 0);
  1222. sc->lastEffect = type;
  1223. }
  1224. status_change_end(target, type);
  1225. }
  1226. }
  1227. if ((sce=sc->getSCE(SC_ENDURE)) && !sce->val4) {
  1228. /** [Skotlex]
  1229. * Endure count is only reduced by non-players on non-gvg maps.
  1230. * val4 signals infinite endure.
  1231. **/
  1232. if (src && src->type != BL_PC && !map_flag_gvg2(target->m) && !map_getmapflag(target->m, MF_BATTLEGROUND) && --(sce->val2) <= 0)
  1233. status_change_end(target, SC_ENDURE);
  1234. }
  1235. #ifndef RENEWAL
  1236. if ((sce=sc->getSCE(SC_GRAVITATION)) && sce->val3 == BCT_SELF) {
  1237. std::shared_ptr<s_skill_unit_group> sg = skill_id2group(sce->val4);
  1238. if (sg) {
  1239. skill_delunitgroup(sg);
  1240. sce->val4 = 0;
  1241. status_change_end(target, SC_GRAVITATION);
  1242. }
  1243. }
  1244. #endif
  1245. if(sc->getSCE(SC_DANCING) && hp > (status->max_hp / 4))
  1246. status_change_end(target, SC_DANCING);
  1247. if(sc->getSCE(SC_CLOAKINGEXCEED) && --(sc->getSCE(SC_CLOAKINGEXCEED)->val2) <= 0)
  1248. status_change_end(target, SC_CLOAKINGEXCEED);
  1249. if(sc->getSCE(SC_KAGEMUSYA) && --(sc->getSCE(SC_KAGEMUSYA)->val3) <= 0)
  1250. status_change_end(target, SC_KAGEMUSYA);
  1251. }
  1252. if (target->type == BL_PC)
  1253. pc_bonus_script_clear(BL_CAST(BL_PC,target),BSF_REM_ON_DAMAGED);
  1254. unit_skillcastcancel(target, 2);
  1255. }
  1256. // We need to log the real damage on exp_calc_type 1
  1257. if (battle_config.exp_calc_type == 1) {
  1258. dhp = hp;
  1259. // Coma real damage
  1260. if (flag&16)
  1261. dhp = status->hp - 1;
  1262. }
  1263. status->hp-= hp;
  1264. status->sp-= sp;
  1265. status->ap-= ap;
  1266. // Coma
  1267. if (flag&16) {
  1268. status->hp = 1;
  1269. status->sp = 1;
  1270. if (!sp) sp = 1; // To make sure the status bar is updated
  1271. }
  1272. if (sc && hp && status->hp) {
  1273. if (sc->getSCE(SC_AUTOBERSERK) &&
  1274. (!sc->getSCE(SC_PROVOKE) || !sc->getSCE(SC_PROVOKE)->val4) &&
  1275. status->hp < status->max_hp / 4)
  1276. sc_start4(src,target,SC_PROVOKE,100,10,0,0,1,0);
  1277. if (sc->getSCE(SC_BERSERK) && status->hp <= 100)
  1278. status_change_end(target, SC_BERSERK);
  1279. if( sc->getSCE(SC_RAISINGDRAGON) && status->hp <= 1000 )
  1280. status_change_end(target, SC_RAISINGDRAGON);
  1281. if (sc->getSCE(SC_SATURDAYNIGHTFEVER) && status->hp <= 100)
  1282. status_change_end(target, SC_SATURDAYNIGHTFEVER);
  1283. }
  1284. // Need to pass original HP damage for the mob damage log
  1285. dhp = cap_value(dhp, INT_MIN, INT_MAX);
  1286. switch (target->type) {
  1287. case BL_PC:
  1288. pc_damage(reinterpret_cast<map_session_data*>(target), src, hp, sp, ap);
  1289. break;
  1290. case BL_MOB:
  1291. mob_damage(reinterpret_cast<mob_data*>(target), src, static_cast<int32>(dhp));
  1292. break;
  1293. case BL_HOM:
  1294. hom_heal(reinterpret_cast<homun_data&>(*target), hp != 0, sp != 0);
  1295. break;
  1296. case BL_MER:
  1297. mercenary_heal(reinterpret_cast<s_mercenary_data*>(target), hp, sp);
  1298. break;
  1299. case BL_ELEM:
  1300. elemental_heal(reinterpret_cast<s_elemental_data*>(target), hp, sp);
  1301. break;
  1302. }
  1303. // Normal attack damage is logged in the monster's dmglog as attack damage
  1304. // This counts as exp tap and is used for determining the MVP
  1305. if (src && src->type == BL_MOB && skill_id == 0)
  1306. mob_log_damage(reinterpret_cast<mob_data*>(src), target, 0, dhp);
  1307. if( src && target->type == BL_PC && ((TBL_PC*)target)->disguise ) { // Stop walking when attacked in disguise to prevent walk-delay bug
  1308. unit_stop_walking( target, USW_FIXPOS );
  1309. }
  1310. if( status->hp || (flag&8) ) { // Still lives or has been dead before this damage.
  1311. if (walkdelay)
  1312. unit_set_walkdelay(target, gettick(), walkdelay, 0);
  1313. return (int32)(hp+sp+ap);
  1314. }
  1315. status->hp = 0;
  1316. /** [Skotlex]
  1317. * NOTE: These dead functions should return:
  1318. * 0: Death cancelled, auto-revived.
  1319. * Non-zero: Standard death. Clear status, cancel move/attack, etc
  1320. * &2: Remove object from map.
  1321. * &4: Delete object from memory. (One time spawn mobs)
  1322. **/
  1323. switch (target->type) {
  1324. case BL_PC: flag = pc_dead((TBL_PC*)target,src); break;
  1325. case BL_MOB: flag = mob_dead((TBL_MOB*)target, src, flag&4?3:0); break;
  1326. case BL_HOM: flag = hom_dead((TBL_HOM*)target); break;
  1327. case BL_MER: flag = mercenary_dead((TBL_MER*)target); break;
  1328. case BL_ELEM: flag = elemental_dead((TBL_ELEM*)target); break;
  1329. default: // Unhandled case, do nothing to object.
  1330. flag = 0;
  1331. break;
  1332. }
  1333. if(!flag) // Death cancelled.
  1334. return (int32)(hp+sp+ap);
  1335. // Normal death
  1336. if (battle_config.clear_unit_ondeath &&
  1337. battle_config.clear_unit_ondeath&target->type)
  1338. skill_clear_unitgroup(target);
  1339. if(target->type&BL_REGEN) { // Reset regen ticks.
  1340. struct regen_data *regen = status_get_regen_data(target);
  1341. if (regen) {
  1342. memset(&regen->tick, 0, sizeof(regen->tick));
  1343. if (regen->sregen)
  1344. memset(&regen->sregen->tick, 0, sizeof(regen->sregen->tick));
  1345. if (regen->ssregen)
  1346. memset(&regen->ssregen->tick, 0, sizeof(regen->ssregen->tick));
  1347. }
  1348. }
  1349. if( sc && sc->getSCE(SC_KAIZEL) && !map_flag_gvg2(target->m) ) { // flag&8 = disable Kaizel
  1350. int32 time = skill_get_time2(SL_KAIZEL,sc->getSCE(SC_KAIZEL)->val1);
  1351. // Look for Osiris Card's bonus effect on the character and revive 100% or revive normally
  1352. if ( target->type == BL_PC && BL_CAST(BL_PC,target)->special_state.restart_full_recover )
  1353. status_revive(target, 100, 100);
  1354. else
  1355. status_revive(target, sc->getSCE(SC_KAIZEL)->val2, 0);
  1356. status_change_clear(target,0);
  1357. clif_skill_nodamage(target,*target,ALL_RESURRECTION,1);
  1358. sc_start(src,target,SC_KYRIE,100,10,time);
  1359. if( target->type == BL_MOB )
  1360. ((TBL_MOB*)target)->state.rebirth = 1;
  1361. return (int32)(hp+sp+ap);
  1362. }
  1363. // Disable Ultimate Sacrifice on GVG maps
  1364. if (sc && sc->getSCE(SC_ULTIMATE_S) && !map_flag_gvg2(target->m)) {
  1365. status_revive(target, 100, 100);
  1366. status_change_clear(target, 0);
  1367. clif_skill_nodamage(target, *target, ALL_RESURRECTION, 1);
  1368. if (target->type == BL_MOB)
  1369. ((TBL_MOB*)target)->state.rebirth = 1;
  1370. return (int32)(hp+sp+ap);
  1371. }
  1372. if (target->type == BL_MOB && sc && sc->getSCE(SC_REBIRTH) && !((TBL_MOB*) target)->state.rebirth) { // Ensure the monster has not already rebirthed before doing so.
  1373. status_revive(target, sc->getSCE(SC_REBIRTH)->val2, 0);
  1374. status_change_clear(target,0);
  1375. ((TBL_MOB*)target)->state.rebirth = 1;
  1376. return (int32)(hp+sp+ap);
  1377. }
  1378. status_change_clear(target,0);
  1379. if(flag&4) // Delete from memory. (also invokes map removal code)
  1380. unit_free(target,CLR_DEAD);
  1381. else if(flag&2) // remove from map
  1382. unit_remove_map(target,CLR_DEAD);
  1383. else { // Some death states that would normally be handled by unit_remove_map
  1384. unit_stop_attack(target);
  1385. unit_stop_walking(target,USW_FIXPOS|USW_RELEASE_TARGET);
  1386. unit_skillcastcancel(target,0);
  1387. clif_clearunit_area( *target, CLR_DEAD );
  1388. skill_unit_move(target,gettick(),4);
  1389. skill_cleartimerskill(target);
  1390. }
  1391. // Always run NPC scripts for players last
  1392. //FIXME those ain't always run if a player die if he was resurrect meanwhile
  1393. //cf SC_REBIRTH, SC_KAIZEL, pc_dead...
  1394. if(target->type == BL_PC) {
  1395. TBL_PC *sd = BL_CAST(BL_PC,target);
  1396. if( sd->bg_id ) {
  1397. std::shared_ptr<s_battleground_data> bg = util::umap_find(bg_team_db, sd->bg_id);
  1398. if( bg && !(bg->die_event.empty()) )
  1399. npc_event(sd, bg->die_event.c_str(), 0);
  1400. }
  1401. npc_script_event( *sd, NPCE_DIE );
  1402. }
  1403. return (int32)(hp+sp+ap);
  1404. }
  1405. /**
  1406. * Heals an object
  1407. * @param bl: Object to heal [PC|MOB|HOM|MER|ELEM]
  1408. * @param hhp: How much HP to heal
  1409. * @param hsp: How much SP to heal
  1410. * @param hap: How much AP to heal
  1411. * @param flag: Whether it's Forced(&1), gives HP/SP/AP(&2) heal effect,
  1412. * or gives HP(&4) heal effect with 0 heal
  1413. * Forced healing overrides heal impedement statuses (Berserk)
  1414. * @return hp+sp+ap
  1415. */
  1416. int32 status_heal(struct block_list *bl,int64 hhp,int64 hsp, int64 hap, int32 flag)
  1417. {
  1418. status_change *sc;
  1419. int32 hp = (int32)cap_value(hhp,INT_MIN,INT_MAX);
  1420. int32 sp = (int32)cap_value(hsp,INT_MIN,INT_MAX);
  1421. int32 ap = (int32)cap_value(hap,INT_MIN,INT_MAX);
  1422. status_data* status = status_get_status_data(*bl);
  1423. if (status == &dummy_status || !status->hp)
  1424. return 0;
  1425. sc = status_get_sc(bl);
  1426. if (sc != nullptr && sc->empty())
  1427. sc = nullptr;
  1428. if (hp < 0) {
  1429. if (hp == INT_MIN) // -INT_MIN == INT_MIN in some architectures!
  1430. hp++;
  1431. status_damage(nullptr, bl, -hp, 0, 0, 1, 0);
  1432. hp = 0;
  1433. }
  1434. if(hp) {
  1435. if( sc && (sc->getSCE(SC_BERSERK)) ) {
  1436. if( flag&1 )
  1437. flag &= ~2;
  1438. else
  1439. hp = 0;
  1440. }
  1441. if((uint32)hp > status->max_hp - status->hp)
  1442. hp = status->max_hp - status->hp;
  1443. }
  1444. if(sp < 0) {
  1445. if (sp == INT_MIN)
  1446. sp++;
  1447. status_damage(nullptr, bl, 0, -sp, 0, 1, 0);
  1448. sp = 0;
  1449. }
  1450. if(sp) {
  1451. if((uint32)sp > status->max_sp - status->sp)
  1452. sp = status->max_sp - status->sp;
  1453. }
  1454. if (ap < 0) {
  1455. if (ap == INT_MIN)
  1456. ap++;
  1457. status_damage(nullptr, bl, 0, 0, -ap, 0, 1, 0);
  1458. ap = 0;
  1459. }
  1460. if (ap) {
  1461. if ((uint32)ap > status->max_ap - status->ap)
  1462. ap = status->max_ap - status->ap;
  1463. }
  1464. if(!ap && !sp && !hp && !(flag&4))
  1465. return 0;
  1466. status->hp += hp;
  1467. status->sp += sp;
  1468. status->ap += ap;
  1469. if(hp && sc &&
  1470. sc->getSCE(SC_AUTOBERSERK) &&
  1471. sc->getSCE(SC_PROVOKE) &&
  1472. sc->getSCE(SC_PROVOKE)->val4==1 &&
  1473. status->hp >= status->max_hp / 4
  1474. ) // End auto berserk.
  1475. status_change_end(bl, SC_PROVOKE);
  1476. // Send HP update to client
  1477. switch(bl->type) {
  1478. case BL_PC:
  1479. pc_heal(reinterpret_cast<map_session_data*>(bl), hp, sp, ap, flag);
  1480. break;
  1481. case BL_MOB:
  1482. mob_heal(reinterpret_cast<mob_data*>(bl), hp);
  1483. break;
  1484. case BL_HOM:
  1485. hom_heal(reinterpret_cast<homun_data&>(*bl), hp != 0, sp != 0);
  1486. break;
  1487. case BL_MER:
  1488. mercenary_heal(reinterpret_cast<s_mercenary_data*>(bl), hp, sp);
  1489. break;
  1490. case BL_ELEM:
  1491. elemental_heal(reinterpret_cast<s_elemental_data*>(bl), hp, sp);
  1492. break;
  1493. }
  1494. return (int32)hp+sp+ap;
  1495. }
  1496. /**
  1497. * Applies percentage based damage to a unit.
  1498. * If a mob is killed this way and there is no src, no EXP/Drops will be awarded.
  1499. * @param src: Object initiating HP/SP/AP modification [PC|MOB|PET|HOM|MER|ELEM]
  1500. * @param target: Object to modify HP/SP/AP
  1501. * @param hp_rate: Percentage of HP to modify. If > 0:percent is of current HP, if < 0:percent is of max HP
  1502. * @param sp_rate: Percentage of SP to modify. If > 0:percent is of current SP, if < 0:percent is of max SP
  1503. * @param ap_rate: Percentage of AP to modify. If > 0:percent is of current AP, if < 0:percent is of max AP
  1504. * @param flag: \n
  1505. * 0: Heal target \n
  1506. * 1: Use status_damage \n
  1507. * 2: Use status_damage and make sure target must not die from subtraction
  1508. * @return hp+sp+ap through status_heal()
  1509. */
  1510. int32 status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, int8 ap_rate, uint8 flag)
  1511. {
  1512. uint32 hp = 0, sp = 0, ap = 0;
  1513. status_data* status = status_get_status_data(*target);
  1514. // It's safe now [MarkZD]
  1515. if (hp_rate > 99)
  1516. hp = status->hp;
  1517. else if (hp_rate > 0)
  1518. hp = apply_rate(status->hp, hp_rate);
  1519. else if (hp_rate < -99)
  1520. hp = status->max_hp;
  1521. else if (hp_rate < 0)
  1522. hp = (apply_rate(status->max_hp, -hp_rate));
  1523. if (hp_rate && !hp)
  1524. hp = 1;
  1525. if (flag == 2 && hp >= status->hp)
  1526. hp = status->hp-1; // Must not kill target.
  1527. if (sp_rate > 99)
  1528. sp = status->sp;
  1529. else if (sp_rate > 0)
  1530. sp = apply_rate(status->sp, sp_rate);
  1531. else if (sp_rate < -99)
  1532. sp = status->max_sp;
  1533. else if (sp_rate < 0)
  1534. sp = (apply_rate(status->max_sp, -sp_rate));
  1535. if (sp_rate && !sp)
  1536. sp = 1;
  1537. if (ap_rate > 99)
  1538. ap = status->ap;
  1539. else if (ap_rate > 0)
  1540. ap = apply_rate(status->ap, ap_rate);
  1541. else if (ap_rate < -99)
  1542. ap = status->max_ap;
  1543. else if (ap_rate < 0)
  1544. ap = (apply_rate(status->max_ap, -ap_rate));
  1545. if (ap_rate && !ap)
  1546. ap = 1;
  1547. // Ugly check in case damage dealt is too much for the received args of
  1548. // status_heal / status_damage. [Skotlex]
  1549. if (hp > INT_MAX) {
  1550. hp -= INT_MAX;
  1551. if (flag)
  1552. status_damage(src, target, INT_MAX, 0, 0, (!src||src==target?5:1), 0);
  1553. else
  1554. status_heal(target, INT_MAX, 0, 0);
  1555. }
  1556. if (sp > INT_MAX) {
  1557. sp -= INT_MAX;
  1558. if (flag)
  1559. status_damage(src, target, 0, INT_MAX, 0, (!src||src==target?5:1), 0);
  1560. else
  1561. status_heal(target, 0, INT_MAX, 0);
  1562. }
  1563. if (ap > INT_MAX) {
  1564. ap -= INT_MAX;
  1565. if (flag)
  1566. status_damage(src, target, 0, 0, INT_MAX, 0, (!src || src == target ? 5 : 1), 0);
  1567. else
  1568. status_heal(target, 0, 0, INT_MAX, 0);
  1569. }
  1570. if (flag)
  1571. return status_damage(src, target, hp, sp, ap, 0, (!src||src==target?5:1), 0);
  1572. return status_heal(target, hp, sp, ap, 0);
  1573. }
  1574. /**
  1575. * Revives a unit
  1576. * @param bl: Object to revive [PC|MOB|HOM]
  1577. * @param per_hp: Percentage of HP to revive with
  1578. * @param per_sp: Percentage of SP to revive with
  1579. * @param per_ap: Percentage of AP to revive with
  1580. * @return Successful (1) or Invalid target (0)
  1581. */
  1582. int32 status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp, unsigned char per_ap)
  1583. {
  1584. uint32 hp, sp, ap;
  1585. if (!status_isdead(*bl)) return 0;
  1586. status_data* status = status_get_status_data(*bl);
  1587. if (status == &dummy_status)
  1588. return 0; // Invalid target.
  1589. hp = (int64)status->max_hp * per_hp/100;
  1590. sp = (int64)status->max_sp * per_sp/100;
  1591. ap = (int64)status->max_ap * per_ap/100;
  1592. if(hp > status->max_hp - status->hp)
  1593. hp = status->max_hp - status->hp;
  1594. else if (per_hp && !hp)
  1595. hp = 1;
  1596. if(sp > status->max_sp - status->sp)
  1597. sp = status->max_sp - status->sp;
  1598. else if (per_sp && !sp)
  1599. sp = 1;
  1600. if (ap > status->max_ap - status->ap)
  1601. ap = status->max_ap - status->ap;
  1602. else if (per_ap && !ap)
  1603. ap = 1;
  1604. status->hp += hp;
  1605. status->sp += sp;
  1606. status->ap += ap;
  1607. if (bl->prev) // Animation only if character is already on a map.
  1608. clif_resurrection( *bl );
  1609. switch (bl->type) {
  1610. case BL_PC: pc_revive((TBL_PC*)bl, hp, sp, ap); break;
  1611. case BL_MOB: mob_revive((TBL_MOB*)bl, hp); break;
  1612. case BL_HOM: hom_revive((TBL_HOM*)bl, hp, sp); break;
  1613. }
  1614. return 1;
  1615. }
  1616. /**
  1617. * Checks whether the src can use the skill on the target,
  1618. * taking into account status/option of both source/target
  1619. * @param src: Object using skill on target [PC|MOB|PET|HOM|MER|ELEM]
  1620. src MAY be nullptr to indicate we shouldn't check it, this is a ground-based skill attack
  1621. * @param target: Object being targeted by src [PC|MOB|HOM|MER|ELEM]
  1622. target MAY be nullptr, which checks if src can cast skill_id on the ground
  1623. * @param skill_id: Skill ID being used on target
  1624. * @param flag: 0 - Trying to use skill on target
  1625. * 1 - Cast bar is done
  1626. * 2 - Skill already pulled off, check is due to ground-based skills or splash-damage ones
  1627. * @return src can use skill (1) or cannot use skill (0)
  1628. * @author [Skotlex]
  1629. */
  1630. bool status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int32 flag) {
  1631. status_data* status;
  1632. int32 hide_flag;
  1633. if (src) {
  1634. if (src->type != BL_PC && status_isdead(*src))
  1635. return false;
  1636. status = status_get_status_data(*src);
  1637. }else{
  1638. status = &dummy_status;
  1639. }
  1640. status_change *sc = status_get_sc(src);
  1641. status_change *tsc = status_get_sc(target);
  1642. if (!skill_id) { // Normal attack checks.
  1643. if (sc && sc->cant.attack)
  1644. return false;
  1645. // This mode is only needed for melee attacking.
  1646. if (!status_has_mode(status,MD_CANATTACK))
  1647. return false;
  1648. // Dead state is not checked for skills as some skills can be used
  1649. // on dead characters, said checks are left to skill.cpp [Skotlex]
  1650. if (target && status_isdead(*target))
  1651. return false;
  1652. }
  1653. switch( skill_id ) {
  1654. #ifndef RENEWAL
  1655. case PA_PRESSURE:
  1656. if( flag && tsc && tsc->option&OPTION_HIDE)
  1657. return false; // Gloria Avoids pretty much everything....
  1658. break;
  1659. #endif
  1660. case GN_WALLOFTHORN:
  1661. if( target && status_isdead(*target) )
  1662. return false;
  1663. break;
  1664. case AL_TELEPORT:
  1665. case ALL_ODINS_POWER:
  1666. // Should fail when used on top of Land Protector [Skotlex]
  1667. if (src && map_getcell(src->m, src->x, src->y, CELL_CHKLANDPROTECTOR)
  1668. && !status_has_mode(status,MD_STATUSIMMUNE)
  1669. && (src->type != BL_PC || ((TBL_PC*)src)->skillitem != skill_id))
  1670. return false;
  1671. break;
  1672. case SC_MANHOLE:
  1673. // Skill is disabled against special racial grouped monsters(GvG and Battleground)
  1674. if (target && ( util::vector_exists(status_get_race2(target), RC2_GVG) || util::vector_exists(status_get_race2(target), RC2_BATTLEFIELD) ) )
  1675. return false;
  1676. default:
  1677. break;
  1678. }
  1679. if( sc != nullptr && !sc->empty() ) {
  1680. if (sc->getSCE(SC_ALL_RIDING))
  1681. return false; //You can't use skills while in the new mounts (The client doesn't let you, this is to make cheat-safe)
  1682. if (flag == 1 && !status_has_mode(status,MD_STATUSIMMUNE) && ( // Applies to after cast completion only and doesn't apply to Boss monsters.
  1683. (sc->getSCE(SC_ASH) && rnd()%2) || // Volcanic Ash has a 50% chance of causing skills to fail.
  1684. (sc->getSCE(SC_KYOMU) && rnd()%100 < 25) // Kyomu has a 25% chance of causing skills fail.
  1685. )) {
  1686. if (src->type == BL_PC)
  1687. clif_skill_fail( *((map_session_data*)src), skill_id );
  1688. return false;
  1689. }
  1690. if (skill_id > 0 && sc->opt1 && sc->opt1 != OPT1_STONEWAIT && sc->opt1 != OPT1_BURNING && skill_id != RK_REFRESH && skill_id != SU_GROOMING && skill_id != SR_GENTLETOUCH_CURE) { // Stuned/Frozen/etc
  1691. if (flag != 1) // Can't cast, casted stuff can't damage.
  1692. return false;
  1693. if (skill_get_casttype(skill_id) == CAST_DAMAGE)
  1694. return false; // Damage spells stop casting.
  1695. }
  1696. if (
  1697. (sc->getSCE(SC_TRICKDEAD) && skill_id != NV_TRICKDEAD)
  1698. || (sc->getSCE(SC_AUTOCOUNTER) && !flag && skill_id)
  1699. || (sc->getSCE(SC_GOSPEL) && sc->getSCE(SC_GOSPEL)->val4 == BCT_SELF && skill_id != PA_GOSPEL)
  1700. || (sc->getSCE(SC_SUHIDE) && skill_id != SU_HIDE)
  1701. )
  1702. return false;
  1703. if (sc->getSCE(SC_WINKCHARM) && target && !flag) { // Prevents skill usage
  1704. block_list *wink_target = map_id2bl(sc->getSCE(SC_WINKCHARM)->val2);
  1705. if (wink_target != nullptr) {
  1706. unit_data *wink_ud = unit_bl2ud(src);
  1707. if (wink_ud != nullptr && wink_ud->walktimer == INVALID_TIMER)
  1708. unit_walktobl(src, map_id2bl(sc->getSCE(SC_WINKCHARM)->val2), 3, 1);
  1709. clif_emotion(src, ET_THROB);
  1710. return false;
  1711. } else
  1712. status_change_end(src, SC_WINKCHARM);
  1713. }
  1714. if (sc->getSCE(SC_BLADESTOP)) {
  1715. switch (sc->getSCE(SC_BLADESTOP)->val1) {
  1716. case 5:
  1717. if (skill_id == MO_EXTREMITYFIST)
  1718. break;
  1719. [[fallthrough]];
  1720. case 4:
  1721. if (skill_id == MO_CHAINCOMBO)
  1722. break;
  1723. [[fallthrough]];
  1724. case 3:
  1725. if (skill_id == MO_INVESTIGATE)
  1726. break;
  1727. [[fallthrough]];
  1728. case 2:
  1729. if (skill_id == MO_FINGEROFFENSIVE)
  1730. break;
  1731. [[fallthrough]];
  1732. default:
  1733. return false;
  1734. }
  1735. }
  1736. if (sc->getSCE(SC_DANCING) && flag!=2) {
  1737. std::shared_ptr<s_skill_db> skill = skill_db.find(skill_id);
  1738. if (!skill)
  1739. return false;
  1740. if (src->type == BL_PC && ((skill_id >= WA_SWING_DANCE && skill_id <= WM_UNLIMITED_HUMMING_VOICE ) ||
  1741. skill_id == WM_FRIGG_SONG))
  1742. { // Lvl 5 Lesson or higher allow you use 3rd job skills while dancing.
  1743. if( pc_checkskill((TBL_PC*)src,WM_LESSON) < 5 )
  1744. return false;
  1745. #ifndef RENEWAL
  1746. } else if(sc->getSCE(SC_LONGING)) { // Allow everything except dancing/re-dancing. [Skotlex]
  1747. if (skill_id == BD_ENCORE || skill->inf2[INF2_ISSONG] || skill->inf2[INF2_ISENSEMBLE])
  1748. return false;
  1749. #endif
  1750. } else if(!skill->inf2[INF2_ALLOWWHENPERFORMING]) // Skills that can be used in dancing state
  1751. return false;
  1752. #ifndef RENEWAL
  1753. if ((sc->getSCE(SC_DANCING)->val1&0xFFFF) == CG_HERMODE && skill_id == BD_ADAPTATION)
  1754. return false; // Can't amp out of Wand of Hermode :/ [Skotlex]
  1755. #endif
  1756. }
  1757. if (skill_id && // Do not block item-casted skills.
  1758. (src->type != BL_PC || ((TBL_PC*)src)->skillitem != skill_id)
  1759. ) { // Skills blocked through status changes...
  1760. if (!flag && ( // Blocked only from using the skill (stuff like autospell may still go through
  1761. ( sc->cant.cast && skill_id != RK_REFRESH && skill_id != SU_GROOMING && skill_id != SR_GENTLETOUCH_CURE ) ||
  1762. #ifndef RENEWAL
  1763. (sc->getSCE(SC_BASILICA) && (sc->getSCE(SC_BASILICA)->val4 != src->id || skill_id != HP_BASILICA)) || // Only Basilica caster that can cast, and only Basilica to cancel it
  1764. #endif
  1765. (sc->getSCE(SC_MARIONETTE) && skill_id != CG_MARIONETTE) || // Only skill you can use is marionette again to cancel it
  1766. (sc->getSCE(SC_MARIONETTE2) && skill_id == CG_MARIONETTE) || // Cannot use marionette if you are being buffed by another
  1767. (sc->getSCE(SC_ANKLE) && skill_block_check(src, SC_ANKLE, skill_id)) ||
  1768. (sc->getSCE(SC_STASIS) && skill_block_check(src, SC_STASIS, skill_id)) ||
  1769. (sc->getSCE(SC_BITE) && skill_block_check(src, SC_BITE, skill_id)) ||
  1770. (sc->getSCE(SC_NOVAEXPLOSING) && skill_block_check(src, SC_NOVAEXPLOSING, skill_id)) ||
  1771. (sc->getSCE(SC_GRAVITYCONTROL) && skill_block_check(src, SC_GRAVITYCONTROL, skill_id)) ||
  1772. (sc->getSCE(SC_KAGEHUMI) && skill_block_check(src, SC_KAGEHUMI, skill_id))
  1773. #ifdef RENEWAL
  1774. || (sc->getSCE(SC_ENSEMBLEFATIGUE) && skill_id != CG_SPECIALSINGER)
  1775. #endif
  1776. ))
  1777. return false;
  1778. // Skill blocking.
  1779. if (
  1780. (sc->getSCE(SC_VOLCANO) && skill_id == WZ_ICEWALL) ||
  1781. #ifndef RENEWAL
  1782. (sc->getSCE(SC_ROKISWEIL) && skill_id != BD_ADAPTATION) ||
  1783. #endif
  1784. (sc->getSCE(SC_HERMODE) && skill_get_inf(skill_id) & INF_SUPPORT_SKILL) ||
  1785. (sc->getSCE(SC_NOCHAT) && sc->getSCE(SC_NOCHAT)->val1&MANNER_NOSKILL)
  1786. )
  1787. return false;
  1788. }
  1789. if (sc->option) {
  1790. if ((sc->option&OPTION_HIDE) && src->type == BL_PC && (skill_id == 0 || !skill_get_inf2(skill_id, INF2_ALLOWWHENHIDDEN))) {
  1791. // Non players can use all skills while hidden.
  1792. return false;
  1793. }
  1794. if (sc->option&OPTION_CHASEWALK && skill_id != ST_CHASEWALK)
  1795. return false;
  1796. }
  1797. }
  1798. if (target == nullptr || target == src) // No further checking needed.
  1799. return true;
  1800. if (tsc != nullptr && !tsc->empty()) {
  1801. if(!skill_id && tsc->getSCE(SC_TRICKDEAD))
  1802. return false;
  1803. if((skill_id == WZ_STORMGUST || skill_id == WZ_FROSTNOVA || skill_id == NJ_HYOUSYOURAKU || skill_id == NPC_STORMGUST2)
  1804. && tsc->getSCE(SC_FREEZE))
  1805. return false;
  1806. if(skill_id == PR_LEXAETERNA && (tsc->getSCE(SC_FREEZE) || tsc->getSCE(SC_STONE)))
  1807. return false;
  1808. if (tsc->getSCE(SC__MANHOLE) && !skill_get_inf2(skill_id, INF2_TARGETMANHOLE))
  1809. return false;
  1810. }
  1811. // If targetting, cloak+hide protect you, otherwise only hiding does.
  1812. hide_flag = flag?OPTION_HIDE:(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK);
  1813. // Skill that can hit hidden target
  1814. if( skill_get_inf2(skill_id, INF2_TARGETHIDDEN) )
  1815. hide_flag &= ~OPTION_HIDE;
  1816. switch( target->type ) {
  1817. case BL_PC: {
  1818. map_session_data *tsd = (TBL_PC*)target;
  1819. bool is_boss = (src && status_get_class_(src) == CLASS_BOSS);
  1820. bool is_detect = status_has_mode(status,MD_DETECTOR);
  1821. if (pc_isinvisible(tsd))
  1822. return false;
  1823. if (tsc) {
  1824. if ((tsc->option&hide_flag) && !is_boss && (tsd->special_state.perfect_hiding || !is_detect))
  1825. return false;
  1826. if ((tsc->getSCE(SC_CLOAKINGEXCEED) || tsc->getSCE(SC_NEWMOON)) && !is_boss && (tsd->special_state.perfect_hiding || is_detect))
  1827. return false; // Works against insect and demon but not against bosses
  1828. if (tsc->getSCE(SC__FEINTBOMB) && (is_boss || is_detect))
  1829. return false; // Works against all
  1830. if ((tsc->getSCE(SC_CAMOUFLAGE) || tsc->getSCE(SC_STEALTHFIELD) || tsc->getSCE(SC_SUHIDE)) && !(is_boss || is_detect) && (!skill_id || (!flag && src)))
  1831. return false; // Insect, demon, and boss can detect
  1832. }
  1833. }
  1834. break;
  1835. case BL_ITEM: // Allow targetting of items to pick'em up (or in the case of mobs, to loot them).
  1836. // !TODO: Would be nice if this could be used to judge whether the player can or not pick up the item it targets. [Skotlex]
  1837. if (status_has_mode(status,MD_LOOTER))
  1838. return true;
  1839. return false;
  1840. case BL_HOM:
  1841. case BL_MER:
  1842. case BL_ELEM:
  1843. if( target->type == BL_HOM && skill_id && battle_config.hom_setting&HOMSET_NO_SUPPORT_SKILL && skill_get_inf(skill_id)&INF_SUPPORT_SKILL && battle_get_master(target) != src )
  1844. return false; // Can't use support skills on Homunculus (only Master/Self)
  1845. if( target->type == BL_MER && (skill_id == PR_ASPERSIO || (skill_id >= SA_FLAMELAUNCHER && skill_id <= SA_SEISMICWEAPON)) && battle_get_master(target) != src )
  1846. return false; // Can't use Weapon endow skills on Mercenary (only Master)
  1847. if( skill_id == AM_POTIONPITCHER && ( target->type == BL_MER || target->type == BL_ELEM) )
  1848. return false; // Can't use Potion Pitcher on Mercenaries
  1849. if (tsc && tsc->getSCE(SC_ELEMENTAL_VEIL) && !(src && status_get_class_(src) == CLASS_BOSS) && !status_has_mode(status, MD_DETECTOR))
  1850. return false;
  1851. [[fallthrough]];
  1852. default:
  1853. // Check for chase-walk/hiding/cloaking opponents.
  1854. if( tsc ) {
  1855. if( tsc->option&hide_flag && !status_has_mode(status,MD_DETECTOR))
  1856. return false;
  1857. }
  1858. }
  1859. return true;
  1860. }
  1861. /**
  1862. * Checks whether the src can see the target
  1863. * @param src: Object using skill on target [PC|MOB|PET|HOM|MER|ELEM]
  1864. * @param target: Object being targeted by src [PC|MOB|HOM|MER|ELEM]
  1865. * @param checkblind: Whether blind condition should be considered (sets view range to 1)
  1866. * @return src can see (true) or target is invisible (false)
  1867. * @author [Skotlex]
  1868. */
  1869. bool status_check_visibility(block_list* src, block_list* target, bool checkblind)
  1870. {
  1871. int32 view_range;
  1872. status_change* tsc = status_get_sc(target);
  1873. switch (src->type) {
  1874. case BL_MOB:
  1875. view_range = ((TBL_MOB*)src)->db->range3;
  1876. break;
  1877. case BL_PET:
  1878. view_range = ((TBL_PET*)src)->db->range2;
  1879. break;
  1880. default:
  1881. view_range = AREA_SIZE;
  1882. }
  1883. if (checkblind) {
  1884. status_change* sc = status_get_sc(src);
  1885. if (sc != nullptr && sc->getSCE(SC_BLIND) != nullptr)
  1886. view_range = 1;
  1887. }
  1888. if (src->m != target->m || !check_distance_bl(src, target, view_range))
  1889. return false;
  1890. if ( src->type == BL_NPC) // NPCs don't care for the rest
  1891. return true;
  1892. if (tsc) {
  1893. bool is_boss = (status_get_class_(src) == CLASS_BOSS);
  1894. bool is_detector = status_bl_has_mode(src,MD_DETECTOR);
  1895. switch (target->type) { // Check for chase-walk/hiding/cloaking opponents.
  1896. case BL_PC: {
  1897. map_session_data *tsd = (TBL_PC*)target;
  1898. if (((tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) || tsc->getSCE(SC_CAMOUFLAGE) || tsc->getSCE(SC_STEALTHFIELD) || tsc->getSCE(SC_SUHIDE)) && !is_boss && (tsd->special_state.perfect_hiding || !is_detector))
  1899. return false;
  1900. if ((tsc->getSCE(SC_CLOAKINGEXCEED) || tsc->getSCE(SC_NEWMOON)) && !is_boss && ((tsd && tsd->special_state.perfect_hiding) || is_detector))
  1901. return false;
  1902. if (tsc->getSCE(SC__FEINTBOMB) && !is_boss && !is_detector)
  1903. return false;
  1904. }
  1905. break;
  1906. case BL_ELEM:
  1907. if (tsc->getSCE(SC_ELEMENTAL_VEIL) && !is_boss && !is_detector)
  1908. return false;
  1909. break;
  1910. default:
  1911. if (((tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) || tsc->getSCE(SC_CAMOUFLAGE) || tsc->getSCE(SC_STEALTHFIELD) || tsc->getSCE(SC_SUHIDE)) && !is_boss && !is_detector)
  1912. return false;
  1913. }
  1914. }
  1915. return true;
  1916. }
  1917. /**
  1918. * Base ASPD value taken from the job tables
  1919. * @param sd: Player object
  1920. * @param status: Player status
  1921. * @return base amotion after single/dual weapon and shield adjustments [RENEWAL]
  1922. * base amotion after single/dual weapon and stats adjustments [PRE-RENEWAL]
  1923. */
  1924. int32 status_base_amotion_pc(map_session_data* sd, struct status_data* status)
  1925. {
  1926. std::shared_ptr<s_job_info> job = job_db.find(sd->status.class_);
  1927. if (job == nullptr)
  1928. return 2000;
  1929. int32 amotion;
  1930. #ifdef RENEWAL_ASPD
  1931. int16 skill_lv, val = 0;
  1932. float temp_aspd = 0;
  1933. amotion = job->aspd_base[sd->weapontype1]; // Single weapon
  1934. if (sd->status.shield)
  1935. amotion += job->aspd_base[MAX_WEAPON_TYPE];
  1936. else if (sd->weapontype2 != W_FIST && sd->equip_index[EQI_HAND_R] != sd->equip_index[EQI_HAND_L])
  1937. amotion += job->aspd_base[sd->weapontype2] / 4; // Dual-wield
  1938. switch(sd->status.weapon) {
  1939. case W_BOW:
  1940. case W_MUSICAL:
  1941. case W_WHIP:
  1942. case W_REVOLVER:
  1943. case W_RIFLE:
  1944. case W_GATLING:
  1945. case W_SHOTGUN:
  1946. case W_GRENADE:
  1947. temp_aspd = status->dex * status->dex / 7.0f + status->agi * status->agi * 0.5f;
  1948. break;
  1949. default:
  1950. temp_aspd = status->dex * status->dex / 5.0f + status->agi * status->agi * 0.5f;
  1951. break;
  1952. }
  1953. temp_aspd = (float)(sqrt(temp_aspd) * 0.25f) + 0xc4;
  1954. if ((skill_lv = pc_checkskill(sd,SA_ADVANCEDBOOK)) > 0 && sd->status.weapon == W_BOOK)
  1955. val += (skill_lv - 1) / 2 + 1;
  1956. if ((skill_lv = pc_checkskill(sd, SG_DEVIL)) > 0 && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd)))
  1957. val += 1 + skill_lv;
  1958. if ((skill_lv = pc_checkskill(sd,GS_SINGLEACTION)) > 0 && (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE))
  1959. val += ((skill_lv + 1) / 2);
  1960. if (pc_isriding(sd))
  1961. val -= 50 - 10 * pc_checkskill(sd, KN_CAVALIERMASTERY);
  1962. else if (pc_isridingdragon(sd))
  1963. val -= 25 - 5 * pc_checkskill(sd, RK_DRAGONTRAINING);
  1964. amotion = ((int32)(temp_aspd + ((float)(status_calc_aspd(&sd->bl, &sd->sc, true) + val) * status->agi / 200)) - min(amotion, 200));
  1965. #else
  1966. // Angra Manyu disregards aspd_base and similar
  1967. if (pc_checkequip2(sd, ITEMID_ANGRA_MANYU, EQI_ACC_L, EQI_MAX))
  1968. return 0;
  1969. // Base weapon delay
  1970. amotion = (sd->status.weapon < MAX_WEAPON_TYPE)
  1971. ? (job->aspd_base[sd->status.weapon]) // Single weapon
  1972. : (job->aspd_base[sd->weapontype1] + job->aspd_base[sd->weapontype2]) * 7 / 10; // Dual-wield
  1973. // Percentual delay reduction from stats
  1974. amotion -= amotion * (4 * status->agi + status->dex) / 1000;
  1975. // Raw delay adjustment from bAspd bonus
  1976. amotion += sd->bonus.aspd_add;
  1977. #endif
  1978. return amotion;
  1979. }
  1980. /**
  1981. * Base attack value calculated for units
  1982. * @param bl: Object to get attack for [BL_CHAR|BL_NPC]
  1983. * @param status: Object status
  1984. * @return base attack
  1985. */
  1986. uint16 status_base_atk(const struct block_list *bl, const struct status_data *status, int32 level)
  1987. {
  1988. int32 flag = 0, str, dex, dstr;
  1989. #ifdef RENEWAL
  1990. if (!(bl->type&battle_config.enable_baseatk_renewal))
  1991. return 0;
  1992. #else
  1993. if (!(bl->type&battle_config.enable_baseatk))
  1994. return 0;
  1995. #endif
  1996. if (bl->type == BL_PC)
  1997. switch(((TBL_PC*)bl)->status.weapon) {
  1998. case W_BOW:
  1999. case W_MUSICAL:
  2000. case W_WHIP:
  2001. case W_REVOLVER:
  2002. case W_RIFLE:
  2003. case W_GATLING:
  2004. case W_SHOTGUN:
  2005. case W_GRENADE:
  2006. flag = 1;
  2007. }
  2008. if (flag) {
  2009. #ifdef RENEWAL
  2010. dstr =
  2011. #endif
  2012. str = status->dex;
  2013. dex = status->str;
  2014. } else {
  2015. #ifdef RENEWAL
  2016. dstr =
  2017. #endif
  2018. str = status->str;
  2019. dex = status->dex;
  2020. }
  2021. /** [Skotlex]
  2022. * Normally only players have base-atk, but homunc have a different batk
  2023. * equation, hinting that perhaps non-players should use this for batk.
  2024. **/
  2025. switch (bl->type) {
  2026. case BL_HOM:
  2027. #ifdef RENEWAL
  2028. str = 2 * level + status_get_homstr(bl);
  2029. #else
  2030. dstr = str / 10;
  2031. str += dstr*dstr;
  2032. #endif
  2033. break;
  2034. case BL_PC:
  2035. #ifdef RENEWAL
  2036. str = (dstr * 10 + dex * 10 / 5 + status->luk * 10 / 3 + level * 10 / 4) / 10 + 5 * status->pow;
  2037. #else
  2038. dstr = str / 10;
  2039. str += dstr*dstr;
  2040. str += dex / 5 + status->luk / 5;
  2041. #endif
  2042. break;
  2043. default:// Others
  2044. #ifdef RENEWAL
  2045. str = dstr + level;
  2046. #else
  2047. dstr = str / 10;
  2048. str += dstr*dstr;
  2049. str += dex / 5 + status->luk / 5;
  2050. #endif
  2051. break;
  2052. }
  2053. return cap_value(str, 0, USHRT_MAX);
  2054. }
  2055. #ifdef RENEWAL
  2056. /**
  2057. * Weapon attack value calculated for Players
  2058. * @param wa: Weapon attack
  2059. * @param status: Player status
  2060. * @return weapon attack
  2061. */
  2062. uint32 status_weapon_atk(weapon_atk &wa)
  2063. {
  2064. return wa.atk + wa.atk2;
  2065. }
  2066. #endif
  2067. #ifndef RENEWAL
  2068. uint16 status_base_matk_min(const struct status_data* status) { return status->int_ + (status->int_ / 7) * (status->int_ / 7); }
  2069. uint16 status_base_matk_max(const struct status_data* status) { return status->int_ + (status->int_ / 5) * (status->int_ / 5); }
  2070. #else
  2071. /*
  2072. * Calculates minimum attack variance 80% from db's ATK1 for non BL_PC
  2073. * status->batk (base attack) will be added in battle_calc_base_damage
  2074. */
  2075. uint16 status_base_atk_min(struct block_list *bl, const struct status_data* status, int32 level)
  2076. {
  2077. switch (bl->type) {
  2078. case BL_PET:
  2079. case BL_MOB:
  2080. case BL_MER:
  2081. case BL_ELEM:
  2082. return status->rhw.atk * 80 / 100;
  2083. case BL_HOM:
  2084. return (status_get_homstr(bl) + status_get_homdex(bl)) / 5;
  2085. default:
  2086. return status->rhw.atk;
  2087. }
  2088. }
  2089. /*
  2090. * Calculates maximum attack variance 120% from db's ATK1 for non BL_PC
  2091. * status->batk (base attack) will be added in battle_calc_base_damage
  2092. */
  2093. uint16 status_base_atk_max(struct block_list *bl, const struct status_data* status, int32 level)
  2094. {
  2095. switch (bl->type) {
  2096. case BL_PET:
  2097. case BL_MOB:
  2098. case BL_MER:
  2099. case BL_ELEM:
  2100. return status->rhw.atk * 120 / 100;
  2101. case BL_HOM:
  2102. return (status_get_homluk(bl) + status_get_homstr(bl) + status_get_homdex(bl)) / 3;
  2103. default:
  2104. return status->rhw.atk2;
  2105. }
  2106. }
  2107. /*
  2108. * Calculates minimum magic attack
  2109. */
  2110. uint16 status_base_matk_min(struct block_list *bl, const struct status_data* status, int32 level)
  2111. {
  2112. switch (bl->type) {
  2113. case BL_PET:
  2114. case BL_MOB:
  2115. case BL_MER:
  2116. case BL_ELEM:
  2117. return status->int_ + level + status->rhw.matk * 70 / 100;
  2118. case BL_HOM:
  2119. return status_get_homint(bl) + level + (status_get_homint(bl) + status_get_homdex(bl)) / 5;
  2120. case BL_PC:
  2121. default:
  2122. return status->int_ + (status->int_ / 2) + (status->dex / 5) + (status->luk / 3) + (level / 4) + 5 * status->spl;
  2123. }
  2124. }
  2125. /*
  2126. * Calculates maximum magic attack
  2127. */
  2128. uint16 status_base_matk_max(struct block_list *bl, const struct status_data* status, int32 level)
  2129. {
  2130. switch (bl->type) {
  2131. case BL_PET:
  2132. case BL_MOB:
  2133. case BL_MER:
  2134. case BL_ELEM:
  2135. return status->int_ + level + status->rhw.matk * 130 / 100;
  2136. case BL_HOM:
  2137. return status_get_homint(bl) + level + (status_get_homluk(bl) + status_get_homint(bl) + status_get_homdex(bl)) / 3;
  2138. case BL_PC:
  2139. default:
  2140. return status->int_ + (status->int_ / 2) + (status->dex / 5) + (status->luk / 3) + (level / 4) + 5 * status->spl;
  2141. }
  2142. }
  2143. #endif
  2144. /**
  2145. * Fills in the misc data that can be calculated from the other status info (except for level)
  2146. * @param bl: Object to calculate status on [PC|MOB|PET|HOM|MERC|ELEM]
  2147. * @param status: Player status
  2148. */
  2149. void status_calc_misc(struct block_list *bl, struct status_data *status, int32 level)
  2150. {
  2151. int32 stat;
  2152. // Non players get the value set, players need to stack with previous bonuses.
  2153. if( bl->type != BL_PC ){
  2154. status->batk =
  2155. status->hit = status->flee =
  2156. status->def2 = status->mdef2 =
  2157. status->cri = status->flee2 =
  2158. status->patk = status->smatk =
  2159. status->hplus = status->crate = 0;
  2160. if (bl->type != BL_MOB) // BL_MOB has values set when loading mob_db
  2161. status->res = status->mres = 0;
  2162. }
  2163. #ifdef RENEWAL // Renewal formulas
  2164. if (bl->type == BL_HOM) {
  2165. // Def2
  2166. stat = status_get_homvit(bl) + status_get_homagi(bl) / 2;
  2167. status->def2 = cap_value(stat, 0, SHRT_MAX);
  2168. // Mdef2
  2169. stat = (status_get_homvit(bl) + status_get_homint(bl)) / 2;
  2170. status->mdef2 = cap_value(stat, 0, SHRT_MAX);
  2171. // Def
  2172. stat = status->def;
  2173. stat += status_get_homvit(bl) + level / 2;
  2174. status->def = cap_value(stat, 0, SHRT_MAX);
  2175. // Mdef
  2176. stat = (int32)(((float)status_get_homvit(bl) + level) / 4 + (float)status_get_homint(bl) / 2);
  2177. status->mdef = cap_value(stat, 0, SHRT_MAX);
  2178. // Hit
  2179. stat = level + status->dex + 150;
  2180. status->hit = cap_value(stat, 1, SHRT_MAX);
  2181. // Flee
  2182. stat = level + status_get_homagi(bl);
  2183. status->flee = cap_value(stat, 1, SHRT_MAX);
  2184. } else {
  2185. // Hit
  2186. stat = status->hit;
  2187. stat += level + status->dex + (bl->type == BL_PC ? status->luk / 3 + 175 : 150); //base level + ( every 1 dex = +1 hit ) + (every 3 luk = +1 hit) + 175
  2188. stat += 2 * status->con;
  2189. status->hit = cap_value(stat, 1, SHRT_MAX);
  2190. // Flee
  2191. stat = status->flee;
  2192. stat += level + status->agi + (bl->type == BL_MER ? 0 : bl->type == BL_PC ? status->luk / 5 : 0) + 100; //base level + ( every 1 agi = +1 flee ) + (every 5 luk = +1 flee) + 100
  2193. stat += 2 * status->con;
  2194. status->flee = cap_value(stat, 1, SHRT_MAX);
  2195. // Def2
  2196. if (bl->type == BL_MER)
  2197. stat = (int32)(status->vit + ((float)level / 10) + ((float)status->vit / 5));
  2198. else {
  2199. stat = status->def2;
  2200. stat += (int32)(((float)level + status->vit) / 2 + (bl->type == BL_PC ? ((float)status->agi / 5) : 0)); //base level + (every 2 vit = +1 def) + (every 5 agi = +1 def)
  2201. }
  2202. status->def2 = cap_value(stat, 0, SHRT_MAX);
  2203. // Mdef2
  2204. if (bl->type == BL_MER)
  2205. stat = (int32)(((float)level / 10) + ((float)status->int_ / 5));
  2206. else {
  2207. stat = status->mdef2;
  2208. stat += (int32)(bl->type == BL_PC ? (status->int_ + ((float)level / 4) + ((float)(status->dex + status->vit) / 5)) : ((float)(status->int_ + level) / 4)); //(every 4 base level = +1 mdef) + (every 1 int32 = +1 mdef) + (every 5 dex = +1 mdef) + (every 5 vit = +1 mdef)
  2209. }
  2210. status->mdef2 = cap_value(stat, 0, SHRT_MAX);
  2211. // PAtk
  2212. stat = status->patk;
  2213. stat += status->pow / 3 + status->con / 5;
  2214. status->patk = cap_value(stat, 0, SHRT_MAX);
  2215. // SMatk
  2216. stat = status->smatk;
  2217. stat += status->spl / 3 + status->con / 5;
  2218. status->smatk = cap_value(stat, 0, SHRT_MAX);
  2219. // Res
  2220. stat = status->res;
  2221. stat += status->sta + status->sta / 3 * 5;
  2222. status->res = cap_value(stat, 0, SHRT_MAX);
  2223. // Mres
  2224. stat = status->mres;
  2225. stat += status->wis + status->wis / 3 * 5;
  2226. status->mres = cap_value(stat, 0, SHRT_MAX);
  2227. // HPlus
  2228. stat = status->hplus;
  2229. stat += status->crt;
  2230. status->hplus = cap_value(stat, 0, SHRT_MAX);
  2231. // CRate
  2232. stat = status->crate;
  2233. stat += status->crt / 3;
  2234. status->crate = cap_value(stat, 0, SHRT_MAX);
  2235. }
  2236. // ATK
  2237. if (bl->type != BL_PC) {
  2238. status->rhw.atk2 = status_base_atk_max(bl, status, level);
  2239. status->rhw.atk = status_base_atk_min(bl, status, level);
  2240. }
  2241. // MAtk
  2242. status->matk_min = status_base_matk_min(bl, status, level);
  2243. status->matk_max = status_base_matk_max(bl, status, level);
  2244. #else
  2245. // Matk
  2246. status->matk_min = status_base_matk_min(status);
  2247. status->matk_max = status_base_matk_max(status);
  2248. // Hit
  2249. stat = status->hit;
  2250. stat += level + status->dex;
  2251. status->hit = cap_value(stat, 1, SHRT_MAX);
  2252. // Flee
  2253. stat = status->flee;
  2254. stat += level + status->agi;
  2255. status->flee = cap_value(stat, 1, SHRT_MAX);
  2256. // Def2
  2257. stat = status->def2;
  2258. stat += status->vit;
  2259. status->def2 = cap_value(stat, 0, SHRT_MAX);
  2260. // Mdef2
  2261. stat = status->mdef2;
  2262. stat += status->int_ + (status->vit / 2);
  2263. status->mdef2 = cap_value(stat, 0, SHRT_MAX);
  2264. #endif
  2265. //Critical
  2266. if( bl->type&battle_config.enable_critical ) {
  2267. stat = status->cri;
  2268. #ifdef RENEWAL
  2269. stat += (level / 10); // (every 10 BaseLevel = +0.1 critical)
  2270. stat += 10 + (status->luk*3); // (every 1 luk = +0.3 critical)
  2271. #else
  2272. stat += 10 + (status->luk*10/3); // (every 1 luk = +0.3 critical)
  2273. #endif
  2274. status->cri = cap_value(stat, 1, SHRT_MAX);
  2275. } else
  2276. status->cri = 0;
  2277. if (bl->type&battle_config.enable_perfect_flee) {
  2278. stat = status->flee2;
  2279. stat += status->luk + 10; // (every 10 luk = +1 perfect flee)
  2280. status->flee2 = cap_value(stat, 0, SHRT_MAX);
  2281. } else
  2282. status->flee2 = 0;
  2283. if (status->batk) {
  2284. int32 temp = status->batk + status_base_atk(bl, status, level);
  2285. status->batk = cap_value(temp, 0, USHRT_MAX);
  2286. } else
  2287. status->batk = status_base_atk(bl, status, level);
  2288. if (status->cri) {
  2289. switch (bl->type) {
  2290. case BL_MOB:
  2291. if(battle_config.mob_critical_rate != 100)
  2292. status->cri = cap_value(status->cri*battle_config.mob_critical_rate/100,1,SHRT_MAX);
  2293. if(!status->cri && battle_config.mob_critical_rate)
  2294. status->cri = 10;
  2295. break;
  2296. case BL_PC:
  2297. // Players don't have a critical adjustment setting as of yet.
  2298. break;
  2299. default:
  2300. if(battle_config.critical_rate != 100)
  2301. status->cri = cap_value(status->cri*battle_config.critical_rate/100,1,SHRT_MAX);
  2302. if (!status->cri && battle_config.critical_rate)
  2303. status->cri = 10;
  2304. }
  2305. }
  2306. if(bl->type&BL_REGEN)
  2307. status_calc_regen(bl, status, status_get_regen_data(bl));
  2308. }
  2309. /**
  2310. * Calculates the initial status for the given mob
  2311. * @param md: Mob object
  2312. * @param opt: Whether or not it is the first calculation
  2313. This will only be false when a mob levels up (Regular and WoE Guardians)
  2314. * @return 1 for calculated special statuses or 0 for none
  2315. * @author [Skotlex]
  2316. */
  2317. int32 status_calc_mob_(struct mob_data* md, uint8 opt)
  2318. {
  2319. struct status_data *status;
  2320. struct block_list *mbl = nullptr;
  2321. int32 flag=0;
  2322. if (opt&SCO_FIRST) { // Set basic level on respawn.
  2323. if (md->level > 0 && md->level <= MAX_LEVEL && md->level != md->db->lv)
  2324. ;
  2325. else
  2326. md->level = md->db->lv;
  2327. md->damagetaken = md->db->damagetaken;
  2328. }
  2329. // Check if we need custom base-status
  2330. if (battle_config.mobs_level_up && md->level > md->db->lv)
  2331. flag|=1;
  2332. if (md->special_state.size)
  2333. flag|=2;
  2334. if (md->guardian_data && md->guardian_data->guardup_lv)
  2335. flag|=4;
  2336. if (md->mob_id == MOBID_EMPERIUM)
  2337. flag|=4;
  2338. if (battle_config.slaves_inherit_speed && md->master_id)
  2339. flag|=8;
  2340. if (md->master_id && md->special_state.ai>AI_ATTACK)
  2341. flag|=16;
  2342. if (md->master_id && battle_config.slaves_inherit_mode)
  2343. flag |= 32;
  2344. if (!flag) { // No special status required.
  2345. if (md->base_status) {
  2346. aFree(md->base_status);
  2347. md->base_status = nullptr;
  2348. }
  2349. if (opt&SCO_FIRST)
  2350. memcpy(&md->status, &md->db->status, sizeof(struct status_data));
  2351. return 0;
  2352. }
  2353. if (!md->base_status)
  2354. md->base_status = (struct status_data*)aCalloc(1, sizeof(struct status_data));
  2355. status = md->base_status;
  2356. memcpy(status, &md->db->status, sizeof(struct status_data));
  2357. if (flag&(8|16))
  2358. mbl = map_id2bl(md->master_id);
  2359. if (flag&8 && mbl) {
  2360. struct status_data *mstatus = status_get_base_status(mbl);
  2361. if (mstatus &&
  2362. battle_config.slaves_inherit_speed&(status_has_mode(mstatus,MD_CANMOVE)?1:2))
  2363. status->speed = mstatus->speed;
  2364. if( status->speed < 2 ) // Minimum for the unit to function properly
  2365. status->speed = 2;
  2366. }
  2367. if (flag&32)
  2368. status_calc_slave_mode(*md);
  2369. if (flag&1) { // Increase from mobs leveling up [Valaris]
  2370. int32 diff = md->level - md->db->lv;
  2371. status->str += diff;
  2372. status->agi += diff;
  2373. status->vit += diff;
  2374. status->int_ += diff;
  2375. status->dex += diff;
  2376. status->luk += diff;
  2377. status->max_hp += diff * status->vit;
  2378. status->max_sp += diff * status->int_;
  2379. status->hp = status->max_hp;
  2380. status->sp = status->max_sp;
  2381. status->speed -= cap_value(diff, 0, status->speed - 10);
  2382. }
  2383. if (flag&2 && battle_config.mob_size_influence) { // Change for sized monsters [Valaris]
  2384. if (md->special_state.size == SZ_MEDIUM) {
  2385. status->max_hp /= 2;
  2386. status->max_sp /= 2;
  2387. if (!status->max_hp) status->max_hp = 1;
  2388. if (!status->max_sp) status->max_sp = 1;
  2389. status->hp = status->max_hp;
  2390. status->sp = status->max_sp;
  2391. status->str /= 2;
  2392. status->agi /= 2;
  2393. status->vit /= 2;
  2394. status->int_ /= 2;
  2395. status->dex /= 2;
  2396. status->luk /= 2;
  2397. if (!status->str) status->str = 1;
  2398. if (!status->agi) status->agi = 1;
  2399. if (!status->vit) status->vit = 1;
  2400. if (!status->int_) status->int_ = 1;
  2401. if (!status->dex) status->dex = 1;
  2402. if (!status->luk) status->luk = 1;
  2403. } else if (md->special_state.size == SZ_BIG) {
  2404. status->max_hp *= 2;
  2405. status->max_sp *= 2;
  2406. status->hp = status->max_hp;
  2407. status->sp = status->max_sp;
  2408. status->str *= 2;
  2409. status->agi *= 2;
  2410. status->vit *= 2;
  2411. status->int_ *= 2;
  2412. status->dex *= 2;
  2413. status->luk *= 2;
  2414. }
  2415. }
  2416. status_calc_misc(&md->bl, status, md->level);
  2417. if(flag&4) { // Strengthen Guardians - custom value +10% / lv
  2418. struct map_data *mapdata = map_getmapdata(md->bl.m);
  2419. std::shared_ptr<guild_castle> gc = castle_db.mapname2gc(mapdata->name);
  2420. if (gc == nullptr)
  2421. ShowError("status_calc_mob: No castle set at map %s\n", mapdata->name);
  2422. else if(gc->castle_id < 24 || md->mob_id == MOBID_EMPERIUM) {
  2423. #ifdef RENEWAL
  2424. status->max_hp += 50 * (gc->defense / 5);
  2425. #else
  2426. status->max_hp += 1000 * gc->defense;
  2427. #endif
  2428. status->hp = status->max_hp;
  2429. status->def += (gc->defense+2)/3;
  2430. status->mdef += (gc->defense+2)/3;
  2431. }
  2432. if(md->mob_id != MOBID_EMPERIUM) {
  2433. status->max_hp += 1000 * gc->defense;
  2434. status->hp = status->max_hp;
  2435. status->batk += 2 * md->guardian_data->guardup_lv + 8;
  2436. status->rhw.atk += 2 * md->guardian_data->guardup_lv + 8;
  2437. status->rhw.atk2 += 2 * md->guardian_data->guardup_lv + 8;
  2438. status->aspd_rate -= 2 * md->guardian_data->guardup_lv + 3;
  2439. }
  2440. }
  2441. if (flag&16 && mbl) { // Max HP setting from Summon Flora/marine Sphere
  2442. struct unit_data *ud = unit_bl2ud(mbl);
  2443. // Remove special AI when this is used by regular mobs.
  2444. if (mbl->type == BL_MOB && !((TBL_MOB*)mbl)->special_state.ai)
  2445. md->special_state.ai = AI_NONE;
  2446. if (ud) {
  2447. // Different levels of HP according to skill level
  2448. if(!ud->skill_id) // !FIXME: We lost the unit data for magic decoy in somewhere before this
  2449. ud->skill_id = ((TBL_PC*)mbl)->menuskill_id;
  2450. switch(ud->skill_id) {
  2451. case AM_SPHEREMINE:
  2452. status->max_hp = 2000 + 400*ud->skill_lv;
  2453. break;
  2454. case KO_ZANZOU:
  2455. status->max_hp = 3000 + 3000 * ud->skill_lv;
  2456. break;
  2457. case AM_CANNIBALIZE:
  2458. status->max_hp = 1500 + 200*ud->skill_lv + 10*status_get_lv(mbl);
  2459. status->mode = static_cast<e_mode>(status->mode|MD_CANATTACK|MD_AGGRESSIVE);
  2460. break;
  2461. case MH_SUMMON_LEGION:
  2462. {
  2463. int32 homblvl = status_get_lv(mbl);
  2464. status->max_hp = 10 * (100 * (ud->skill_lv + 2) + homblvl);
  2465. status->batk = 100 * (ud->skill_lv+5) / 2;
  2466. status->def = 10 * (100 * (ud->skill_lv+2) + homblvl);
  2467. // status->aspd_rate = 10 * (2 * (20 - ud->skill_lv) - homblvl/10);
  2468. // status->aspd_rate = max(100,status->aspd_rate);
  2469. break;
  2470. }
  2471. case NC_SILVERSNIPER:
  2472. {
  2473. status_data* mstatus = status_get_status_data(*mbl);
  2474. // TODO: check if dummy_status? Can never be nullptr [Lemongrass]
  2475. if(!mstatus)
  2476. break;
  2477. status->max_hp = (1000 * ud->skill_lv) + (mstatus->hp / 3) + (status_get_lv(mbl) * 12);
  2478. status->batk = 200 * ud->skill_lv;
  2479. break;
  2480. }
  2481. case NC_MAGICDECOY:
  2482. {
  2483. status_data* mstatus = status_get_status_data(*mbl);
  2484. // TODO: check if dummy_status? Can never be nullptr [Lemongrass]
  2485. if(!mstatus)
  2486. break;
  2487. status->max_hp = (1000 * ((TBL_PC*)mbl)->menuskill_val) + (mstatus->sp * 4) + (status_get_lv(mbl) * 12);
  2488. status->matk_min = status->matk_max = 250 + 50*((TBL_PC*)mbl)->menuskill_val;
  2489. break;
  2490. }
  2491. case MT_SUMMON_ABR_BATTLE_WARIOR:
  2492. case MT_SUMMON_ABR_DUAL_CANNON:
  2493. case MT_SUMMON_ABR_MOTHER_NET:
  2494. case MT_SUMMON_ABR_INFINITY: {
  2495. map_session_data *msd = BL_CAST(BL_PC, mbl);
  2496. status_data* mstatus = status_get_status_data(*mbl);
  2497. // TODO: check if mstatus is dummy_status? Can never be nullptr [Lemongrass]
  2498. if (msd == nullptr || mstatus == nullptr)
  2499. break;
  2500. uint8 abr_mastery = pc_checkskill(msd, MT_ABR_M);
  2501. // Custom formulas for ABR's.
  2502. // Its unknown how the summoner's stats affects the ABR's stats.
  2503. // I decided to do something similar to elementals for now until I know.
  2504. // Also added hit increase from ABR-Mastery for balance reasons. [Rytech]
  2505. status->max_hp = ( 5000 + 40000 * abr_mastery ) * mstatus->vit / 100;
  2506. status->rhw.atk = ( 2 * mstatus->batk + 200 + 600 * abr_mastery ) * 70 / 100;
  2507. status->rhw.atk2 = 2 * mstatus->batk + 200 + 600 * abr_mastery;
  2508. status->def = mstatus->def + 20 * abr_mastery;
  2509. status->mdef = mstatus->mdef + 4 * abr_mastery;
  2510. status->hit = mstatus->hit + 5 * abr_mastery / 2;
  2511. status->flee = mstatus->flee + 10 * abr_mastery;
  2512. status->speed = mstatus->speed;
  2513. // The Infinity ABR appears to have a much higher attack then other
  2514. // ABR's and im guessing has a much higher MaxHP due to it being a AP
  2515. // costing summon. [Rytech]
  2516. if (ud->skill_id == MT_SUMMON_ABR_INFINITY) {
  2517. status->max_hp += 20000;
  2518. status->rhw.atk += 1400; // 70% of 2000
  2519. status->rhw.atk2 += 2000;
  2520. }
  2521. }
  2522. break;
  2523. case BO_WOODENWARRIOR:
  2524. case BO_WOODEN_FAIRY:
  2525. case BO_CREEPER:
  2526. case BO_HELLTREE: {
  2527. map_session_data *msd = BL_CAST(BL_PC, mbl);
  2528. status_data* mstatus = status_get_status_data(*mbl);
  2529. // TODO: check if mstatus is dummy_status? Can never be nullptr [Lemongrass]
  2530. if (msd == nullptr || mstatus == nullptr)
  2531. break;
  2532. uint8 bionic_mastery = pc_checkskill(msd, BO_BIONICS_M);
  2533. // Custom formulas for bionic's.
  2534. // Its unknown how the summoner's stats affects the bionic's stats.
  2535. // I decided to do something similar to elementals for now until I know.
  2536. // Also added hit increase from Bionic-Mastery for balance reasons. [Rytech]
  2537. status->max_hp = (5000 + 40000 * bionic_mastery) * mstatus->vit / 100;
  2538. //status->max_sp = (50 + 20 * bionic_mastery) * mstatus->int_ / 100;// Wait what??? Bionic Mastery increases MaxSP? They have SP???
  2539. status->rhw.atk = (2 * mstatus->batk + 600 * bionic_mastery) * 70 / 100;
  2540. status->rhw.atk2 = 2 * mstatus->batk + 600 * bionic_mastery;
  2541. status->def = mstatus->def + 20 * bionic_mastery;
  2542. status->mdef = mstatus->mdef + 4 * bionic_mastery;
  2543. status->hit = mstatus->hit + 5 * bionic_mastery / 2;
  2544. status->flee = mstatus->flee + 10 * bionic_mastery;
  2545. status->speed = mstatus->speed;
  2546. // The Hell Tree bionic appears to have a much higher attack then other
  2547. // bionic's and im guessing has a much higher MaxHP due to it being a AP
  2548. // costing summon. [Rytech]
  2549. if (ud->skill_id == BO_HELLTREE) {
  2550. status->max_hp += 20000;
  2551. status->rhw.atk += 1400; // 70% of 2000
  2552. status->rhw.atk2 += 2000;
  2553. }
  2554. }
  2555. break;
  2556. }
  2557. status->hp = status->max_hp;
  2558. }
  2559. }
  2560. if (opt&SCO_FIRST) // Initial battle status
  2561. memcpy(&md->status, status, sizeof(struct status_data));
  2562. return 1;
  2563. }
  2564. /**
  2565. * Calculates the stats of the given pet
  2566. * @param pd: Pet object
  2567. * @param opt: Whether or not it is the first calculation
  2568. This will only be false when a pet levels up
  2569. * @return 1
  2570. * @author [Skotlex]
  2571. */
  2572. void status_calc_pet_(struct pet_data *pd, uint8 opt)
  2573. {
  2574. nullpo_retv(pd);
  2575. if (opt&SCO_FIRST) {
  2576. memcpy(&pd->status, &pd->db->status, sizeof(struct status_data));
  2577. pd->status.mode = MD_CANMOVE; // Pets discard all modes, except walking
  2578. pd->status.class_ = CLASS_NORMAL;
  2579. pd->status.speed = pd->get_pet_walk_speed();
  2580. if(battle_config.pet_attack_support || battle_config.pet_damage_support) {
  2581. // Attack support requires the pet to be able to attack
  2582. pd->status.mode = static_cast<e_mode>(pd->status.mode|MD_CANATTACK);
  2583. }
  2584. }
  2585. if (battle_config.pet_lv_rate && pd->master) {
  2586. map_session_data *sd = pd->master;
  2587. int32 lv;
  2588. lv =sd->status.base_level*battle_config.pet_lv_rate/100;
  2589. if (lv < 0)
  2590. lv = 1;
  2591. if (lv != pd->pet.level || opt&SCO_FIRST) {
  2592. struct status_data *bstat = &pd->db->status, *status = &pd->status;
  2593. pd->pet.level = lv;
  2594. if (!(opt&SCO_FIRST)) // Lv Up animation
  2595. clif_misceffect( pd->bl, NOTIFYEFFECT_BASE_LEVEL_UP );
  2596. status->rhw.atk = (bstat->rhw.atk*lv)/pd->db->lv;
  2597. status->rhw.atk2 = (bstat->rhw.atk2*lv)/pd->db->lv;
  2598. status->str = (bstat->str*lv)/pd->db->lv;
  2599. status->agi = (bstat->agi*lv)/pd->db->lv;
  2600. status->vit = (bstat->vit*lv)/pd->db->lv;
  2601. status->int_ = (bstat->int_*lv)/pd->db->lv;
  2602. status->dex = (bstat->dex*lv)/pd->db->lv;
  2603. status->luk = (bstat->luk*lv)/pd->db->lv;
  2604. status->rhw.atk = cap_value(status->rhw.atk, 1, battle_config.pet_max_atk1);
  2605. status->rhw.atk2 = cap_value(status->rhw.atk2, 2, battle_config.pet_max_atk2);
  2606. status->str = cap_value(status->str,1,battle_config.pet_max_stats);
  2607. status->agi = cap_value(status->agi,1,battle_config.pet_max_stats);
  2608. status->vit = cap_value(status->vit,1,battle_config.pet_max_stats);
  2609. status->int_= cap_value(status->int_,1,battle_config.pet_max_stats);
  2610. status->dex = cap_value(status->dex,1,battle_config.pet_max_stats);
  2611. status->luk = cap_value(status->luk,1,battle_config.pet_max_stats);
  2612. status_calc_misc(&pd->bl, &pd->status, lv);
  2613. if (!(opt&SCO_FIRST)) // Not done the first time because the pet is not visible yet
  2614. clif_send_petstatus( *sd, *pd );
  2615. }
  2616. } else if (opt&SCO_FIRST) {
  2617. status_calc_misc(&pd->bl, &pd->status, pd->db->lv);
  2618. if (!battle_config.pet_lv_rate && pd->pet.level != pd->db->lv)
  2619. pd->pet.level = pd->db->lv;
  2620. }
  2621. // Support rate modifier (1000 = 100%)
  2622. pd->rate_fix = min(1000 * (pd->pet.intimate - battle_config.pet_support_min_friendly) / (1000 - battle_config.pet_support_min_friendly) + 500, USHRT_MAX);
  2623. pd->rate_fix = min(apply_rate(pd->rate_fix, battle_config.pet_support_rate), USHRT_MAX);
  2624. }
  2625. /**
  2626. * Get HP bonus modifiers
  2627. * @param bl: block_list that will be checked
  2628. * @param type: type of e_status_bonus (STATUS_BONUS_FIX or STATUS_BONUS_RATE)
  2629. * @return bonus: total bonus for HP
  2630. * @author [Cydh]
  2631. */
  2632. static int32 status_get_hpbonus(struct block_list *bl, enum e_status_bonus type) {
  2633. int32 bonus = 0;
  2634. if (type == STATUS_BONUS_FIX) {
  2635. status_change *sc = status_get_sc(bl);
  2636. //Only for BL_PC
  2637. if (bl->type == BL_PC) {
  2638. map_session_data *sd = map_id2sd(bl->id);
  2639. uint16 skill_lv;
  2640. bonus += sd->bonus.hp;
  2641. if ((skill_lv = pc_checkskill(sd,CR_TRUST)) > 0)
  2642. bonus += skill_lv * 200;
  2643. if (pc_checkskill(sd,SU_SPRITEMABLE) > 0)
  2644. bonus += 1000;
  2645. if (pc_checkskill(sd, SU_POWEROFSEA) > 0) {
  2646. bonus += 1000;
  2647. if (pc_checkskill_summoner(sd, SUMMONER_POWER_SEA) >= 20)
  2648. bonus += 3000;
  2649. }
  2650. if ((skill_lv = pc_checkskill(sd, NV_BREAKTHROUGH)) > 0)
  2651. bonus += 350 * skill_lv + (skill_lv > 4 ? 250 : 0);
  2652. if ((skill_lv = pc_checkskill(sd, NV_TRANSCENDENCE)) > 0)
  2653. bonus += 350 * skill_lv + (skill_lv > 4 ? 250 : 0);
  2654. #ifndef HP_SP_TABLES
  2655. if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.base_level >= 99)
  2656. bonus += 2000; // Supernovice lvl99 hp bonus.
  2657. if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.base_level >= 150)
  2658. bonus += 2000; // Supernovice lvl150 hp bonus.
  2659. #endif
  2660. }
  2661. //Bonus by SC
  2662. // !CHECKME: status_get_hpbonus shouldn't be used for SC from usable items
  2663. if (sc) {
  2664. if(sc->getSCE(SC_INCMHP))
  2665. bonus += sc->getSCE(SC_INCMHP)->val1;
  2666. if(sc->getSCE(SC_EARTH_INSIGNIA) && sc->getSCE(SC_EARTH_INSIGNIA)->val1 == 2)
  2667. bonus += 500;
  2668. if (sc->getSCE(SC_PROMOTE_HEALTH_RESERCH))
  2669. bonus += sc->getSCE(SC_PROMOTE_HEALTH_RESERCH)->val3;
  2670. if(sc->getSCE(SC_SOLID_SKIN_OPTION))
  2671. bonus += 2000;
  2672. if(sc->getSCE(SC_MARIONETTE))
  2673. bonus -= 1000;
  2674. if(sc->getSCE(SC_SWORDCLAN))
  2675. bonus += 30;
  2676. if(sc->getSCE(SC_ARCWANDCLAN))
  2677. bonus += 30;
  2678. if(sc->getSCE(SC_GOLDENMACECLAN))
  2679. bonus += 30;
  2680. if(sc->getSCE(SC_CROSSBOWCLAN))
  2681. bonus += 30;
  2682. #ifdef RENEWAL
  2683. if (sc->getSCE(SC_ANGELUS))
  2684. bonus += sc->getSCE(SC_ANGELUS)->val1 * 50;
  2685. #endif
  2686. }
  2687. } else if (type == STATUS_BONUS_RATE) {
  2688. status_change *sc = status_get_sc(bl);
  2689. //Bonus by SC
  2690. // !CHECKME: status_get_hpbonus shouldn't be used for SC from usable items
  2691. if (sc) {
  2692. //Increasing
  2693. if(sc->getSCE(SC_INCMHPRATE))
  2694. bonus += sc->getSCE(SC_INCMHPRATE)->val1;
  2695. if(sc->getSCE(SC_APPLEIDUN))
  2696. bonus += sc->getSCE(SC_APPLEIDUN)->val2;
  2697. if(sc->getSCE(SC_DELUGE))
  2698. bonus += sc->getSCE(SC_DELUGE)->val2;
  2699. if(sc->getSCE(SC_BERSERK))
  2700. bonus += 200; //+200%
  2701. if(sc->getSCE(SC_MERC_HPUP))
  2702. bonus += sc->getSCE(SC_MERC_HPUP)->val2;
  2703. if(sc->getSCE(SC_EPICLESIS))
  2704. bonus += sc->getSCE(SC_EPICLESIS)->val2;
  2705. if(sc->getSCE(SC_FRIGG_SONG))
  2706. bonus += sc->getSCE(SC_FRIGG_SONG)->val2;
  2707. if(sc->getSCE(SC_LERADSDEW))
  2708. bonus += sc->getSCE(SC_LERADSDEW)->val3;
  2709. if(sc->getSCE(SC_FORCEOFVANGUARD))
  2710. bonus += (3 * sc->getSCE(SC_FORCEOFVANGUARD)->val1);
  2711. if(sc->getSCE(SC_INSPIRATION))
  2712. bonus += (4 * sc->getSCE(SC_INSPIRATION)->val1);
  2713. if(sc->getSCE(SC_RAISINGDRAGON))
  2714. bonus += sc->getSCE(SC_RAISINGDRAGON)->val1;
  2715. if(sc->getSCE(SC_GT_REVITALIZE))
  2716. bonus += sc->getSCE(SC_GT_REVITALIZE)->val2;
  2717. if(sc->getSCE(SC_ANGRIFFS_MODUS))
  2718. bonus += (5 * sc->getSCE(SC_ANGRIFFS_MODUS)->val1);
  2719. if(sc->getSCE(SC_PETROLOGY_OPTION))
  2720. bonus += sc->getSCE(SC_PETROLOGY_OPTION)->val2;
  2721. if(sc->getSCE(SC_POWER_OF_GAIA))
  2722. bonus += sc->getSCE(SC_POWER_OF_GAIA)->val3;
  2723. if(sc->getSCE(SC_CURSED_SOIL_OPTION))
  2724. bonus += sc->getSCE(SC_CURSED_SOIL_OPTION)->val2;
  2725. if(sc->getSCE(SC_UPHEAVAL_OPTION))
  2726. bonus += sc->getSCE(SC_UPHEAVAL_OPTION)->val2;
  2727. if(sc->getSCE(SC_LAUDAAGNUS))
  2728. bonus += 2 + (sc->getSCE(SC_LAUDAAGNUS)->val1 * 2);
  2729. #ifdef RENEWAL
  2730. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_HPRATE)
  2731. bonus += 30;
  2732. #endif
  2733. if(sc->getSCE(SC_LUNARSTANCE))
  2734. bonus += sc->getSCE(SC_LUNARSTANCE)->val2;
  2735. if (sc->getSCE(SC_LUXANIMA))
  2736. bonus += sc->getSCE(SC_LUXANIMA)->val3;
  2737. if (sc->getSCE(SC_FIRM_FAITH))
  2738. bonus += sc->getSCE(SC_FIRM_FAITH)->val2;
  2739. //Decreasing
  2740. if (sc->getSCE(SC_VENOMBLEED) && sc->getSCE(SC_VENOMBLEED)->val3 == 1)
  2741. bonus -= 15;
  2742. if(sc->getSCE(SC_BEYONDOFWARCRY))
  2743. bonus -= sc->getSCE(SC_BEYONDOFWARCRY)->val3;
  2744. if(sc->getSCE(SC__WEAKNESS))
  2745. bonus -= sc->getSCE(SC__WEAKNESS)->val2;
  2746. if(sc->getSCE(SC_EQC))
  2747. bonus -= sc->getSCE(SC_EQC)->val3;
  2748. }
  2749. // Max rate reduce is -100%
  2750. bonus = cap_value(bonus,-100,INT_MAX);
  2751. }
  2752. return min(bonus,INT_MAX);
  2753. }
  2754. /**
  2755. * HP bonus rate from equipment
  2756. */
  2757. static int32 status_get_hpbonus_equip(TBL_PC *sd) {
  2758. int32 bonus = 0;
  2759. bonus += sd->hprate;
  2760. return bonus -= 100; //Default hprate is 100, so it should be add 0%
  2761. }
  2762. /**
  2763. * HP bonus rate from usable items
  2764. */
  2765. static int32 status_get_hpbonus_item(block_list *bl) {
  2766. int32 bonus = 0;
  2767. // status_change *sc = status_get_sc(bl);
  2768. //Bonus by SC
  2769. // if (sc) {
  2770. // }
  2771. // Max rate reduce is -100%
  2772. return cap_value(bonus, -100, INT_MAX);
  2773. }
  2774. /**
  2775. * Get SP bonus modifiers
  2776. * @param bl: block_list that will be checked
  2777. * @param type: type of e_status_bonus (STATUS_BONUS_FIX or STATUS_BONUS_RATE)
  2778. * @return bonus: total bonus for SP
  2779. * @author [Cydh]
  2780. */
  2781. static int32 status_get_spbonus(struct block_list *bl, enum e_status_bonus type) {
  2782. int32 bonus = 0;
  2783. if (type == STATUS_BONUS_FIX) {
  2784. status_change *sc = status_get_sc(bl);
  2785. //Only for BL_PC
  2786. if (bl->type == BL_PC) {
  2787. map_session_data *sd = map_id2sd(bl->id);
  2788. uint16 skill_lv;
  2789. bonus += sd->bonus.sp;
  2790. if ((skill_lv = pc_checkskill(sd,SL_KAINA)) > 0)
  2791. bonus += 30 * skill_lv;
  2792. if ((skill_lv = pc_checkskill(sd,RA_RESEARCHTRAP)) > 0)
  2793. bonus += 200 + 20 * skill_lv;
  2794. if ((skill_lv = pc_checkskill(sd,WM_LESSON)) > 0)
  2795. bonus += 30 * skill_lv;
  2796. if (pc_checkskill(sd,SU_SPRITEMABLE) > 0)
  2797. bonus += 100;
  2798. if (pc_checkskill(sd, SU_POWEROFSEA) > 0) {
  2799. bonus += 100;
  2800. if (pc_checkskill_summoner(sd, SUMMONER_POWER_SEA) >= 20)
  2801. bonus += 300;
  2802. }
  2803. if ((skill_lv = pc_checkskill(sd, NV_BREAKTHROUGH)) > 0)
  2804. bonus += 30 * skill_lv + (skill_lv > 4 ? 50 : 0);
  2805. if ((skill_lv = pc_checkskill(sd, NV_TRANSCENDENCE)) > 0)
  2806. bonus += 30 * skill_lv + (skill_lv > 4 ? 50 : 0);
  2807. }
  2808. //Bonus by SC
  2809. // !CHECKME: status_get_spbonus shouldn't be used for SC from usable items
  2810. if (sc) {
  2811. if(sc->getSCE(SC_INCMSP))
  2812. bonus += sc->getSCE(SC_INCMSP)->val1;
  2813. if(sc->getSCE(SC_EARTH_INSIGNIA) && sc->getSCE(SC_EARTH_INSIGNIA)->val1 == 3)
  2814. bonus += 50;
  2815. if(sc->getSCE(SC_SWORDCLAN))
  2816. bonus += 10;
  2817. if(sc->getSCE(SC_ARCWANDCLAN))
  2818. bonus += 10;
  2819. if(sc->getSCE(SC_GOLDENMACECLAN))
  2820. bonus += 10;
  2821. if(sc->getSCE(SC_CROSSBOWCLAN))
  2822. bonus += 10;
  2823. }
  2824. } else if (type == STATUS_BONUS_RATE) {
  2825. status_change *sc = status_get_sc(bl);
  2826. //Only for BL_PC
  2827. if (bl->type == BL_PC) {
  2828. map_session_data *sd = map_id2sd(bl->id);
  2829. uint8 i;
  2830. if((i = pc_checkskill(sd,HP_MEDITATIO)) > 0)
  2831. bonus += i;
  2832. if((i = pc_checkskill(sd,HW_SOULDRAIN)) > 0)
  2833. bonus += 2 * i;
  2834. #ifdef RENEWAL
  2835. if ((i = pc_checkskill(sd, (sd->status.sex ? BA_MUSICALLESSON : DC_DANCINGLESSON))) > 0)
  2836. bonus += i;
  2837. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_SPRATE)
  2838. bonus += 30;
  2839. #endif
  2840. }
  2841. //Bonus by SC
  2842. // !CHECKME: status_get_spbonus shouldn't be used for SC from usable items
  2843. if (sc) {
  2844. //Increasing
  2845. if(sc->getSCE(SC_INCMSPRATE))
  2846. bonus += sc->getSCE(SC_INCMSPRATE)->val1;
  2847. if(sc->getSCE(SC_RAISINGDRAGON))
  2848. bonus += sc->getSCE(SC_RAISINGDRAGON)->val1;
  2849. if(sc->getSCE(SC_SERVICE4U))
  2850. bonus += sc->getSCE(SC_SERVICE4U)->val2;
  2851. if(sc->getSCE(SC_MERC_SPUP))
  2852. bonus += sc->getSCE(SC_MERC_SPUP)->val2;
  2853. if (sc->getSCE(SC_LUXANIMA))
  2854. bonus += sc->getSCE(SC_LUXANIMA)->val3;
  2855. //Decreasing
  2856. if (sc->getSCE(SC_MELODYOFSINK))
  2857. bonus -= sc->getSCE(SC_MELODYOFSINK)->val3;
  2858. }
  2859. // Max rate reduce is -100%
  2860. bonus = cap_value(bonus,-100,INT_MAX);
  2861. }
  2862. return min(bonus,INT_MAX);
  2863. }
  2864. /**
  2865. * SP bonus rate from equipment
  2866. */
  2867. static int32 status_get_spbonus_equip(TBL_PC *sd) {
  2868. int32 bonus = 0;
  2869. bonus += sd->sprate;
  2870. return bonus -= 100; //Default sprate is 100, so it should be add 0%
  2871. }
  2872. /**
  2873. * SP bonus rate from usable items
  2874. */
  2875. static int32 status_get_spbonus_item(block_list *bl) {
  2876. int32 bonus = 0;
  2877. status_change *sc = status_get_sc(bl);
  2878. //Bonus by SC
  2879. if (sc) {
  2880. if (sc->getSCE(SC_ENERGY_DRINK_RESERCH))
  2881. bonus += sc->getSCE(SC_ENERGY_DRINK_RESERCH)->val3;
  2882. }
  2883. // Max rate reduce is -100%
  2884. return cap_value(bonus, -100, INT_MAX);
  2885. }
  2886. /**
  2887. * Get AP bonus modifiers
  2888. * @param bl: block_list that will be checked
  2889. * @param type: type of e_status_bonus (STATUS_BONUS_FIX or STATUS_BONUS_RATE)
  2890. * @return bonus: total bonus for AP
  2891. */
  2892. static int32 status_get_apbonus(struct block_list *bl, enum e_status_bonus type) {
  2893. int32 bonus = 0;
  2894. if (type == STATUS_BONUS_FIX) {
  2895. status_change *sc = status_get_sc(bl);
  2896. //Only for BL_PC
  2897. if (bl->type == BL_PC) {
  2898. map_session_data *sd = map_id2sd(bl->id);
  2899. //uint16 skill_lv;
  2900. bonus += sd->bonus.ap;
  2901. //if ((skill_lv = pc_checkskill(sd, NV_BASIC)) > 0)
  2902. // bonus += 100 * skill_lv;
  2903. }
  2904. //Bonus by SC
  2905. if (sc) {
  2906. //if (sc->getSCE(SC_NONE))
  2907. // bonus += sc->getSCE(SC_NONE)->val1;
  2908. }
  2909. } else if (type == STATUS_BONUS_RATE) {
  2910. status_change *sc = status_get_sc(bl);
  2911. //Only for BL_PC
  2912. if (bl->type == BL_PC) {
  2913. map_session_data *sd = map_id2sd(bl->id);
  2914. //uint8 i;
  2915. //if ((i = pc_checkskill(sd, NV_BASIC)) > 0)
  2916. // bonus += 100 * i;
  2917. }
  2918. //Bonus by SC
  2919. if (sc) {
  2920. //if (sc->getSCE(SC_NONE))
  2921. // bonus += sc->getSCE(SC_NONE)->val1;
  2922. }
  2923. // Max rate reduce is -100%
  2924. bonus = cap_value(bonus, -100, INT_MAX);
  2925. }
  2926. return min(bonus, INT_MAX);
  2927. }
  2928. /**
  2929. * AP bonus rate from equipment
  2930. * @param sd: Player data
  2931. * @return AP rate
  2932. */
  2933. static int32 status_get_apbonus_equip(TBL_PC *sd) {
  2934. int32 bonus = 0;
  2935. bonus += sd->aprate;
  2936. return bonus -= 100; //Default aprate is 100, so it should be add 0%
  2937. }
  2938. /**
  2939. * AP bonus rate from usable items
  2940. * @param bl: Object to check against
  2941. * @return AP bonus
  2942. */
  2943. static int32 status_get_apbonus_item(block_list *bl) {
  2944. int32 bonus = 0;
  2945. status_change *sc = status_get_sc(bl);
  2946. //Bonus by SC
  2947. if (sc) {
  2948. //if (sc->getSCE(SC_NONE))
  2949. // bonus += sc->getSCE(SC_NONE)->val1;
  2950. }
  2951. // Max rate reduce is -100%
  2952. return cap_value(bonus, -100, INT_MAX);
  2953. }
  2954. /**
  2955. * Get final MaxHP or MaxSP for player. References: http://irowiki.org/wiki/Max_HP and http://irowiki.org/wiki/Max_SP
  2956. * The calculation needs base_level, base_status/battle_status (vit or int), additive modifier, and multiplicative modifier
  2957. * @param sd Player
  2958. * @param stat Vit/Int of player as param modifier
  2959. * @param isHP true - calculates Max HP, false - calculated Max SP
  2960. * @return max The max value of HP or SP
  2961. */
  2962. static uint32 status_calc_maxhpsp_pc(map_session_data* sd, uint32 stat, bool isHP) {
  2963. nullpo_ret(sd);
  2964. double dmax = 0;
  2965. uint32 level = umax(sd->status.base_level,1);
  2966. std::shared_ptr<s_job_info> job = job_db.find(pc_mapid2jobid(sd->class_, sd->status.sex));
  2967. if (job == nullptr)
  2968. return 1;
  2969. if (isHP) { //Calculates MaxHP
  2970. double equip_bonus = 0, item_bonus = 0;
  2971. dmax = job->base_hp[level-1] * (1 + (umax(stat,1) * 0.01)) * ((sd->class_&JOBL_UPPER)?1.25:(pc_is_taekwon_ranker(sd))?3:1);
  2972. dmax += sd->indexed_bonus.param_equip[PARAM_VIT]; //Vit from equip gives +1 additional HP
  2973. dmax += status_get_hpbonus(&sd->bl,STATUS_BONUS_FIX);
  2974. equip_bonus = (dmax * status_get_hpbonus_equip(sd) / 100);
  2975. item_bonus = (dmax * status_get_hpbonus_item(&sd->bl) / 100); // !FIXME: using bMaxHP* for usable items may cause rounding issue
  2976. dmax += equip_bonus + item_bonus;
  2977. dmax += (int64)(dmax * status_get_hpbonus(&sd->bl,STATUS_BONUS_RATE) / 100); //Aegis accuracy
  2978. }
  2979. else { //Calculates MaxSP
  2980. double equip_bonus = 0, item_bonus = 0;
  2981. dmax = job->base_sp[level-1] * (1 + (umax(stat,1) * 0.01)) * ((sd->class_&JOBL_UPPER)?1.25:(pc_is_taekwon_ranker(sd))?3:1);
  2982. dmax += sd->indexed_bonus.param_equip[PARAM_INT]; //Int from equip gives +1 additional SP
  2983. dmax += status_get_spbonus(&sd->bl,STATUS_BONUS_FIX);
  2984. equip_bonus = (dmax * status_get_spbonus_equip(sd) / 100);
  2985. item_bonus = (dmax * status_get_spbonus_item(&sd->bl) / 100); // !FIXME: using bMaxSP* for usable items may cause rounding issue
  2986. dmax += equip_bonus + item_bonus;
  2987. dmax += (int64)(dmax * status_get_spbonus(&sd->bl,STATUS_BONUS_RATE) / 100); //Aegis accuracy
  2988. }
  2989. //Make sure it's not negative before casting to uint32
  2990. if(dmax < 1) dmax = 1;
  2991. return cap_value((uint32)dmax,1,UINT_MAX);
  2992. }
  2993. /**
  2994. * Get final MaxAP for player.
  2995. * @param sd: Player data
  2996. * @return AP amount
  2997. */
  2998. static uint32 status_calc_maxap_pc(map_session_data* sd) {
  2999. double dmax = 0, equip_bonus = 0, item_bonus = 0;
  3000. nullpo_ret(sd);
  3001. dmax = (sd->class_&JOBL_FOURTH) ? 200 : 0;
  3002. dmax += status_get_apbonus(&sd->bl, STATUS_BONUS_FIX);
  3003. equip_bonus = (dmax * status_get_apbonus_equip(sd) / 100);
  3004. item_bonus = (dmax * status_get_apbonus_item(&sd->bl) / 100);
  3005. dmax += equip_bonus + item_bonus;
  3006. dmax += (int64)(dmax * status_get_apbonus(&sd->bl, STATUS_BONUS_RATE) / 100);// Aegis accuracy
  3007. //Make sure it's not negative before casting to uint32
  3008. if (dmax < 0) dmax = 0;
  3009. return cap_value((uint32)dmax, 0, UINT_MAX);
  3010. }
  3011. /**
  3012. * Calculates player's weight
  3013. * @param sd: Player object
  3014. * @param flag: Calculation type
  3015. * CALCWT_ITEM - Item weight
  3016. * CALCWT_MAXBONUS - Skill/Status/Configuration max weight bonus
  3017. * @return false - failed, true - success
  3018. */
  3019. bool status_calc_weight(map_session_data *sd, enum e_status_calc_weight_opt flag)
  3020. {
  3021. int32 b_weight, b_max_weight, skill, i;
  3022. status_change *sc;
  3023. nullpo_retr(false, sd);
  3024. sc = &sd->sc;
  3025. b_max_weight = sd->max_weight; // Store max weight for later comparison
  3026. b_weight = sd->weight; // Store current weight for later comparison
  3027. sd->max_weight = job_db.get_maxWeight(pc_mapid2jobid(sd->class_, sd->status.sex)) + sd->status.str * 300; // Recalculate max weight
  3028. if (flag&CALCWT_ITEM) {
  3029. sd->weight = 0; // Reset current weight
  3030. for(i = 0; i < MAX_INVENTORY; i++) {
  3031. if (!sd->inventory.u.items_inventory[i].nameid || sd->inventory_data[i] == nullptr)
  3032. continue;
  3033. sd->weight += sd->inventory_data[i]->weight * sd->inventory.u.items_inventory[i].amount;
  3034. }
  3035. }
  3036. if (flag&CALCWT_MAXBONUS) {
  3037. // Skill/Status bonus weight increases
  3038. sd->max_weight += sd->add_max_weight; // From bAddMaxWeight
  3039. if ((skill = pc_checkskill(sd, MC_INCCARRY)) > 0)
  3040. sd->max_weight += 2000 * skill;
  3041. if (pc_isriding(sd) && pc_checkskill(sd, KN_RIDING) > 0)
  3042. sd->max_weight += 10000;
  3043. else if (pc_isridingdragon(sd))
  3044. sd->max_weight += 5000 + 2000 * pc_checkskill(sd, RK_DRAGONTRAINING);
  3045. if (sc->getSCE(SC_KNOWLEDGE))
  3046. sd->max_weight += sd->max_weight * sc->getSCE(SC_KNOWLEDGE)->val1 / 10;
  3047. if ((skill = pc_checkskill(sd, ALL_INCCARRY)) > 0)
  3048. sd->max_weight += 2000 * skill;
  3049. if (pc_ismadogear(sd))
  3050. sd->max_weight += 15000;
  3051. }
  3052. // Update the client if the new weight calculations don't match
  3053. if (b_weight != sd->weight)
  3054. clif_updatestatus(*sd, SP_WEIGHT);
  3055. if (b_max_weight != sd->max_weight) {
  3056. clif_updatestatus(*sd, SP_MAXWEIGHT);
  3057. pc_updateweightstatus(sd);
  3058. }
  3059. return true;
  3060. }
  3061. /**
  3062. * Calculates player's cart weight
  3063. * @param sd: Player object
  3064. * @param flag: Calculation type
  3065. * CALCWT_ITEM - Cart item weight
  3066. * CALCWT_MAXBONUS - Skill/Status/Configuration max weight bonus
  3067. * CALCWT_CARTSTATE - Whether to check for cart state
  3068. * @return false - failed, true - success
  3069. */
  3070. bool status_calc_cart_weight(map_session_data *sd, enum e_status_calc_weight_opt flag)
  3071. {
  3072. int32 b_cart_weight_max, i;
  3073. nullpo_retr(false, sd);
  3074. if (!pc_iscarton(sd) && !(flag&CALCWT_CARTSTATE))
  3075. return false;
  3076. b_cart_weight_max = sd->cart_weight_max; // Store cart max weight for later comparison
  3077. sd->cart_weight_max = battle_config.max_cart_weight; // Recalculate max weight
  3078. if (flag&CALCWT_ITEM) {
  3079. sd->cart_weight = 0; // Reset current cart weight
  3080. sd->cart_num = 0; // Reset current cart item count
  3081. for(i = 0; i < MAX_CART; i++) {
  3082. if (!sd->cart.u.items_cart[i].nameid)
  3083. continue;
  3084. sd->cart_weight += itemdb_weight(sd->cart.u.items_cart[i].nameid) * sd->cart.u.items_cart[i].amount; // Recalculate current cart weight
  3085. sd->cart_num++; // Recalculate current cart item count
  3086. }
  3087. }
  3088. // Skill bonus max weight increases
  3089. if (flag&CALCWT_MAXBONUS)
  3090. sd->cart_weight_max += (pc_checkskill(sd, GN_REMODELING_CART) * 5000);
  3091. // Update the client if the new weight calculations don't match
  3092. if (b_cart_weight_max != sd->cart_weight_max)
  3093. clif_updatestatus(*sd, SP_CARTINFO);
  3094. return true;
  3095. }
  3096. /**
  3097. * Calculates player data from scratch without counting SC adjustments
  3098. * Should be invoked whenever players raise stats, learn passive skills or change equipment
  3099. * @param sd: Player object
  3100. * @param opt: Whether it is first calc (login) or not
  3101. * @return (-1) for too many recursive calls, (1) recursive call, (0) success
  3102. */
  3103. int32 status_calc_pc_sub(map_session_data* sd, uint8 opt)
  3104. {
  3105. static int32 calculating = 0; ///< Check for recursive call preemption. [Skotlex]
  3106. struct status_data *base_status; ///< Pointer to the player's base status
  3107. status_change *sc = &sd->sc;
  3108. struct s_skill b_skill[MAX_SKILL]; ///< Previous skill tree
  3109. int32 i, skill, refinedef = 0;
  3110. int16 index = -1;
  3111. if (++calculating > 10) // Too many recursive calls!
  3112. return -1;
  3113. // Remember player-specific values that are currently being shown to the client (for refresh purposes)
  3114. memcpy(b_skill, &sd->status.skill, sizeof(b_skill));
  3115. pc_calc_skilltree(sd); // SkillTree calculation
  3116. if (opt&SCO_FIRST) {
  3117. // Load Hp/SP from char-received data.
  3118. sd->battle_status.hp = sd->status.hp;
  3119. sd->battle_status.sp = sd->status.sp;
  3120. if (battle_config.keep_ap_on_logout == 1)
  3121. sd->battle_status.ap = sd->status.ap;
  3122. sd->regen.sregen = &sd->sregen;
  3123. sd->regen.ssregen = &sd->ssregen;
  3124. }
  3125. base_status = &sd->base_status;
  3126. // These are not zeroed. [zzo]
  3127. sd->hprate = 100;
  3128. sd->sprate = 100;
  3129. sd->aprate = 100;
  3130. sd->castrate = 100;
  3131. sd->dsprate = 100;
  3132. sd->hprecov_rate = 100;
  3133. sd->sprecov_rate = 100;
  3134. sd->matk_rate = 100;
  3135. sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100;
  3136. sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100;
  3137. sd->patk_rate = sd->smatk_rate = 100;
  3138. sd->res_rate = sd->mres_rate = 100;
  3139. sd->hplus_rate = sd->crate_rate = 100;
  3140. sd->regen.state.block = 0;
  3141. sd->add_max_weight = 0;
  3142. sd->indexed_bonus = {};
  3143. memset (&sd->right_weapon.overrefine, 0, sizeof(sd->right_weapon) - sizeof(sd->right_weapon.atkmods));
  3144. memset (&sd->left_weapon.overrefine, 0, sizeof(sd->left_weapon) - sizeof(sd->left_weapon.atkmods));
  3145. if (sd->special_state.intravision)
  3146. clif_status_load(&sd->bl, EFST_CLAIRVOYANCE, 0);
  3147. if (sd->special_state.no_walk_delay)
  3148. clif_status_load(&sd->bl, EFST_ENDURE, 0);
  3149. memset(&sd->special_state,0,sizeof(sd->special_state));
  3150. if (pc_isvip(sd)) // Magic Stone requirement avoidance for VIP.
  3151. sd->special_state.no_gemstone = battle_config.vip_gemstone;
  3152. if (!sd->state.permanent_speed) {
  3153. memset(&base_status->max_hp, 0, sizeof(struct status_data)-(sizeof(base_status->hp)+sizeof(base_status->sp)+sizeof(base_status->ap)));
  3154. base_status->speed = DEFAULT_WALK_SPEED;
  3155. } else {
  3156. int32 pSpeed = base_status->speed;
  3157. memset(&base_status->max_hp, 0, sizeof(struct status_data)-(sizeof(base_status->hp)+sizeof(base_status->sp)+sizeof(base_status->ap)));
  3158. base_status->speed = pSpeed;
  3159. }
  3160. // !FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex]
  3161. // Give them all modes except these (useful for clones)
  3162. base_status->mode = static_cast<e_mode>(MD_MASK&~(MD_STATUSIMMUNE|MD_IGNOREMELEE|MD_IGNOREMAGIC|MD_IGNORERANGED|MD_IGNOREMISC|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK));
  3163. base_status->size = (sd->class_&JOBL_BABY) ? SZ_SMALL : (((sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) ? battle_config.summoner_size : SZ_MEDIUM);
  3164. if (battle_config.character_size && pc_isriding(sd)) { // [Lupus]
  3165. if (sd->class_&JOBL_BABY) {
  3166. if (battle_config.character_size&SZ_BIG)
  3167. base_status->size++;
  3168. } else
  3169. if(battle_config.character_size&SZ_MEDIUM)
  3170. base_status->size++;
  3171. }
  3172. base_status->aspd_rate = 1000;
  3173. base_status->ele_lv = 1;
  3174. base_status->race = ((sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) ? battle_config.summoner_race : RC_PLAYER_HUMAN;
  3175. base_status->class_ = CLASS_NORMAL;
  3176. sd->autospell.clear();
  3177. sd->autospell2.clear();
  3178. sd->autospell3.clear();
  3179. sd->addeff.clear();
  3180. sd->addeff_atked.clear();
  3181. sd->addeff_onskill.clear();
  3182. sd->skillatk.clear();
  3183. sd->skillusesprate.clear();
  3184. sd->skillusesp.clear();
  3185. sd->skillheal.clear();
  3186. sd->skillheal2.clear();
  3187. sd->skillblown.clear();
  3188. sd->skillcastrate.clear();
  3189. sd->skillfixcastrate.clear();
  3190. sd->subskill.clear();
  3191. sd->skillcooldown.clear();
  3192. sd->skillfixcast.clear();
  3193. sd->skillvarcast.clear();
  3194. sd->add_def.clear();
  3195. sd->add_mdef.clear();
  3196. sd->add_mdmg.clear();
  3197. sd->reseff.clear();
  3198. sd->itemgrouphealrate.clear();
  3199. sd->add_drop.clear();
  3200. sd->itemhealrate.clear();
  3201. sd->subele2.clear();
  3202. sd->subrace3.clear();
  3203. sd->skilldelay.clear();
  3204. sd->sp_vanish.clear();
  3205. sd->hp_vanish.clear();
  3206. sd->itemsphealrate.clear();
  3207. sd->itemgroupsphealrate.clear();
  3208. // Zero up structures...
  3209. memset(&sd->hp_loss, 0, sizeof(sd->hp_loss)
  3210. + sizeof(sd->sp_loss)
  3211. + sizeof(sd->hp_regen)
  3212. + sizeof(sd->sp_regen)
  3213. + sizeof(sd->percent_hp_regen)
  3214. + sizeof(sd->percent_sp_regen)
  3215. + sizeof(sd->def_set_race)
  3216. + sizeof(sd->mdef_set_race)
  3217. + sizeof(sd->norecover_state_race)
  3218. + sizeof(sd->hp_vanish_race)
  3219. + sizeof(sd->sp_vanish_race)
  3220. );
  3221. memset(&sd->bonus, 0, sizeof(sd->bonus));
  3222. // Autobonus
  3223. pc_delautobonus(*sd, sd->autobonus, true);
  3224. pc_delautobonus(*sd, sd->autobonus2, true);
  3225. pc_delautobonus(*sd, sd->autobonus3, true);
  3226. if (sd->pd != nullptr) {
  3227. pet_delautobonus(*sd, sd->pd->autobonus, true);
  3228. pet_delautobonus(*sd, sd->pd->autobonus2, true);
  3229. pet_delautobonus(*sd, sd->pd->autobonus3, true);
  3230. }
  3231. // Parse equipment
  3232. for (i = 0; i < EQI_MAX; i++) {
  3233. current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
  3234. current_equip_combo_pos = 0;
  3235. if (index < 0)
  3236. continue;
  3237. if (i == EQI_AMMO)
  3238. continue;
  3239. if (pc_is_same_equip_index((enum equip_index)i, sd->equip_index, index))
  3240. continue;
  3241. if (!sd->inventory_data[index])
  3242. continue;
  3243. base_status->def += sd->inventory_data[index]->def;
  3244. // Items may be equipped, their effects however are nullified.
  3245. if (opt&SCO_FIRST && sd->inventory_data[index]->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT)
  3246. || !itemdb_isNoEquip(sd->inventory_data[index],sd->bl.m))) { // Execute equip-script on login
  3247. run_script(sd->inventory_data[index]->equip_script,0,sd->bl.id,0);
  3248. if (!calculating)
  3249. return 1;
  3250. }
  3251. // Sanitize the refine level in case someone decreased the value inbetween
  3252. if (sd->inventory.u.items_inventory[index].refine > MAX_REFINE)
  3253. sd->inventory.u.items_inventory[index].refine = MAX_REFINE;
  3254. std::shared_ptr<s_refine_level_info> info = refine_db.findCurrentLevelInfo( *sd->inventory_data[index], sd->inventory.u.items_inventory[index] );
  3255. #ifdef RENEWAL
  3256. std::shared_ptr<s_enchantgradelevel> enchantgrade_info = nullptr;
  3257. if( sd->inventory.u.items_inventory[index].enchantgrade > 0 ){
  3258. enchantgrade_info = enchantgrade_db.findCurrentLevelInfo( *sd->inventory_data[index], sd->inventory.u.items_inventory[index] );
  3259. }
  3260. #endif
  3261. if (sd->inventory_data[index]->type == IT_WEAPON) {
  3262. int32 wlv = sd->inventory_data[index]->weapon_level;
  3263. struct weapon_data *wd;
  3264. struct weapon_atk *wa;
  3265. if(wlv >= MAX_WEAPON_LEVEL)
  3266. wlv = MAX_WEAPON_LEVEL;
  3267. if(i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) {
  3268. wd = &sd->left_weapon; // Left-hand weapon
  3269. wa = &base_status->lhw;
  3270. } else {
  3271. wd = &sd->right_weapon;
  3272. wa = &base_status->rhw;
  3273. }
  3274. wa->atk += sd->inventory_data[index]->atk;
  3275. if( info != nullptr ){
  3276. wa->atk2 += info->bonus / 100;
  3277. #ifdef RENEWAL
  3278. if( enchantgrade_info != nullptr ){
  3279. wa->atk2 += ( ( ( info->bonus / 100 ) * enchantgrade_info->bonus ) / 100 );
  3280. }
  3281. if( wlv == 5 ){
  3282. base_status->patk += sd->inventory.u.items_inventory[index].refine * 2;
  3283. base_status->smatk += sd->inventory.u.items_inventory[index].refine * 2;
  3284. }
  3285. #endif
  3286. }
  3287. #ifdef RENEWAL
  3288. if (sd->bonus.weapon_atk_rate)
  3289. wa->atk += wa->atk * sd->bonus.weapon_atk_rate / 100;
  3290. wa->matk += sd->inventory_data[index]->matk;
  3291. wa->wlv = wlv;
  3292. // Renewal magic attack refine bonus
  3293. if( info != nullptr && sd->weapontype1 != W_BOW ){
  3294. wa->matk += info->bonus / 100;
  3295. if( enchantgrade_info != nullptr ){
  3296. wa->matk += ( ( ( info->bonus / 100 ) * enchantgrade_info->bonus ) / 100 );
  3297. }
  3298. }
  3299. #endif
  3300. // Overrefine bonus.
  3301. if( info != nullptr ){
  3302. wd->overrefine = info->randombonus_max / 100;
  3303. }
  3304. wa->range += sd->inventory_data[index]->range;
  3305. if(sd->inventory_data[index]->script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(sd->inventory_data[index],sd->bl.m))) {
  3306. if (wd == &sd->left_weapon) {
  3307. sd->state.lr_flag = LR_FLAG_WEAPON;
  3308. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  3309. sd->state.lr_flag = LR_FLAG_NONE;
  3310. } else
  3311. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  3312. if (!calculating) // Abort, run_script retriggered this. [Skotlex]
  3313. return 1;
  3314. }
  3315. #ifdef RENEWAL
  3316. if (sd->bonus.weapon_matk_rate)
  3317. wa->matk += wa->matk * sd->bonus.weapon_matk_rate / 100;
  3318. #endif
  3319. if(sd->inventory.u.items_inventory[index].card[0] == CARD0_FORGE) { // Forged weapon
  3320. wd->star += (sd->inventory.u.items_inventory[index].card[1]>>8);
  3321. if(wd->star >= 15) wd->star = 40; // 3 Star Crumbs now give +40 dmg
  3322. if(pc_famerank(MakeDWord(sd->inventory.u.items_inventory[index].card[2],sd->inventory.u.items_inventory[index].card[3]) ,MAPID_BLACKSMITH))
  3323. wd->star += 10;
  3324. if (!wa->ele) // Do not overwrite element from previous bonuses.
  3325. wa->ele = (sd->inventory.u.items_inventory[index].card[1]&0x0f);
  3326. }
  3327. } else if(sd->inventory_data[index]->type == IT_ARMOR) {
  3328. if( info != nullptr ){
  3329. refinedef += info->bonus;
  3330. #ifdef RENEWAL
  3331. if( sd->inventory_data[index]->armor_level == 2 ){
  3332. base_status->res += sd->inventory.u.items_inventory[index].refine * 2;
  3333. base_status->mres += sd->inventory.u.items_inventory[index].refine * 2;
  3334. }
  3335. #endif
  3336. }
  3337. if(sd->inventory_data[index]->script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(sd->inventory_data[index],sd->bl.m))) {
  3338. if( i == EQI_HAND_L ) // Shield
  3339. sd->state.lr_flag = LR_FLAG_SHIELD;
  3340. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  3341. if( i == EQI_HAND_L ) // Shield
  3342. sd->state.lr_flag = LR_FLAG_NONE;
  3343. if (!calculating) // Abort, run_script retriggered this. [Skotlex]
  3344. return 1;
  3345. }
  3346. } else if( sd->inventory_data[index]->type == IT_SHADOWGEAR ) { // Shadow System
  3347. if (sd->inventory_data[index]->script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(sd->inventory_data[index],sd->bl.m))) {
  3348. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  3349. if( !calculating )
  3350. return 1;
  3351. }
  3352. }
  3353. }
  3354. if(sd->equip_index[EQI_AMMO] >= 0) {
  3355. index = sd->equip_index[EQI_AMMO];
  3356. if(sd->inventory_data[index]) { // Arrows
  3357. sd->bonus.arrow_atk += sd->inventory_data[index]->atk;
  3358. sd->state.lr_flag = LR_FLAG_ARROW;
  3359. if( !itemdb_group.item_exists(IG_THROWABLE, sd->inventory_data[index]->nameid) ) // Don't run scripts on throwable items
  3360. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  3361. sd->state.lr_flag = LR_FLAG_NONE;
  3362. if (!calculating) // Abort, run_script retriggered status_calc_pc. [Skotlex]
  3363. return 1;
  3364. }
  3365. }
  3366. // Process and check item combos
  3367. if (!sd->combos.empty()) {
  3368. for (const auto &combo : sd->combos) {
  3369. std::shared_ptr<s_item_combo> item_combo;
  3370. current_equip_item_index = -1;
  3371. current_equip_combo_pos = combo->pos;
  3372. if (combo->bonus == nullptr || !(item_combo = itemdb_combo.find(combo->id)))
  3373. continue;
  3374. bool no_run = false;
  3375. size_t j = 0;
  3376. // Check combo items
  3377. while (j < item_combo->nameid.size()) {
  3378. std::shared_ptr<item_data> id = item_db.find(item_combo->nameid[j]);
  3379. // Don't run the script if at least one of combo's pair has restriction
  3380. if (id && !pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(id.get(), sd->bl.m)) {
  3381. no_run = true;
  3382. break;
  3383. }
  3384. j++;
  3385. }
  3386. if (no_run)
  3387. continue;
  3388. run_script(combo->bonus, 0, sd->bl.id, 0);
  3389. if (!calculating) // Abort, run_script retriggered this
  3390. return 1;
  3391. }
  3392. }
  3393. // Store equipment script bonuses
  3394. memcpy(sd->indexed_bonus.param_equip,sd->indexed_bonus.param_bonus,sizeof(sd->indexed_bonus.param_equip));
  3395. memset(sd->indexed_bonus.param_bonus, 0, sizeof(sd->indexed_bonus.param_bonus));
  3396. base_status->def += (refinedef+50)/100;
  3397. // Parse Cards
  3398. for (i = 0; i < EQI_MAX; i++) {
  3399. current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
  3400. current_equip_combo_pos = 0;
  3401. if (index < 0)
  3402. continue;
  3403. if (i == EQI_AMMO)
  3404. continue;
  3405. if (pc_is_same_equip_index((enum equip_index)i, sd->equip_index, index))
  3406. continue;
  3407. if (sd->inventory_data[index]) {
  3408. int32 j;
  3409. // Card script execution.
  3410. if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
  3411. continue;
  3412. for (j = 0; j < MAX_SLOTS; j++) { // Uses MAX_SLOTS to support Soul Bound system [Inkfish]
  3413. int32 c = sd->inventory.u.items_inventory[index].card[j];
  3414. current_equip_card_id= c;
  3415. if(!c)
  3416. continue;
  3417. std::shared_ptr<item_data> data = item_db.find(c);
  3418. if(!data)
  3419. continue;
  3420. if (opt&SCO_FIRST && data->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(data.get(), sd->bl.m))) {// Execute equip-script on login
  3421. run_script(data->equip_script,0,sd->bl.id,0);
  3422. if (!calculating)
  3423. return 1;
  3424. }
  3425. if(!data->script)
  3426. continue;
  3427. if(!pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(data.get(), sd->bl.m)) // Card restriction checks.
  3428. continue;
  3429. if(i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) { // Left hand status.
  3430. sd->state.lr_flag = LR_FLAG_WEAPON;
  3431. run_script(data->script,0,sd->bl.id,0);
  3432. sd->state.lr_flag = LR_FLAG_NONE;
  3433. } else
  3434. run_script(data->script,0,sd->bl.id,0);
  3435. if (!calculating) // Abort, run_script his function. [Skotlex]
  3436. return 1;
  3437. }
  3438. }
  3439. }
  3440. current_equip_card_id = 0; // Clear stored card ID [Secret]
  3441. // Parse random options
  3442. for (i = 0; i < EQI_MAX; i++) {
  3443. current_equip_item_index = index = sd->equip_index[i];
  3444. current_equip_combo_pos = 0;
  3445. current_equip_opt_index = -1;
  3446. if (index < 0)
  3447. continue;
  3448. if (i == EQI_AMMO)
  3449. continue;
  3450. if (pc_is_same_equip_index((enum equip_index)i, sd->equip_index, index))
  3451. continue;
  3452. if (sd->inventory_data[index]) {
  3453. for (uint8 j = 0; j < MAX_ITEM_RDM_OPT; j++) {
  3454. int16 opt_id = sd->inventory.u.items_inventory[index].option[j].id;
  3455. if (!opt_id)
  3456. continue;
  3457. current_equip_opt_index = j;
  3458. std::shared_ptr<s_random_opt_data> data = random_option_db.find(opt_id);
  3459. if (!data || !data->script)
  3460. continue;
  3461. if (!pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(sd->inventory_data[index], sd->bl.m))
  3462. continue;
  3463. if (i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) { // Left hand status.
  3464. sd->state.lr_flag = LR_FLAG_WEAPON;
  3465. run_script(data->script, 0, sd->bl.id, 0);
  3466. sd->state.lr_flag = LR_FLAG_NONE;
  3467. }
  3468. else
  3469. run_script(data->script, 0, sd->bl.id, 0);
  3470. if (!calculating)
  3471. return 1;
  3472. }
  3473. }
  3474. current_equip_opt_index = -1;
  3475. }
  3476. if (!sc->empty()){
  3477. if( status_change_entry* sce = sc->getSCE(SC_ITEMSCRIPT); sce != nullptr ){
  3478. std::shared_ptr<item_data> data = item_db.find(sc->getSCE(SC_ITEMSCRIPT)->val1);
  3479. if (data && data->script)
  3480. run_script(data->script, 0, sd->bl.id, 0);
  3481. }
  3482. for( sc_type type = SC_NONE; type < SC_MAX; type = static_cast<sc_type>( type + 1 ) ){
  3483. if( status_change_entry* sce = sc->getSCE( type ); sce != nullptr ){
  3484. if( std::shared_ptr<s_status_change_db> scdb = status_db.find( type ); scdb != nullptr && scdb->script != nullptr ){
  3485. run_script( scdb->script, 0, sd->bl.id, 0 );
  3486. }
  3487. }
  3488. }
  3489. }
  3490. pc_bonus_script(sd);
  3491. if( sd->pd ) { // Pet Bonus
  3492. struct pet_data *pd = sd->pd;
  3493. std::shared_ptr<s_pet_db> pet_db_ptr = pd->get_pet_db();
  3494. if (pet_db_ptr != nullptr && pet_db_ptr->pet_bonus_script)
  3495. run_script(pet_db_ptr->pet_bonus_script,0,sd->bl.id,0);
  3496. if (pet_db_ptr != nullptr && pd->pet.intimate > 0 && (!battle_config.pet_equip_required || pd->pet.equip > 0) && pd->state.skillbonus == 1 && pd->bonus)
  3497. pc_bonus(sd,pd->bonus->type, pd->bonus->val);
  3498. }
  3499. // param_bonus now holds card bonuses.
  3500. if(base_status->rhw.range < 1) base_status->rhw.range = 1;
  3501. if(base_status->lhw.range < 1) base_status->lhw.range = 1;
  3502. if(base_status->rhw.range < base_status->lhw.range)
  3503. base_status->rhw.range = base_status->lhw.range;
  3504. sd->bonus.double_rate += sd->bonus.double_add_rate;
  3505. sd->bonus.perfect_hit += sd->bonus.perfect_hit_add;
  3506. sd->bonus.splash_range += sd->bonus.splash_add_range;
  3507. // Damage modifiers from weapon type
  3508. if( std::shared_ptr<s_sizefix_db> right_weapon = size_fix_db.find(sd->weapontype1); right_weapon != nullptr ){
  3509. sd->right_weapon.atkmods[SZ_SMALL] = right_weapon->small;
  3510. sd->right_weapon.atkmods[SZ_MEDIUM] = right_weapon->medium;
  3511. sd->right_weapon.atkmods[SZ_BIG] = right_weapon->large;
  3512. }
  3513. if( std::shared_ptr<s_sizefix_db> left_weapon = size_fix_db.find(sd->weapontype2); left_weapon != nullptr ){
  3514. sd->left_weapon.atkmods[SZ_SMALL] = left_weapon->small;
  3515. sd->left_weapon.atkmods[SZ_MEDIUM] = left_weapon->medium;
  3516. sd->left_weapon.atkmods[SZ_BIG] = left_weapon->large;
  3517. }
  3518. if((pc_isriding(sd) || pc_isridingdragon(sd)) &&
  3519. (sd->status.weapon==W_1HSPEAR || sd->status.weapon==W_2HSPEAR))
  3520. { // When Riding with spear, damage modifier to mid-class becomes
  3521. // same as versus large size.
  3522. sd->right_weapon.atkmods[SZ_MEDIUM] = sd->right_weapon.atkmods[SZ_BIG];
  3523. sd->left_weapon.atkmods[SZ_MEDIUM] = sd->left_weapon.atkmods[SZ_BIG];
  3524. }
  3525. // ----- STATS CALCULATION -----
  3526. // Job bonuses
  3527. std::shared_ptr<s_job_info> job_info = job_db.find( pc_mapid2jobid( sd->class_, sd->status.sex ) );
  3528. if( job_info != nullptr ){
  3529. const auto& bonus = job_info->job_bonus[sd->status.job_level-1];
  3530. base_status->str += bonus[PARAM_STR];
  3531. base_status->agi += bonus[PARAM_AGI];
  3532. base_status->vit += bonus[PARAM_VIT];
  3533. base_status->int_ += bonus[PARAM_INT];
  3534. base_status->dex += bonus[PARAM_DEX];
  3535. base_status->luk += bonus[PARAM_LUK];
  3536. base_status->pow += bonus[PARAM_POW];
  3537. base_status->sta += bonus[PARAM_STA];
  3538. base_status->wis += bonus[PARAM_WIS];
  3539. base_status->spl += bonus[PARAM_SPL];
  3540. base_status->con += bonus[PARAM_CON];
  3541. base_status->crt += bonus[PARAM_CRT];
  3542. }
  3543. // If a Super Novice has never died and is at least joblv 70, he gets all stats +10
  3544. if(((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && (sd->status.job_level >= 70 || sd->class_&JOBL_THIRD)) && sd->die_counter == 0) {
  3545. base_status->str += 10;
  3546. base_status->agi += 10;
  3547. base_status->vit += 10;
  3548. base_status->int_+= 10;
  3549. base_status->dex += 10;
  3550. base_status->luk += 10;
  3551. }
  3552. // Absolute modifiers from passive skills
  3553. if(pc_checkskill(sd,BS_HILTBINDING)>0)
  3554. base_status->str++;
  3555. if((skill=pc_checkskill(sd,SA_DRAGONOLOGY))>0)
  3556. base_status->int_ += (skill+1)/2; // +1 INT / 2 lv
  3557. if((skill=pc_checkskill(sd,AC_OWL))>0)
  3558. base_status->dex += skill;
  3559. if((skill = pc_checkskill(sd,RA_RESEARCHTRAP))>0)
  3560. base_status->int_ += skill;
  3561. if (pc_checkskill(sd, SU_POWEROFLAND) > 0)
  3562. base_status->int_ += 20;
  3563. // Bonuses from cards and equipment as well as base stat, remember to avoid overflows.
  3564. i = base_status->str + sd->status.str + sd->indexed_bonus.param_bonus[PARAM_STR] + sd->indexed_bonus.param_equip[PARAM_STR];
  3565. base_status->str = cap_value(i,0,USHRT_MAX);
  3566. i = base_status->agi + sd->status.agi + sd->indexed_bonus.param_bonus[PARAM_AGI] + sd->indexed_bonus.param_equip[PARAM_AGI];
  3567. base_status->agi = cap_value(i,0,USHRT_MAX);
  3568. i = base_status->vit + sd->status.vit + sd->indexed_bonus.param_bonus[PARAM_VIT] + sd->indexed_bonus.param_equip[PARAM_VIT];
  3569. base_status->vit = cap_value(i,0,USHRT_MAX);
  3570. i = base_status->int_+ sd->status.int_+ sd->indexed_bonus.param_bonus[PARAM_INT] + sd->indexed_bonus.param_equip[PARAM_INT];
  3571. base_status->int_ = cap_value(i,0,USHRT_MAX);
  3572. i = base_status->dex + sd->status.dex + sd->indexed_bonus.param_bonus[PARAM_DEX] + sd->indexed_bonus.param_equip[PARAM_DEX];
  3573. base_status->dex = cap_value(i,0,USHRT_MAX);
  3574. i = base_status->luk + sd->status.luk + sd->indexed_bonus.param_bonus[PARAM_LUK] + sd->indexed_bonus.param_equip[PARAM_LUK];
  3575. base_status->luk = cap_value(i,0,USHRT_MAX);
  3576. i = base_status->pow + sd->status.pow + sd->indexed_bonus.param_bonus[PARAM_POW] + sd->indexed_bonus.param_equip[PARAM_POW];
  3577. base_status->pow = cap_value(i, 0, USHRT_MAX);
  3578. i = base_status->sta + sd->status.sta + sd->indexed_bonus.param_bonus[PARAM_STA] + sd->indexed_bonus.param_equip[PARAM_STA];
  3579. base_status->sta = cap_value(i, 0, USHRT_MAX);
  3580. i = base_status->wis + sd->status.wis + sd->indexed_bonus.param_bonus[PARAM_WIS] + sd->indexed_bonus.param_equip[PARAM_WIS];
  3581. base_status->wis = cap_value(i, 0, USHRT_MAX);
  3582. i = base_status->spl + sd->status.spl + sd->indexed_bonus.param_bonus[PARAM_SPL] + sd->indexed_bonus.param_equip[PARAM_SPL];
  3583. base_status->spl = cap_value(i, 0, USHRT_MAX);
  3584. i = base_status->con + sd->status.con + sd->indexed_bonus.param_bonus[PARAM_CON] + sd->indexed_bonus.param_equip[PARAM_CON];
  3585. base_status->con = cap_value(i, 0, USHRT_MAX);
  3586. i = base_status->crt + sd->status.crt + sd->indexed_bonus.param_bonus[PARAM_CRT] + sd->indexed_bonus.param_equip[PARAM_CRT];
  3587. base_status->crt = cap_value(i, 0, USHRT_MAX);
  3588. if (sd->special_state.no_walk_delay) {
  3589. if (sc->getSCE(SC_ENDURE)) {
  3590. if (sc->getSCE(SC_ENDURE)->val4)
  3591. sc->getSCE(SC_ENDURE)->val4 = 0;
  3592. status_change_end(&sd->bl, SC_ENDURE);
  3593. }
  3594. clif_status_load(&sd->bl, EFST_ENDURE, 1);
  3595. base_status->mdef++;
  3596. }
  3597. // ----- CONCENTRATION CALCULATION -----
  3598. if ((skill = pc_checkskill(sd, NW_GRENADE_MASTERY)) > 0)
  3599. base_status->con += skill;
  3600. // ----- SPELL CALCULATION -----
  3601. if ((skill = pc_checkskill(sd, SOA_SOUL_MASTERY)) > 0)
  3602. base_status->spl += skill;
  3603. // ------ ATTACK CALCULATION ------
  3604. // Base batk value is set in status_calc_misc
  3605. #ifndef RENEWAL
  3606. // !FIXME: Weapon-type bonus (Why is the weapon_atk bonus applied to base attack?)
  3607. if (sd->status.weapon < MAX_WEAPON_TYPE && sd->indexed_bonus.weapon_atk[sd->status.weapon])
  3608. base_status->batk += sd->indexed_bonus.weapon_atk[sd->status.weapon];
  3609. // Absolute modifiers from passive skills
  3610. if((skill=pc_checkskill(sd,BS_HILTBINDING))>0)
  3611. base_status->batk += 4;
  3612. #else
  3613. base_status->watk = status_weapon_atk(base_status->rhw);
  3614. base_status->watk2 = status_weapon_atk(base_status->lhw);
  3615. base_status->eatk = sd->bonus.eatk;
  3616. #endif
  3617. // ----- HP MAX CALCULATION -----
  3618. base_status->max_hp = sd->status.max_hp = status_calc_maxhpsp_pc(sd,base_status->vit,true);
  3619. if(battle_config.hp_rate != 100)
  3620. base_status->max_hp = (uint32)(battle_config.hp_rate * (base_status->max_hp/100.));
  3621. if (sd->status.base_level < 100)
  3622. base_status->max_hp = cap_value(base_status->max_hp,1,(uint32)battle_config.max_hp_lv99);
  3623. else if (sd->status.base_level < 151)
  3624. base_status->max_hp = cap_value(base_status->max_hp,1,(uint32)battle_config.max_hp_lv150);
  3625. else
  3626. base_status->max_hp = cap_value(base_status->max_hp,1,(uint32)battle_config.max_hp);
  3627. // ----- SP MAX CALCULATION -----
  3628. base_status->max_sp = sd->status.max_sp = status_calc_maxhpsp_pc(sd,base_status->int_,false);
  3629. if(battle_config.sp_rate != 100)
  3630. base_status->max_sp = (uint32)(battle_config.sp_rate * (base_status->max_sp/100.));
  3631. base_status->max_sp = cap_value(base_status->max_sp,1,(uint32)battle_config.max_sp);
  3632. // ----- AP MAX CALCULATION -----
  3633. base_status->max_ap = sd->status.max_ap = status_calc_maxap_pc(sd);
  3634. if (battle_config.ap_rate != 100)
  3635. base_status->max_ap = (uint32)(battle_config.ap_rate * (base_status->max_ap / 100.));
  3636. base_status->max_ap = cap_value(base_status->max_ap, 0, (uint32)battle_config.max_ap);
  3637. // ----- RESPAWN HP/SP/AP -----
  3638. // Calc respawn hp and store it on base_status
  3639. if (sd->special_state.restart_full_recover) {
  3640. base_status->hp = base_status->max_hp;
  3641. base_status->sp = base_status->max_sp;
  3642. } else {
  3643. if((sd->class_&MAPID_BASEMASK) == MAPID_NOVICE && !(sd->class_&JOBL_2)
  3644. && battle_config.restart_hp_rate < 50)
  3645. base_status->hp = base_status->max_hp / 2;
  3646. else
  3647. base_status->hp = (int64)base_status->max_hp * battle_config.restart_hp_rate/100;
  3648. if(!base_status->hp)
  3649. base_status->hp = 1;
  3650. base_status->sp = (int64)base_status->max_sp * battle_config.restart_sp_rate /100;
  3651. if( !base_status->sp ) // The minimum for the respawn setting is SP:1
  3652. base_status->sp = 1;
  3653. base_status->ap = (int64)base_status->max_ap * battle_config.restart_ap_rate / 100;
  3654. }
  3655. // ----- MISC CALCULATION -----
  3656. status_calc_misc(&sd->bl, base_status, sd->status.base_level);
  3657. // Equipment modifiers for misc settings
  3658. if(sd->matk_rate < 0)
  3659. sd->matk_rate = 0;
  3660. if(sd->matk_rate != 100) {
  3661. base_status->matk_max = base_status->matk_max * sd->matk_rate/100;
  3662. base_status->matk_min = base_status->matk_min * sd->matk_rate/100;
  3663. }
  3664. if(sd->hit_rate < 0)
  3665. sd->hit_rate = 0;
  3666. if(sd->hit_rate != 100)
  3667. base_status->hit = base_status->hit * sd->hit_rate/100;
  3668. if(sd->flee_rate < 0)
  3669. sd->flee_rate = 0;
  3670. if(sd->flee_rate != 100)
  3671. base_status->flee = base_status->flee * sd->flee_rate/100;
  3672. if(sd->def2_rate < 0)
  3673. sd->def2_rate = 0;
  3674. if(sd->def2_rate != 100)
  3675. base_status->def2 = base_status->def2 * sd->def2_rate/100;
  3676. if(sd->mdef2_rate < 0)
  3677. sd->mdef2_rate = 0;
  3678. if(sd->mdef2_rate != 100)
  3679. base_status->mdef2 = base_status->mdef2 * sd->mdef2_rate/100;
  3680. if(sd->critical_rate < 0)
  3681. sd->critical_rate = 0;
  3682. if(sd->critical_rate != 100)
  3683. base_status->cri = cap_value(base_status->cri * sd->critical_rate/100,SHRT_MIN,SHRT_MAX);
  3684. if (pc_checkskill(sd, SU_POWEROFLIFE) > 0)
  3685. base_status->cri += 200;
  3686. if(sd->flee2_rate < 0)
  3687. sd->flee2_rate = 0;
  3688. if(sd->flee2_rate != 100)
  3689. base_status->flee2 = base_status->flee2 * sd->flee2_rate/100;
  3690. if (sd->patk_rate < 0)
  3691. sd->patk_rate = 0;
  3692. if (sd->patk_rate != 100)
  3693. base_status->patk = base_status->patk * sd->patk_rate / 100;
  3694. if (sd->smatk_rate < 0)
  3695. sd->smatk_rate = 0;
  3696. if (sd->smatk_rate != 100)
  3697. base_status->smatk = base_status->smatk * sd->smatk_rate / 100;
  3698. if (sd->res_rate < 0)
  3699. sd->res_rate = 0;
  3700. if (sd->res_rate != 100)
  3701. base_status->res = base_status->res * sd->res_rate / 100;
  3702. if (sd->mres_rate < 0)
  3703. sd->mres_rate = 0;
  3704. if (sd->mres_rate != 100)
  3705. base_status->mres = base_status->mres * sd->mres_rate / 100;
  3706. if (sd->hplus_rate < 0)
  3707. sd->hplus_rate = 0;
  3708. if (sd->hplus_rate != 100)
  3709. base_status->hplus = base_status->hplus * sd->hplus_rate / 100;
  3710. if (sd->crate_rate < 0)
  3711. sd->crate_rate = 0;
  3712. if (sd->crate_rate != 100)
  3713. base_status->crate = base_status->crate * sd->crate_rate / 100;
  3714. // ----- HIT CALCULATION -----
  3715. // Absolute modifiers from passive skills
  3716. #ifndef RENEWAL
  3717. if((skill=pc_checkskill(sd,BS_WEAPONRESEARCH))>0)
  3718. base_status->hit += skill*2;
  3719. #endif
  3720. if((skill=pc_checkskill(sd,AC_VULTURE))>0) {
  3721. #ifndef RENEWAL
  3722. base_status->hit += skill;
  3723. #endif
  3724. if(sd->status.weapon == W_BOW)
  3725. base_status->rhw.range += skill;
  3726. }
  3727. if(sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE) {
  3728. if((skill=pc_checkskill(sd,GS_SINGLEACTION))>0)
  3729. base_status->hit += 2*skill;
  3730. if((skill=pc_checkskill(sd,GS_SNAKEEYE))>0) {
  3731. base_status->hit += skill;
  3732. base_status->rhw.range += skill;
  3733. }
  3734. }
  3735. if((sd->status.weapon == W_1HAXE || sd->status.weapon == W_2HAXE) && (skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
  3736. base_status->hit += skill * 3;
  3737. if((sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE) && (skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
  3738. base_status->hit += skill * 2;
  3739. if (pc_checkskill(sd, SU_POWEROFLIFE) > 0)
  3740. base_status->hit += 20;
  3741. if ((skill = pc_checkskill_imperial_guard(sd, 2)) > 0)// IG_SPEAR_SWORD_M
  3742. base_status->hit += skill * 3;
  3743. if (sd->status.weapon == W_BOOK && (skill = pc_checkskill(sd, SKE_WAR_BOOK_MASTERY)) > 0)
  3744. base_status->hit += skill * 3;
  3745. if ((skill = pc_checkskill(sd, SU_SOULATTACK)) > 0)
  3746. base_status->rhw.range += skill_get_range2(&sd->bl, SU_SOULATTACK, skill, true);
  3747. // ----- FLEE CALCULATION -----
  3748. // Absolute modifiers from passive skills
  3749. if((skill=pc_checkskill(sd,TF_MISS))>0)
  3750. base_status->flee += skill*(sd->class_&JOBL_2 && (sd->class_&MAPID_BASEMASK) == MAPID_THIEF? 4 : 3);
  3751. if((skill=pc_checkskill(sd,MO_DODGE))>0)
  3752. base_status->flee += (skill*3) / 2;
  3753. if (pc_checkskill(sd, SU_POWEROFLIFE) > 0)
  3754. base_status->flee += 20;
  3755. if ((skill = pc_checkskill(sd, SHC_SHADOW_SENSE)) > 0)
  3756. base_status->flee += skill * 10;
  3757. // ----- CRITICAL CALCULATION -----
  3758. #ifdef RENEWAL
  3759. if ((skill = pc_checkskill(sd, DC_DANCINGLESSON)) > 0)
  3760. base_status->cri += skill * 10;
  3761. if ((skill = pc_checkskill(sd, PR_MACEMASTERY)) > 0 && (sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE))
  3762. base_status->cri += skill * 10;
  3763. #endif
  3764. if ((skill = pc_checkskill(sd, SHC_SHADOW_SENSE)) > 0)
  3765. {
  3766. if (sd->status.weapon == W_DAGGER || sd->status.weapon == W_DOUBLE_DD ||
  3767. sd->status.weapon == W_DOUBLE_DS || sd->status.weapon == W_DOUBLE_DA)
  3768. base_status->cri += 100 + skill * 40;
  3769. else if (sd->status.weapon == W_KATAR)
  3770. base_status->cri += 50 + skill * 20;
  3771. }
  3772. // ----- P.Atk/S.Matk CALCULATION -----
  3773. if ((skill = pc_checkskill(sd, TR_STAGE_MANNER)) > 0 && (sd->status.weapon == W_BOW || sd->status.weapon == W_MUSICAL || sd->status.weapon == W_WHIP)) {
  3774. base_status->patk += skill * 3;
  3775. base_status->smatk += skill * 3;
  3776. }
  3777. if ((skill = pc_checkskill(sd, HN_SELFSTUDY_TATICS)) > 0)
  3778. base_status->patk += skill;
  3779. if ((skill = pc_checkskill(sd, HN_SELFSTUDY_SOCERY)) > 0)
  3780. base_status->smatk += skill;
  3781. if ((skill = pc_checkskill(sd, NW_P_F_I)) > 0 && (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE))
  3782. base_status->patk += skill + 2;
  3783. if ((skill = pc_checkskill(sd, SOA_TALISMAN_MASTERY)) > 0)
  3784. base_status->smatk += skill;
  3785. if (sd->status.weapon == W_BOOK && (skill = pc_checkskill(sd, SKE_WAR_BOOK_MASTERY)) > 0)
  3786. base_status->patk += skill+2;
  3787. // 2-Handed Staff Mastery
  3788. if( sd->status.weapon == W_2HSTAFF && ( skill = pc_checkskill( sd, AG_TWOHANDSTAFF ) ) > 0 ){
  3789. base_status->smatk += skill * 2;
  3790. }
  3791. if ((skill = pc_checkskill(sd, SH_MYSTICAL_CREATURE_MASTERY)) > 0) {
  3792. base_status->smatk += skill * 15 / 10;
  3793. base_status->patk += skill * 15 / 10;
  3794. }
  3795. // ----- PHYSICAL RESISTANCE CALCULATION -----
  3796. if ((skill = pc_checkskill_imperial_guard(sd, 1)) > 0)// IG_SHIELD_MASTERY
  3797. base_status->res += skill * 3;
  3798. // ----- EQUIPMENT-DEF CALCULATION -----
  3799. // Apply relative modifiers from equipment
  3800. if(sd->def_rate < 0)
  3801. sd->def_rate = 0;
  3802. if(sd->def_rate != 100) {
  3803. i = base_status->def * sd->def_rate/100;
  3804. base_status->def = cap_value(i, DEFTYPE_MIN, DEFTYPE_MAX);
  3805. }
  3806. if(pc_ismadogear(sd) && pc_checkskill(sd, NC_MAINFRAME) > 0)
  3807. base_status->def += 20 + (pc_checkskill(sd, NC_MAINFRAME) * 20);
  3808. #ifndef RENEWAL
  3809. if (!battle_config.weapon_defense_type && base_status->def > battle_config.max_def) {
  3810. base_status->def2 += battle_config.over_def_bonus*(base_status->def -battle_config.max_def);
  3811. base_status->def = (unsigned char)battle_config.max_def;
  3812. }
  3813. #endif
  3814. // ----- EQUIPMENT-MDEF CALCULATION -----
  3815. // Apply relative modifiers from equipment
  3816. if(sd->mdef_rate < 0)
  3817. sd->mdef_rate = 0;
  3818. if(sd->mdef_rate != 100) {
  3819. i = base_status->mdef * sd->mdef_rate/100;
  3820. base_status->mdef = cap_value(i, DEFTYPE_MIN, DEFTYPE_MAX);
  3821. }
  3822. #ifndef RENEWAL
  3823. if (!battle_config.magic_defense_type && base_status->mdef > battle_config.max_def) {
  3824. base_status->mdef2 += battle_config.over_def_bonus*(base_status->mdef -battle_config.max_def);
  3825. base_status->mdef = (signed char)battle_config.max_def;
  3826. }
  3827. #endif
  3828. // ----- ASPD CALCULATION -----
  3829. /// Unlike other stats, ASPD rate modifiers from skills/SCs/items/etc are first all added together, then the final modifier is applied
  3830. // Basic ASPD value
  3831. i = status_base_amotion_pc(sd,base_status);
  3832. base_status->amotion = cap_value(i,pc_maxaspd(sd),2000);
  3833. // Relative modifiers from passive skills
  3834. // Renewal modifiers are handled in status_base_amotion_pc
  3835. #ifndef RENEWAL_ASPD
  3836. if((skill=pc_checkskill(sd,SA_ADVANCEDBOOK))>0 && sd->status.weapon == W_BOOK)
  3837. base_status->aspd_rate -= 5*skill;
  3838. if ((skill = pc_checkskill(sd,SG_DEVIL)) > 0 && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd)))
  3839. base_status->aspd_rate -= 30*skill;
  3840. if((skill=pc_checkskill(sd,GS_SINGLEACTION))>0 &&
  3841. (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE))
  3842. base_status->aspd_rate -= ((skill+1)/2) * 10;
  3843. if(pc_isriding(sd))
  3844. base_status->aspd_rate += 500-100*pc_checkskill(sd,KN_CAVALIERMASTERY);
  3845. else if(pc_isridingdragon(sd))
  3846. base_status->aspd_rate += 250-50*pc_checkskill(sd,RK_DRAGONTRAINING);
  3847. #endif
  3848. base_status->adelay = 2*base_status->amotion;
  3849. // ----- DMOTION -----
  3850. i = 800-base_status->agi*4;
  3851. base_status->dmotion = cap_value(i, 400, 800);
  3852. if(battle_config.pc_damage_delay_rate != 100)
  3853. base_status->dmotion = base_status->dmotion*battle_config.pc_damage_delay_rate/100;
  3854. // ----- MISC CALCULATIONS -----
  3855. // Weight
  3856. status_calc_weight(sd, CALCWT_MAXBONUS);
  3857. status_calc_cart_weight(sd, CALCWT_MAXBONUS);
  3858. if (pc_checkskill(sd, SM_MOVINGRECOVERY) > 0 || pc_ismadogear(sd))
  3859. sd->regen.state.walk = 1;
  3860. else
  3861. sd->regen.state.walk = 0;
  3862. // Skill SP cost
  3863. if((skill=pc_checkskill(sd,HP_MANARECHARGE))>0 )
  3864. sd->dsprate -= 4*skill;
  3865. if(sc->getSCE(SC_SERVICE4U))
  3866. sd->dsprate -= sc->getSCE(SC_SERVICE4U)->val3;
  3867. // Underflow protections.
  3868. if(sd->dsprate < 0)
  3869. sd->dsprate = 0;
  3870. if(sd->castrate < 0)
  3871. sd->castrate = 0;
  3872. if(sd->hprecov_rate < 0)
  3873. sd->hprecov_rate = 0;
  3874. if(sd->sprecov_rate < 0)
  3875. sd->sprecov_rate = 0;
  3876. // Anti-element and anti-race
  3877. if((skill=pc_checkskill(sd,CR_TRUST))>0)
  3878. sd->indexed_bonus.subele[ELE_HOLY] += skill*5;
  3879. if((skill=pc_checkskill(sd,BS_SKINTEMPER))>0) {
  3880. sd->indexed_bonus.subele[ELE_NEUTRAL] += skill;
  3881. sd->indexed_bonus.subele[ELE_FIRE] += skill*5;
  3882. }
  3883. if((skill=pc_checkskill(sd,SA_DRAGONOLOGY))>0) {
  3884. uint8 dragon_matk = skill * 2;
  3885. skill = skill * 4;
  3886. sd->right_weapon.addrace[RC_DRAGON]+=skill;
  3887. if( !battle_config.left_cardfix_to_right ){
  3888. sd->left_weapon.addrace[RC_DRAGON] += skill;
  3889. }
  3890. sd->indexed_bonus.magic_addrace[RC_DRAGON]+=dragon_matk;
  3891. sd->indexed_bonus.subrace[RC_DRAGON]+=skill;
  3892. }
  3893. if ((skill = pc_checkskill(sd, AB_EUCHARISTICA)) > 0) {
  3894. sd->right_weapon.addrace[RC_DEMON] += skill;
  3895. sd->right_weapon.addele[ELE_DARK] += skill;
  3896. if( !battle_config.left_cardfix_to_right ){
  3897. sd->left_weapon.addrace[RC_DEMON] += skill;
  3898. sd->left_weapon.addele[ELE_DARK] += skill;
  3899. }
  3900. sd->indexed_bonus.magic_addrace[RC_DEMON] += skill;
  3901. sd->indexed_bonus.magic_addele[ELE_DARK] += skill;
  3902. sd->indexed_bonus.subrace[RC_DEMON] += skill;
  3903. sd->indexed_bonus.subele[ELE_DARK] += skill;
  3904. }
  3905. if ((skill = pc_checkskill(sd, DK_TWOHANDDEF)) > 0 && (sd->status.weapon == W_2HSWORD || sd->status.weapon == W_2HSPEAR || sd->status.weapon == W_2HAXE)) {
  3906. uint8 defense_bonus[SZ_MAX][10] = {
  3907. { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL
  3908. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3909. { 3, 5, 7, 9, 10, 12, 13, 15, 16, 18 }, // SZ_BIG
  3910. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3911. };
  3912. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3913. sd->indexed_bonus.weapon_subsize[size] += defense_bonus[size][skill - 1];
  3914. }
  3915. }
  3916. if ((skill = pc_checkskill(sd, IQ_WILL_OF_FAITH)) > 0 && sd->status.weapon == W_KNUCKLE) {
  3917. uint8 race_atk[10] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
  3918. uint8 race_def[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  3919. sd->right_weapon.addrace[RC_UNDEAD] += race_atk[skill - 1];
  3920. sd->right_weapon.addrace[RC_DEMON] += race_atk[skill - 1];
  3921. if( !battle_config.left_cardfix_to_right ){
  3922. sd->left_weapon.addrace[RC_UNDEAD] += race_atk[skill - 1];
  3923. sd->left_weapon.addrace[RC_DEMON] += race_atk[skill - 1];
  3924. }
  3925. sd->indexed_bonus.subrace[RC_UNDEAD] += race_def[skill - 1];
  3926. sd->indexed_bonus.subrace[RC_DEMON] += race_def[skill - 1];
  3927. }
  3928. if ((skill = pc_checkskill(sd, CD_MACE_BOOK_M)) > 0 && (sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE || sd->status.weapon == W_BOOK)) {
  3929. uint8 attack_bonus[SZ_MAX][10] = {
  3930. { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL
  3931. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3932. { 3, 5, 7, 9, 10, 12, 13, 15, 16, 18 }, // SZ_BIG
  3933. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3934. };
  3935. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3936. sd->right_weapon.addsize[size] += attack_bonus[size][skill - 1];
  3937. if( !battle_config.left_cardfix_to_right ){
  3938. sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1];
  3939. }
  3940. }
  3941. }
  3942. if ((skill = pc_checkskill(sd, CD_FIDUS_ANIMUS)) > 0) {
  3943. uint8 holy_matk[10] = { 1, 3, 4, 6, 7, 9, 10, 12, 13, 15 };
  3944. sd->indexed_bonus.magic_atk_ele[ELE_HOLY] += holy_matk[skill - 1];
  3945. }
  3946. if ((skill = pc_checkskill(sd, MT_TWOAXEDEF)) > 0 && sd->status.weapon == W_2HAXE) {
  3947. uint8 defense_bonus[SZ_MAX][10] = {
  3948. { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL
  3949. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3950. { 3, 5, 7, 9, 10, 12, 13, 15, 16, 18 }, // SZ_BIG
  3951. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3952. };
  3953. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3954. sd->indexed_bonus.weapon_subsize[size] += defense_bonus[size][skill - 1];
  3955. }
  3956. }
  3957. if ((skill = pc_checkskill(sd, ABC_DAGGER_AND_BOW_M)) > 0 && (sd->status.weapon == W_DAGGER || sd->status.weapon == W_BOW || sd->status.weapon == W_DOUBLE_DD || sd->status.weapon == W_DOUBLE_DS || sd->status.weapon == W_DOUBLE_DA)) {
  3958. uint8 attack_bonus[SZ_MAX][10] = {
  3959. { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL
  3960. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3961. { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }, // SZ_BIG
  3962. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3963. };
  3964. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3965. sd->right_weapon.addsize[size] += attack_bonus[size][skill - 1];
  3966. if( !battle_config.left_cardfix_to_right ){
  3967. sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1];
  3968. }
  3969. }
  3970. }
  3971. if ((skill = pc_checkskill(sd, ABC_MAGIC_SWORD_M)) > 0 && (sd->status.weapon == W_DAGGER || sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DOUBLE_DD || sd->status.weapon == W_DOUBLE_SS || sd->status.weapon == W_DOUBLE_DS || sd->status.weapon == W_DOUBLE_DA || sd->status.weapon == W_DOUBLE_SA)) {
  3972. uint8 attack_bonus[SZ_MAX][10] = {
  3973. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_SMALL
  3974. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3975. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_BIG
  3976. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3977. };
  3978. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3979. sd->indexed_bonus.magic_addsize[size] += attack_bonus[size][skill - 1];
  3980. }
  3981. }
  3982. if ((skill = pc_checkskill(sd, EM_MAGIC_BOOK_M)) > 0 && sd->status.weapon == W_BOOK) {
  3983. sd->indexed_bonus.magic_atk_ele[ELE_WATER] += skill;
  3984. sd->indexed_bonus.magic_atk_ele[ELE_EARTH] += skill;
  3985. sd->indexed_bonus.magic_atk_ele[ELE_FIRE] += skill;
  3986. sd->indexed_bonus.magic_atk_ele[ELE_WIND] += skill;
  3987. sd->indexed_bonus.magic_atk_ele[ELE_POISON] += skill;
  3988. }
  3989. if(!sc->empty()) {
  3990. if(sc->getSCE(SC_CONCENTRATE)) { // Update the card-bonus data
  3991. sc->getSCE(SC_CONCENTRATE)->val3 = sd->indexed_bonus.param_bonus[1]; // Agi
  3992. sc->getSCE(SC_CONCENTRATE)->val4 = sd->indexed_bonus.param_bonus[4]; // Dex
  3993. }
  3994. if(sc->getSCE(SC_SIEGFRIED)) {
  3995. i = sc->getSCE(SC_SIEGFRIED)->val2;
  3996. sd->indexed_bonus.subele[ELE_WATER] += i;
  3997. sd->indexed_bonus.subele[ELE_EARTH] += i;
  3998. sd->indexed_bonus.subele[ELE_FIRE] += i;
  3999. sd->indexed_bonus.subele[ELE_WIND] += i;
  4000. #ifndef RENEWAL
  4001. sd->indexed_bonus.subele[ELE_POISON] += i;
  4002. sd->indexed_bonus.subele[ELE_HOLY] += i;
  4003. sd->indexed_bonus.subele[ELE_DARK] += i;
  4004. sd->indexed_bonus.subele[ELE_GHOST] += i;
  4005. sd->indexed_bonus.subele[ELE_UNDEAD] += i;
  4006. #endif
  4007. }
  4008. #ifdef RENEWAL
  4009. if (sc->getSCE(SC_BASILICA)) {
  4010. i = sc->getSCE(SC_BASILICA)->val1 * 5;
  4011. sd->right_weapon.addele[ELE_DARK] += i;
  4012. sd->right_weapon.addele[ELE_UNDEAD] += i;
  4013. if( !battle_config.left_cardfix_to_right ){
  4014. sd->left_weapon.addele[ELE_DARK] += i;
  4015. sd->left_weapon.addele[ELE_UNDEAD] += i;
  4016. }
  4017. sd->indexed_bonus.magic_atk_ele[ELE_HOLY] += sc->getSCE(SC_BASILICA)->val1 * 3;
  4018. }
  4019. if (sc->getSCE(SC_FIREWEAPON))
  4020. sd->indexed_bonus.magic_atk_ele[ELE_FIRE] += sc->getSCE(SC_FIREWEAPON)->val1;
  4021. if (sc->getSCE(SC_WINDWEAPON))
  4022. sd->indexed_bonus.magic_atk_ele[ELE_WIND] += sc->getSCE(SC_WINDWEAPON)->val1;
  4023. if (sc->getSCE(SC_WATERWEAPON))
  4024. sd->indexed_bonus.magic_atk_ele[ELE_WATER] += sc->getSCE(SC_WATERWEAPON)->val1;
  4025. if (sc->getSCE(SC_EARTHWEAPON))
  4026. sd->indexed_bonus.magic_atk_ele[ELE_EARTH] += sc->getSCE(SC_EARTHWEAPON)->val1;
  4027. #endif
  4028. if(sc->getSCE(SC_PROVIDENCE)) {
  4029. sd->indexed_bonus.subele[ELE_HOLY] += sc->getSCE(SC_PROVIDENCE)->val2;
  4030. sd->indexed_bonus.subrace[RC_DEMON] += sc->getSCE(SC_PROVIDENCE)->val2;
  4031. }
  4032. if( sc->getSCE(SC_FIRE_CLOAK_OPTION) ) {
  4033. i = sc->getSCE(SC_FIRE_CLOAK_OPTION)->val2;
  4034. sd->indexed_bonus.subele[ELE_FIRE] += i;
  4035. sd->indexed_bonus.subele[ELE_WATER] -= i;
  4036. }
  4037. if( sc->getSCE(SC_WATER_DROP_OPTION) ) {
  4038. i = sc->getSCE(SC_WATER_DROP_OPTION)->val2;
  4039. sd->indexed_bonus.subele[ELE_WATER] += i;
  4040. sd->indexed_bonus.subele[ELE_WIND] -= i;
  4041. }
  4042. if( sc->getSCE(SC_WIND_CURTAIN_OPTION) ) {
  4043. i = sc->getSCE(SC_WIND_CURTAIN_OPTION)->val2;
  4044. sd->indexed_bonus.subele[ELE_WIND] += i;
  4045. sd->indexed_bonus.subele[ELE_EARTH] -= i;
  4046. }
  4047. if( sc->getSCE(SC_STONE_SHIELD_OPTION) ) {
  4048. i = sc->getSCE(SC_STONE_SHIELD_OPTION)->val2;
  4049. sd->indexed_bonus.subele[ELE_EARTH] += i;
  4050. sd->indexed_bonus.subele[ELE_FIRE] -= i;
  4051. }
  4052. if (sc->getSCE(SC_LAUDARAMUS))
  4053. sd->bonus.crit_atk_rate += 5 * sc->getSCE(SC_LAUDARAMUS)->val1;
  4054. #ifdef RENEWAL
  4055. if (sc->getSCE(SC_FORTUNE))
  4056. sd->bonus.crit_atk_rate += 2 * sc->getSCE(SC_FORTUNE)->val1;
  4057. #endif
  4058. if (sc->getSCE(SC_SYMPHONYOFLOVER)) {
  4059. sd->indexed_bonus.subele[ELE_GHOST] += sc->getSCE(SC_SYMPHONYOFLOVER)->val1 * 3;
  4060. sd->indexed_bonus.subele[ELE_HOLY] += sc->getSCE(SC_SYMPHONYOFLOVER)->val1 * 3;
  4061. }
  4062. if (sc->getSCE(SC_PYREXIA) && sc->getSCE(SC_PYREXIA)->val3 == 0)
  4063. sd->bonus.crit_atk_rate += sc->getSCE(SC_PYREXIA)->val2;
  4064. if (sc->getSCE(SC_LUXANIMA)) {
  4065. pc_bonus2(sd, SP_ADDSIZE, SZ_ALL, sc->getSCE(SC_LUXANIMA)->val3);
  4066. sd->bonus.crit_atk_rate += sc->getSCE(SC_LUXANIMA)->val3;
  4067. sd->bonus.short_attack_atk_rate += sc->getSCE(SC_LUXANIMA)->val3;
  4068. sd->bonus.long_attack_atk_rate += sc->getSCE(SC_LUXANIMA)->val3;
  4069. }
  4070. if (sc->getSCE(SC_STRIKING))
  4071. sd->bonus.perfect_hit += 20 + 10 * pc_checkskill(sd, SO_STRIKING);
  4072. if( sc->getSCE( SC_RUSH_QUAKE2 ) ){
  4073. sd->bonus.short_attack_atk_rate += 5 * sc->getSCE( SC_RUSH_QUAKE2 )->val1;
  4074. sd->bonus.long_attack_atk_rate += 5 * sc->getSCE( SC_RUSH_QUAKE2 )->val1;
  4075. }
  4076. if (sc->getSCE(SC_HIDDEN_CARD))
  4077. sd->bonus.long_attack_atk_rate += sc->getSCE(SC_HIDDEN_CARD)->val3;
  4078. if (sc->getSCE(SC_DEADLY_DEFEASANCE))
  4079. sd->special_state.no_magic_damage = 0;
  4080. if (sc->getSCE(SC_CLIMAX_DES_HU))
  4081. sd->indexed_bonus.magic_atk_ele[ELE_WIND] += 30;
  4082. if (sc->getSCE(SC_CLIMAX_CRYIMP)) {
  4083. sd->indexed_bonus.subele[ELE_WATER] += 30;
  4084. sd->indexed_bonus.magic_atk_ele[ELE_WATER] += 30;
  4085. }
  4086. if (sc->getSCE(SC_SINCERE_FAITH))
  4087. sd->bonus.perfect_hit += sc->getSCE(SC_SINCERE_FAITH)->val3;
  4088. if (sc->getSCE(SC_HOLY_S)) {
  4089. sd->indexed_bonus.subele[ELE_DARK] += sc->getSCE(SC_HOLY_S)->val2;
  4090. sd->indexed_bonus.subele[ELE_UNDEAD] += sc->getSCE(SC_HOLY_S)->val2;
  4091. sd->indexed_bonus.magic_atk_ele[ELE_HOLY] += sc->getSCE(SC_HOLY_S)->val2;
  4092. }
  4093. if (sc->getSCE(SC_SUMMON_ELEMENTAL_ARDOR))
  4094. sd->indexed_bonus.magic_atk_ele[ELE_FIRE] += 10;
  4095. if (sc->getSCE(SC_SUMMON_ELEMENTAL_DILUVIO))
  4096. sd->indexed_bonus.magic_atk_ele[ELE_WATER] += 10;
  4097. if (sc->getSCE(SC_SUMMON_ELEMENTAL_PROCELLA))
  4098. sd->indexed_bonus.magic_atk_ele[ELE_WIND] += 10;
  4099. if (sc->getSCE(SC_SUMMON_ELEMENTAL_TERREMOTUS))
  4100. sd->indexed_bonus.magic_atk_ele[ELE_EARTH] += 10;
  4101. if (sc->getSCE(SC_SUMMON_ELEMENTAL_SERPENS))
  4102. sd->indexed_bonus.magic_atk_ele[ELE_POISON] += 10;
  4103. if (sc->getSCE(SC_FLAMEARMOR_OPTION)) {
  4104. sd->indexed_bonus.subele[ELE_FIRE] += 100;
  4105. sd->indexed_bonus.subele[ELE_WATER] -= 30;
  4106. }
  4107. if (sc->getSCE(SC_CRYSTAL_ARMOR_OPTION)) {
  4108. sd->indexed_bonus.subele[ELE_WATER] += 100;
  4109. sd->indexed_bonus.subele[ELE_WIND] -= 30;
  4110. }
  4111. if (sc->getSCE(SC_EYES_OF_STORM_OPTION)) {
  4112. sd->indexed_bonus.subele[ELE_WIND] += 100;
  4113. sd->indexed_bonus.subele[ELE_EARTH] -= 30;
  4114. }
  4115. if (sc->getSCE(SC_STRONG_PROTECTION_OPTION)) {
  4116. sd->indexed_bonus.subele[ELE_EARTH] += 100;
  4117. sd->indexed_bonus.subele[ELE_FIRE] -= 30;
  4118. }
  4119. if (sc->getSCE(SC_POISON_SHIELD_OPTION)) {
  4120. sd->indexed_bonus.subele[ELE_POISON] += 100;
  4121. sd->indexed_bonus.subele[ELE_HOLY] -= 30;
  4122. }
  4123. if (pc_checkskill(sd, SU_POWEROFLAND) > 0 && pc_checkskill_summoner(sd, SUMMONER_POWER_LAND) >= 20)
  4124. pc_bonus(sd, SP_MATK_RATE, 20);
  4125. if (sc->getSCE(SC_SHRIMP)) {
  4126. pc_bonus(sd, SP_ATK_RATE, sc->getSCE(SC_SHRIMP)->val2);
  4127. pc_bonus(sd, SP_MATK_RATE, sc->getSCE(SC_SHRIMP)->val2);
  4128. }
  4129. if (sc->getSCE(SC_INCMATKRATE))
  4130. pc_bonus(sd, SP_MATK_RATE, sc->getSCE(SC_INCMATKRATE)->val1);
  4131. if (sc->getSCE(SC_MINDBREAKER))
  4132. pc_bonus(sd, SP_MATK_RATE, sc->getSCE(SC_MINDBREAKER)->val2);
  4133. if (sc->getSCE(SC_CATNIPPOWDER))
  4134. pc_bonus(sd, SP_MATK_RATE, sc->getSCE(SC_CATNIPPOWDER)->val2);
  4135. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_MATKRATE)
  4136. pc_bonus(sd, SP_MATK_RATE, 20);
  4137. if( sc->getSCE(SC_TALISMAN_OF_FIVE_ELEMENTS) != nullptr ) {
  4138. const std::vector<e_element> elements = { ELE_FIRE, ELE_WATER, ELE_WIND, ELE_EARTH, ELE_NEUTRAL };
  4139. int32 bonus = sc->getSCE(SC_TALISMAN_OF_FIVE_ELEMENTS)->val2;
  4140. for( const auto &element : elements ){
  4141. sd->indexed_bonus.magic_addele[element] += bonus;
  4142. sd->right_weapon.addele[element] += bonus;
  4143. if( !battle_config.left_cardfix_to_right ){
  4144. sd->left_weapon.addele[element] += bonus;
  4145. }
  4146. }
  4147. }
  4148. if( sc->getSCE(SC_HEAVEN_AND_EARTH) != nullptr ) {
  4149. i = sc->getSCE(SC_HEAVEN_AND_EARTH)->val2;
  4150. sd->indexed_bonus.magic_atk_ele[ELE_ALL] += i;
  4151. sd->bonus.short_attack_atk_rate += i;
  4152. sd->bonus.long_attack_atk_rate += i;
  4153. }
  4154. }
  4155. status_cpy(&sd->battle_status, base_status);
  4156. // ----- CLIENT-SIDE REFRESH -----
  4157. if(!sd->bl.prev) {
  4158. // Will update on LoadEndAck
  4159. calculating = 0;
  4160. return 0;
  4161. }
  4162. if(memcmp(b_skill,sd->status.skill,sizeof(sd->status.skill))) {
  4163. #if PACKETVER_MAIN_NUM >= 20190807 || PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190918
  4164. // Client doesn't delete unavailable skills even if we refresh the skill tree, individually delete them.
  4165. for (i = 0; i < MAX_SKILL; i++) {
  4166. if (b_skill[i].id != 0 && sd->status.skill[i].id == 0)
  4167. clif_deleteskill(*sd, b_skill[i].id, true);
  4168. }
  4169. #endif
  4170. clif_skillinfoblock(sd);
  4171. }
  4172. // If the skill is learned, the status is infinite.
  4173. if (pc_checkskill(sd, SU_SPRITEMABLE) > 0 && !sd->sc.getSCE(SC_SPRITEMABLE))
  4174. sc_start(&sd->bl, &sd->bl, SC_SPRITEMABLE, 100, 1, INFINITE_TICK);
  4175. if (pc_checkskill(sd, SU_SOULATTACK) > 0 && !sd->sc.getSCE(SC_SOULATTACK))
  4176. sc_start(&sd->bl, &sd->bl, SC_SOULATTACK, 100, 1, INFINITE_TICK);
  4177. calculating = 0;
  4178. return 0;
  4179. }
  4180. /// Intermediate function since C++ does not have a try-finally syntax
  4181. int32 status_calc_pc_( map_session_data* sd, uint8 opt ){
  4182. // Save the old script the player was attached to
  4183. struct script_state* previous_st = sd->st;
  4184. // Store the return value of the original function
  4185. int32 ret = status_calc_pc_sub( sd, opt );
  4186. // If an old script is present
  4187. if( previous_st ){
  4188. // Reattach the player to it, so that the limitations of that script kick back in
  4189. script_attach_state( previous_st );
  4190. }
  4191. // Return the original return value
  4192. return ret;
  4193. }
  4194. /**
  4195. * Calculates Mercenary data
  4196. * @param md: Mercenary object
  4197. * @param opt: Whether it is first calc or not (0 on level up or status)
  4198. * @return 0
  4199. */
  4200. int32 status_calc_mercenary_(s_mercenary_data *md, uint8 opt)
  4201. {
  4202. struct status_data *status = &md->base_status;
  4203. s_mercenary *merc = &md->mercenary;
  4204. if (opt&SCO_FIRST) {
  4205. memcpy(status, &md->db->status, sizeof(struct status_data));
  4206. status->class_ = CLASS_NORMAL;
  4207. status->mode = static_cast<e_mode>(MD_CANMOVE|MD_CANATTACK);
  4208. status->hp = status->max_hp;
  4209. status->sp = status->max_sp;
  4210. md->battle_status.hp = merc->hp;
  4211. md->battle_status.sp = merc->sp;
  4212. if (md->master)
  4213. status->speed = status_get_speed(&md->master->bl);
  4214. }
  4215. status_calc_misc(&md->bl, status, md->db->lv);
  4216. status_cpy(&md->battle_status, status);
  4217. return 0;
  4218. }
  4219. /**
  4220. * Calculates Homunculus data
  4221. * @param hd: Homunculus object
  4222. * @param opt: Whether it is first calc or not (0 on level up or status)
  4223. * @return 1
  4224. */
  4225. int32 status_calc_homunculus_(struct homun_data *hd, uint8 opt)
  4226. {
  4227. struct status_data *status = &hd->base_status;
  4228. struct s_homunculus &hom = hd->homunculus;
  4229. int32 skill_lv;
  4230. int32 amotion;
  4231. status->str = hom.str / 10;
  4232. status->agi = hom.agi / 10;
  4233. status->vit = hom.vit / 10;
  4234. status->dex = hom.dex / 10;
  4235. status->int_ = hom.int_ / 10;
  4236. status->luk = hom.luk / 10;
  4237. APPLY_HOMUN_LEVEL_STATWEIGHT();
  4238. if (opt&SCO_FIRST) {
  4239. const std::shared_ptr<s_homunculus_db> db = hd->homunculusDB;
  4240. status->def_ele = db->element;
  4241. status->ele_lv = 1;
  4242. status->race = db->race;
  4243. status->class_ = CLASS_NORMAL;
  4244. status->size = (hom.class_ == db->evo_class) ? db->evo_size : db->base_size;
  4245. status->rhw.range = 1 + status->size;
  4246. status->mode = static_cast<e_mode>(MD_CANMOVE|MD_CANATTACK);
  4247. status->speed = DEFAULT_WALK_SPEED;
  4248. if (battle_config.hom_setting&HOMSET_COPY_SPEED && hd->master)
  4249. status->speed = status_get_speed(&hd->master->bl);
  4250. status->hp = 1;
  4251. status->sp = 1;
  4252. }
  4253. status->aspd_rate = 1000;
  4254. #ifdef RENEWAL
  4255. amotion = hd->homunculusDB->baseASPD;
  4256. amotion = amotion - amotion * (status->dex + hom.dex_value) / 1000 - (status->agi + hom.agi_value) * amotion / 250;
  4257. status->def = status->mdef = 0;
  4258. #else
  4259. skill_lv = hom.level / 10 + status->vit / 5;
  4260. status->def = cap_value(skill_lv, 0, 99);
  4261. skill_lv = hom.level / 10 + status->int_ / 5;
  4262. status->mdef = cap_value(skill_lv, 0, 99);
  4263. amotion = (1000 - 4 * status->agi - status->dex) * hd->homunculusDB->baseASPD / 1000;
  4264. #endif
  4265. status->amotion = cap_value(amotion, battle_config.max_aspd, 2000);
  4266. status->adelay = status->amotion; //It seems adelay = amotion for Homunculus.
  4267. status->max_hp = hom.max_hp;
  4268. status->max_sp = hom.max_sp;
  4269. hom_calc_skilltree(hd);
  4270. if((skill_lv = hom_checkskill(hd, HAMI_SKIN)) > 0)
  4271. status->def += skill_lv * 4;
  4272. if((skill_lv = hom_checkskill(hd, HVAN_INSTRUCT)) > 0) {
  4273. static const uint8 bonus_int[] = { 1, 2, 2, 4, 5 };
  4274. static const uint8 bonus_str[] = { 1, 1, 3, 4, 4 };
  4275. status->int_ += bonus_int[skill_lv - 1];
  4276. status->str += bonus_str[skill_lv - 1];
  4277. }
  4278. if((skill_lv = hom_checkskill(hd, HAMI_SKIN)) > 0)
  4279. status->max_hp += skill_lv * 2 * status->max_hp / 100;
  4280. if((skill_lv = hom_checkskill(hd, HLIF_BRAIN)) > 0)
  4281. status->max_sp += skill_lv * status->max_sp / 100;
  4282. if((skill_lv = hom_checkskill(hd, MH_CLASSY_FLUTTER)) > 0) {
  4283. status->matk_min += 100 + 60* skill_lv;
  4284. status->matk_max += 100 + 60* skill_lv;
  4285. }
  4286. if((skill_lv = hom_checkskill(hd, MH_BRUSHUP_CLAW)) > 0) {
  4287. status->batk += 100 + 60* skill_lv;
  4288. }
  4289. if((skill_lv = hom_checkskill(hd, MH_POLISHING_NEEDLE)) > 0) {
  4290. status->matk_min += 50 + 20* skill_lv;
  4291. status->matk_max += 50 + 20* skill_lv;
  4292. status->batk += 100 + 40* skill_lv;
  4293. }
  4294. if((skill_lv = hom_checkskill(hd, MH_LICHT_GEHORN)) > 0) {
  4295. status->matk_min += 100 + 30* skill_lv;
  4296. status->matk_max += 100 + 30* skill_lv;
  4297. status->batk += 100 + 30* skill_lv;
  4298. }
  4299. if((skill_lv = hom_checkskill(hd, MH_BLAZING_LAVA)) > 0) {
  4300. status->batk += 100 + 60* skill_lv;
  4301. }
  4302. if (opt&SCO_FIRST) {
  4303. hd->battle_status.hp = hom.hp;
  4304. hd->battle_status.sp = hom.sp;
  4305. if(hom.class_ == 6052) // Eleanor
  4306. sc_start(&hd->bl,&hd->bl, SC_STYLE_CHANGE, 100, MH_MD_FIGHTING, INFINITE_TICK);
  4307. }
  4308. #ifndef RENEWAL
  4309. status->rhw.atk = status->dex;
  4310. status->rhw.atk2 = status->str + hom.level;
  4311. #endif
  4312. status_calc_misc(&hd->bl, status, hom.level);
  4313. status_cpy(&hd->battle_status, status);
  4314. return 1;
  4315. }
  4316. /**
  4317. * Calculates Elemental data
  4318. * @param ed: Elemental object
  4319. * @param opt: Whether it is first calc or not (0 on status change)
  4320. * @return 0
  4321. */
  4322. int32 status_calc_elemental_(s_elemental_data *ed, uint8 opt)
  4323. {
  4324. struct status_data *status = &ed->base_status;
  4325. s_elemental *ele = &ed->elemental;
  4326. map_session_data *sd = ed->master;
  4327. if( !sd )
  4328. return 0;
  4329. if (opt&SCO_FIRST) {
  4330. memcpy(status, &ed->db->status, sizeof(struct status_data));
  4331. if( !ele->mode )
  4332. status->mode = EL_MODE_PASSIVE;
  4333. else
  4334. status->mode = ele->mode;
  4335. status->class_ = CLASS_NORMAL;
  4336. status_calc_misc(&ed->bl, status, 0);
  4337. status->max_hp = ele->max_hp;
  4338. status->max_sp = ele->max_sp;
  4339. status->hp = ele->hp;
  4340. status->sp = ele->sp;
  4341. status->rhw.atk = ele->atk;
  4342. status->rhw.atk2 = ele->atk2;
  4343. status->matk_min += ele->matk;
  4344. status->def += ele->def;
  4345. status->mdef += ele->mdef;
  4346. status->flee = ele->flee;
  4347. status->hit = ele->hit;
  4348. if (ed->master)
  4349. status->speed = status_get_speed(&ed->master->bl);
  4350. memcpy(&ed->battle_status,status,sizeof(struct status_data));
  4351. } else {
  4352. status_calc_misc(&ed->bl, status, 0);
  4353. status_cpy(&ed->battle_status, status);
  4354. }
  4355. return 0;
  4356. }
  4357. /**
  4358. * Calculates NPC data
  4359. * @param nd: NPC object
  4360. * @param opt: Whether it is first calc or not (what?)
  4361. * @return 0
  4362. */
  4363. int32 status_calc_npc_(struct npc_data *nd, uint8 opt)
  4364. {
  4365. struct status_data *status = &nd->status;
  4366. if (!nd)
  4367. return 0;
  4368. if (opt&SCO_FIRST) {
  4369. status->hp = 1;
  4370. status->sp = 1;
  4371. status->max_hp = 1;
  4372. status->max_sp = 1;
  4373. status->def_ele = ELE_NEUTRAL;
  4374. status->ele_lv = 1;
  4375. status->race = RC_DEMIHUMAN;
  4376. status->class_ = CLASS_NORMAL;
  4377. status->size = nd->size;
  4378. status->rhw.range = 1 + status->size;
  4379. status->mode = static_cast<e_mode>(MD_CANMOVE|MD_CANATTACK);
  4380. status->speed = nd->speed;
  4381. }
  4382. status->str = nd->stat_point + nd->params.str;
  4383. status->agi = nd->stat_point + nd->params.agi;
  4384. status->vit = nd->stat_point + nd->params.vit;
  4385. status->int_= nd->stat_point + nd->params.int_;
  4386. status->dex = nd->stat_point + nd->params.dex;
  4387. status->luk = nd->stat_point + nd->params.luk;
  4388. status_calc_misc(&nd->bl, status, nd->level);
  4389. status_cpy(&nd->status, status);
  4390. return 0;
  4391. }
  4392. /**
  4393. * Calculates regeneration values
  4394. * Applies passive skill regeneration additions
  4395. * @param bl: Object to calculate regen for [PC|HOM|MER|ELEM]
  4396. * @param status: Object's status
  4397. * @param regen: Object's base regeneration data
  4398. */
  4399. void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen)
  4400. {
  4401. map_session_data *sd;
  4402. status_change *sc;
  4403. int32 val, skill, reg_flag;
  4404. if( !(bl->type&BL_REGEN) || !regen )
  4405. return;
  4406. sd = BL_CAST(BL_PC,bl);
  4407. sc = status_get_sc(bl);
  4408. val = (status->vit/5) + max(1, status->max_hp/200);
  4409. if( sd && sd->hprecov_rate != 100 )
  4410. val = val*sd->hprecov_rate/100;
  4411. reg_flag = bl->type == BL_PC ? 0 : 1;
  4412. regen->hp = cap_value(val, reg_flag, SHRT_MAX);
  4413. val = 1 + (status->int_/6) + (status->max_sp/100);
  4414. if( status->int_ >= 120 )
  4415. val += ((status->int_-120) / 2) + 4;
  4416. if( sd && sd->sprecov_rate != 100 )
  4417. val = val*sd->sprecov_rate/100;
  4418. regen->sp = cap_value(val, reg_flag, SHRT_MAX);
  4419. if( sd ) {
  4420. struct regen_data_sub *sregen;
  4421. if( (skill=pc_checkskill(sd,HP_MEDITATIO)) > 0 ) {
  4422. val = regen->sp*(100+3*skill)/100;
  4423. regen->sp = cap_value(val, 1, SHRT_MAX);
  4424. }
  4425. // Only players have skill/sitting skill regen for now.
  4426. sregen = regen->sregen;
  4427. val = 0;
  4428. if( (skill=pc_checkskill(sd,SM_RECOVERY)) > 0 )
  4429. val += skill*5 + skill*status->max_hp/500;
  4430. sregen->hp = cap_value(val, 0, SHRT_MAX);
  4431. val = 0;
  4432. if( (skill=pc_checkskill(sd,MG_SRECOVERY)) > 0 )
  4433. val += skill*3 + skill*status->max_sp/500;
  4434. if( (skill=pc_checkskill(sd,NJ_NINPOU)) > 0 )
  4435. val += skill*3 + skill*status->max_sp/500;
  4436. if( (skill=pc_checkskill(sd,WM_LESSON)) > 0 )
  4437. val += 3 + 3 * skill;
  4438. if (sc != nullptr && !sc->empty()) {
  4439. if (sc->getSCE(SC_ANCILLA))
  4440. val += sc->getSCE(SC_ANCILLA)->val2 / 100;
  4441. }
  4442. sregen->sp = cap_value(val, 0, SHRT_MAX);
  4443. // Skill-related recovery (only when sit)
  4444. sregen = regen->ssregen;
  4445. val = 0;
  4446. if( (skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0 )
  4447. val += skill*4 + skill*status->max_hp/500;
  4448. if( (skill=pc_checkskill(sd,TK_HPTIME)) > 0 && sd->state.rest )
  4449. val += skill*30 + skill*status->max_hp/500;
  4450. sregen->hp = cap_value(val, 0, SHRT_MAX);
  4451. val = 0;
  4452. if( (skill=pc_checkskill(sd,TK_SPTIME)) > 0 && sd->state.rest ) {
  4453. val += skill*3 + skill*status->max_sp/500;
  4454. if ((skill=pc_checkskill(sd,SL_KAINA)) > 0) // Power up Enjoyable Rest
  4455. val += (30+10*skill)*val/100;
  4456. }
  4457. if( (skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0 )
  4458. val += skill*2 + skill*status->max_sp/500;
  4459. sregen->sp = cap_value(val, 0, SHRT_MAX);
  4460. }
  4461. if( bl->type == BL_HOM ) {
  4462. struct homun_data *hd = (TBL_HOM*)bl;
  4463. if( (skill = hom_checkskill(hd,HAMI_SKIN)) > 0 ) {
  4464. val = regen->hp*(100+5*skill)/100;
  4465. regen->hp = cap_value(val, 1, SHRT_MAX);
  4466. }
  4467. if( (skill = hom_checkskill(hd,HLIF_BRAIN)) > 0 ) {
  4468. val = regen->sp*(100+3*skill)/100;
  4469. regen->sp = cap_value(val, 1, SHRT_MAX);
  4470. }
  4471. } else if( bl->type == BL_MER ) {
  4472. val = static_cast<decltype(val)>((status->max_hp * status->vit / 10000.0 + 1.0) * 6.0);
  4473. regen->hp = cap_value(val, 1, SHRT_MAX);
  4474. val = static_cast<decltype(val)>((status->max_sp * (status->int_ + 10.0) / 750.0) + 1.0);
  4475. regen->sp = cap_value(val, 1, SHRT_MAX);
  4476. } else if( bl->type == BL_ELEM ) {
  4477. val = static_cast<decltype(val)>((status->max_hp * status->vit / 10000.0 + 1.0) * 6.0);
  4478. regen->hp = cap_value(val, 1, SHRT_MAX);
  4479. val = static_cast<decltype(val)>((status->max_sp * (status->int_ + 10.0) / 750.0) + 1.0);
  4480. regen->sp = cap_value(val, 1, SHRT_MAX);
  4481. }
  4482. }
  4483. /**
  4484. * Calculates SC (Status Changes) regeneration values
  4485. * @param bl: Object to calculate regen for [PC|HOM|MER|ELEM]
  4486. * @param regen: Object's base regeneration data
  4487. * @param sc: Object's status change data
  4488. */
  4489. void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, status_change *sc)
  4490. {
  4491. if (!(bl->type&BL_REGEN) || !regen)
  4492. return;
  4493. regen->flag = RGN_HP|RGN_SP;
  4494. if(regen->sregen) {
  4495. if (regen->sregen->hp)
  4496. regen->flag |= RGN_SHP;
  4497. if (regen->sregen->sp)
  4498. regen->flag |= RGN_SSP;
  4499. regen->sregen->rate.hp = regen->sregen->rate.sp = 100;
  4500. }
  4501. if (regen->ssregen) {
  4502. if (regen->ssregen->hp)
  4503. regen->flag |= RGN_SHP;
  4504. if (regen->ssregen->sp)
  4505. regen->flag |= RGN_SSP;
  4506. regen->ssregen->rate.hp = regen->ssregen->rate.sp = 100;
  4507. }
  4508. regen->rate.hp = regen->rate.sp = 100;
  4509. if (sc == nullptr || sc->empty())
  4510. return;
  4511. // No HP or SP regen
  4512. if ((sc->getSCE(SC_POISON) && !sc->getSCE(SC_SLOWPOISON))
  4513. || (sc->getSCE(SC_DPOISON) && !sc->getSCE(SC_SLOWPOISON))
  4514. || sc->getSCE(SC_BERSERK)
  4515. || sc->getSCE(SC_TRICKDEAD)
  4516. || sc->getSCE(SC_BLEEDING)
  4517. || (sc->getSCE(SC_MAGICMUSHROOM) && sc->getSCE(SC_MAGICMUSHROOM)->val3 == 1)
  4518. || sc->getSCE(SC_SATURDAYNIGHTFEVER)
  4519. || sc->getSCE(SC_REBOUND)
  4520. || sc->getSCE(SC_NORECOVER_STATE))
  4521. regen->flag = RGN_NONE;
  4522. // No natural SP regen
  4523. if (sc->getSCE(SC_DANCING) ||
  4524. #ifdef RENEWAL
  4525. sc->getSCE(SC_MAXIMIZEPOWER) ||
  4526. #endif
  4527. #ifndef RENEWAL
  4528. (bl->type == BL_PC && (((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK &&
  4529. (sc->getSCE(SC_EXTREMITYFIST) || sc->getSCE(SC_EXPLOSIONSPIRITS)) && (!sc->getSCE(SC_SPIRIT) || sc->getSCE(SC_SPIRIT)->val2 != SL_MONK)) ||
  4530. #else
  4531. (bl->type == BL_PC && (((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK &&
  4532. sc->getSCE(SC_EXTREMITYFIST) && (!sc->getSCE(SC_SPIRIT) || sc->getSCE(SC_SPIRIT)->val2 != SL_MONK)) ||
  4533. #endif
  4534. (sc->getSCE(SC_OBLIVIONCURSE) && sc->getSCE(SC_OBLIVIONCURSE)->val3 == 1))
  4535. regen->flag &= ~RGN_SP;
  4536. if (sc->getSCE(SC_TENSIONRELAX)) {
  4537. if (sc->getSCE(SC_WEIGHT50) || sc->getSCE(SC_WEIGHT90))
  4538. regen->state.overweight = 0; // 1x HP regen
  4539. else {
  4540. regen->rate.hp += 200;
  4541. if (regen->sregen)
  4542. regen->sregen->rate.hp += 200;
  4543. }
  4544. }
  4545. if (sc->getSCE(SC_MAGNIFICAT))
  4546. regen->rate.sp += 100;
  4547. if (sc->getSCE(SC_REGENERATION)) {
  4548. const struct status_change_entry *sce = sc->getSCE(SC_REGENERATION);
  4549. if (!sce->val4) {
  4550. regen->rate.hp += (sce->val2*100);
  4551. regen->rate.sp += (sce->val3*100);
  4552. } else
  4553. regen->flag &= ~sce->val4; // Remove regen as specified by val4
  4554. }
  4555. if(sc->getSCE(SC_GT_REVITALIZE)) {
  4556. regen->hp += cap_value(regen->hp * sc->getSCE(SC_GT_REVITALIZE)->val3/100, 1, SHRT_MAX);
  4557. regen->state.walk = 1;
  4558. }
  4559. if (bl->type == BL_ELEM) { // Recovery bonus only applies to the Elementals.
  4560. int32 ele_class = status_get_class(bl);
  4561. switch (ele_class) {
  4562. case ELEMENTALID_AGNI_S:
  4563. case ELEMENTALID_AGNI_M:
  4564. case ELEMENTALID_AGNI_L:
  4565. case ELEMENTALID_ARDOR:
  4566. if (sc->getSCE(SC_FIRE_INSIGNIA) && sc->getSCE(SC_FIRE_INSIGNIA)->val1 == 1)
  4567. regen->rate.hp += 100;
  4568. break;
  4569. case ELEMENTALID_AQUA_S:
  4570. case ELEMENTALID_AQUA_M:
  4571. case ELEMENTALID_AQUA_L:
  4572. case ELEMENTALID_DILUVIO:
  4573. if (sc->getSCE(SC_WATER_INSIGNIA) && sc->getSCE(SC_WATER_INSIGNIA)->val1 == 1)
  4574. regen->rate.hp += 100;
  4575. break;
  4576. case ELEMENTALID_VENTUS_S:
  4577. case ELEMENTALID_VENTUS_M:
  4578. case ELEMENTALID_VENTUS_L:
  4579. case ELEMENTALID_PROCELLA:
  4580. if (sc->getSCE(SC_WIND_INSIGNIA) && sc->getSCE(SC_WIND_INSIGNIA)->val1 == 1)
  4581. regen->rate.hp += 100;
  4582. break;
  4583. case ELEMENTALID_TERA_S:
  4584. case ELEMENTALID_TERA_M:
  4585. case ELEMENTALID_TERA_L:
  4586. case ELEMENTALID_TERREMOTUS:
  4587. case ELEMENTALID_SERPENS:
  4588. if (sc->getSCE(SC_EARTH_INSIGNIA) && sc->getSCE(SC_EARTH_INSIGNIA)->val1 == 1)
  4589. regen->rate.hp += 100;
  4590. break;
  4591. }
  4592. }
  4593. if (sc->getSCE(SC_CATNIPPOWDER)) {
  4594. regen->rate.hp *= 2;
  4595. regen->rate.sp *= 2;
  4596. }
  4597. if (sc->getSCE(SC_SHRIMPBLESSING))
  4598. regen->rate.sp += 50;
  4599. #ifdef RENEWAL
  4600. if (sc->getSCE(SC_NIBELUNGEN)) {
  4601. if (sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_HPREGEN)
  4602. regen->rate.hp += 100;
  4603. else if (sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_SPREGEN)
  4604. regen->rate.sp += 100;
  4605. }
  4606. #endif
  4607. if (sc->getSCE(SC_SIRCLEOFNATURE))
  4608. regen->rate.hp += sc->getSCE(SC_SIRCLEOFNATURE)->val2;
  4609. if (sc->getSCE(SC_SONGOFMANA))
  4610. regen->rate.sp += sc->getSCE(SC_SONGOFMANA)->val3;
  4611. }
  4612. /**
  4613. * Applies a state to a unit - See [StatusChangeStateTable]
  4614. * @param bl: Object to change state on [PC|MOB|HOM|MER|ELEM]
  4615. * @param sc: Object's status change data
  4616. * @param flag: Which state to apply to bl
  4617. * @param start: (1) start state, (0) remove state
  4618. */
  4619. void status_calc_state( struct block_list *bl, status_change *sc, std::bitset<SCS_MAX> flag, bool start )
  4620. {
  4621. /// No sc at all, we can zero without any extra weight over our conciousness
  4622. if( sc->empty() ) {
  4623. sc->cant = {};
  4624. return;
  4625. }
  4626. // Can't move
  4627. if( flag[SCS_NOMOVE] ) {
  4628. if( !flag[SCS_NOMOVECOND] )
  4629. sc->cant.move += (start ? 1 : ((sc->cant.move) ? -1 : 0));
  4630. else if(
  4631. (sc->getSCE(SC_GOSPEL) && sc->getSCE(SC_GOSPEL)->val4 == BCT_SELF) // cannot move while gospel is in effect
  4632. #ifndef RENEWAL
  4633. || (sc->getSCE(SC_BASILICA) && sc->getSCE(SC_BASILICA)->val4 == bl->id) // Basilica caster cannot move
  4634. || (sc->getSCE(SC_GRAVITATION) && sc->getSCE(SC_GRAVITATION)->val3 == BCT_SELF)
  4635. #endif
  4636. || (sc->getSCE(SC_CAMOUFLAGE) && sc->getSCE(SC_CAMOUFLAGE)->val1 < 3)
  4637. || (sc->getSCE(SC_MAGNETICFIELD) && sc->getSCE(SC_MAGNETICFIELD)->val2 != bl->id)
  4638. || (sc->getSCE(SC_FEAR) && sc->getSCE(SC_FEAR)->val2 > 0)
  4639. || (sc->getSCE(SC_HIDING) && (bl->type != BL_PC || (pc_checkskill(BL_CAST(BL_PC,bl),RG_TUNNELDRIVE) <= 0)))
  4640. || (sc->getSCE(SC_DANCING) && sc->getSCE(SC_DANCING)->val4 && (
  4641. #ifndef RENEWAL
  4642. !sc->getSCE(SC_LONGING) ||
  4643. #endif
  4644. (sc->getSCE(SC_DANCING)->val1&0xFFFF) == CG_MOONLIT ||
  4645. (sc->getSCE(SC_DANCING)->val1&0xFFFF) == CG_HERMODE
  4646. ))
  4647. || (sc->getSCE(SC_CRYSTALIZE) && bl->type != BL_MOB)
  4648. )
  4649. sc->cant.move += (start ? 1 : ((sc->cant.move) ? -1 : 0));
  4650. }
  4651. // Can't use skills
  4652. if( flag[SCS_NOCAST] ) {
  4653. if( !flag[SCS_NOCASTCOND] )
  4654. sc->cant.cast += (start ? 1 : ((sc->cant.cast) ? -1 : 0));
  4655. else if (sc->getSCE(SC_OBLIVIONCURSE) && sc->getSCE(SC_OBLIVIONCURSE)->val3 == 1)
  4656. sc->cant.cast += (start ? 1 : ((sc->cant.cast) ? -1 : 0));
  4657. }
  4658. // Can't chat
  4659. if( flag[SCS_NOCHAT] ) {
  4660. if( !flag[SCS_NOCHATCOND] )
  4661. sc->cant.chat += (start ? 1 : ((sc->cant.chat) ? -1 : 0));
  4662. else if(sc->getSCE(SC_NOCHAT) && sc->getSCE(SC_NOCHAT)->val1&MANNER_NOCHAT)
  4663. sc->cant.chat += (start ? 1 : ((sc->cant.chat) ? -1 : 0));
  4664. }
  4665. // Can't attack
  4666. if( flag[SCS_NOATTACK] ) {
  4667. if( !flag[SCS_NOATTACKCOND] )
  4668. sc->cant.attack += (start ? 1 : ((sc->cant.attack) ? -1 : 0));
  4669. /*else if( )
  4670. sc->cant.attack += ( start ? 1 : ((sc->cant.attack)? -1:0) );*/
  4671. }
  4672. // Can't warp
  4673. if (flag[SCS_NOWARP]) {
  4674. if (!flag[SCS_NOWARPCOND])
  4675. sc->cant.warp += (start ? 1 : ((sc->cant.warp) ? -1 : 0));
  4676. /*else if (sc->getSCE())
  4677. sc->cant.warp += ( start ? 1 : ((sc->cant.warp)? -1:0) );*/
  4678. }
  4679. // Player-only states
  4680. if( bl->type == BL_PC ) {
  4681. // Can't pick-up items
  4682. if( flag[SCS_NOPICKITEM] ) {
  4683. if( !flag[SCS_NOPICKITEMCOND] )
  4684. sc->cant.pickup += (start ? 1 : ((sc->cant.pickup) ? -1 : 0));
  4685. else if( (sc->getSCE(SC_NOCHAT) && sc->getSCE(SC_NOCHAT)->val1&MANNER_NOITEM) )
  4686. sc->cant.pickup += (start ? 1 : ((sc->cant.pickup) ? -1 : 0));
  4687. }
  4688. // Can't drop items
  4689. if( flag[SCS_NODROPITEM] ) {
  4690. if( !flag[SCS_NODROPITEMCOND] )
  4691. sc->cant.drop += (start ? 1 : ((sc->cant.drop) ? -1 : 0));
  4692. else if( (sc->getSCE(SC_NOCHAT) && sc->getSCE(SC_NOCHAT)->val1&MANNER_NOITEM) )
  4693. sc->cant.drop += (start ? 1 : ((sc->cant.drop) ? -1 : 0));
  4694. }
  4695. // Can't equip item
  4696. if( flag[SCS_NOEQUIPITEM] ) {
  4697. if( !flag[SCS_NOEQUIPITEMCOND] )
  4698. sc->cant.equip += (start ? 1 : ((sc->cant.equip) ? -1 : 0));
  4699. /*else if( )
  4700. sc->cant.equip += ( start ? 1 : ((sc->cant.equip)? -1:0) );*/
  4701. }
  4702. // Can't unequip item
  4703. if( flag[SCS_NOUNEQUIPITEM]) {
  4704. if( !flag[SCS_NOUNEQUIPITEMCOND] )
  4705. sc->cant.unequip += (start ? 1 : ((sc->cant.unequip) ? -1 : 0));
  4706. /*else if( )
  4707. sc->cant.unequip += ( start ? 1 : ((sc->cant.unequip)? -1:0) );*/
  4708. }
  4709. // Can't consume item
  4710. if( flag[SCS_NOCONSUMEITEM]) {
  4711. if( !flag[SCS_NOCONSUMEITEMCOND] )
  4712. sc->cant.consume += (start ? 1 : ((sc->cant.consume) ? -1 : 0));
  4713. else if( (sc->getSCE(SC_GRAVITATION) && sc->getSCE(SC_GRAVITATION)->val3 == BCT_SELF) ||
  4714. (sc->getSCE(SC_NOCHAT) && sc->getSCE(SC_NOCHAT)->val1&MANNER_NOITEM) )
  4715. sc->cant.consume += (start ? 1 : ((sc->cant.consume) ? -1 : 0));
  4716. }
  4717. // Can't lose exp
  4718. if (flag[SCS_NODEATHPENALTY]) {
  4719. if (!flag[SCS_NODEATHPENALTYCOND])
  4720. sc->cant.deathpenalty += (start ? 1 : ((sc->cant.deathpenalty) ? -1 : 0));
  4721. /*else if (sc->getSCE())
  4722. sc->cant.deathpenalty += ( start ? 1 : ((sc->cant.deathpenalty)? -1:0) );*/
  4723. }
  4724. // Can't sit/stand/talk to NPC
  4725. if (flag[SCS_NOINTERACT]) {
  4726. if (!flag[SCS_NOINTERACTCOND])
  4727. sc->cant.interact += (start ? 1 : ((sc->cant.interact) ? -1 : 0));
  4728. /*else if (sc->getSCE())
  4729. sc->cant.interact += ( start ? 1 : ((sc->cant.interact)? -1:0) );*/
  4730. }
  4731. }
  4732. return;
  4733. }
  4734. /**
  4735. * Recalculates parts of an objects status according to specified flags
  4736. * See [set_sc] [add_sc]
  4737. * @param bl: Object whose status has changed [PC|MOB|HOM|MER|ELEM]
  4738. * @param flag: Which status has changed on bl
  4739. */
  4740. void status_calc_bl_main(struct block_list& bl, std::bitset<SCB_MAX> flag)
  4741. {
  4742. const struct status_data *b_status = status_get_base_status(&bl); // Base Status
  4743. status_data* status = status_get_status_data(bl); // Battle Status
  4744. status_change *sc = status_get_sc(&bl);
  4745. TBL_PC *sd = BL_CAST(BL_PC,&bl);
  4746. int32 temp;
  4747. if (!b_status || !status)
  4748. return;
  4749. /** [Playtester]
  4750. * This needs to be done even if there is currently no status change active, because
  4751. * we need to update the speed on the client when the last status change ends.
  4752. **/
  4753. if(flag[SCB_SPEED]) {
  4754. struct unit_data *ud = unit_bl2ud(&bl);
  4755. /** [Skotlex]
  4756. * Re-walk to adjust speed (we do not check if walktimer != INVALID_TIMER
  4757. * because if you step on something while walking, the moment this
  4758. * piece of code triggers the walk-timer is set on INVALID_TIMER)
  4759. **/
  4760. if (ud)
  4761. ud->state.change_walk_target = 1;
  4762. }
  4763. if(flag[SCB_STR]) {
  4764. status->str = status_calc_str(&bl, sc, b_status->str);
  4765. flag.set(SCB_BATK);
  4766. if( bl.type == BL_HOM )
  4767. flag.set(SCB_WATK);
  4768. }
  4769. if(flag[SCB_AGI]) {
  4770. status->agi = status_calc_agi(&bl, sc, b_status->agi);
  4771. flag.set(SCB_FLEE);
  4772. #ifdef RENEWAL
  4773. flag.set(SCB_DEF2);
  4774. #endif
  4775. if( bl.type&(BL_PC|BL_HOM) ) {
  4776. flag.set(SCB_ASPD);
  4777. flag.set(SCB_DSPD);
  4778. }
  4779. }
  4780. if(flag[SCB_VIT]) {
  4781. status->vit = status_calc_vit(&bl, sc, b_status->vit);
  4782. flag.set(SCB_DEF2);
  4783. flag.set(SCB_MDEF2);
  4784. if( bl.type&(BL_PC|BL_HOM|BL_MER|BL_ELEM) )
  4785. flag.set(SCB_MAXHP);
  4786. if( bl.type == BL_HOM )
  4787. flag.set(SCB_DEF);
  4788. }
  4789. if(flag[SCB_INT]) {
  4790. status->int_ = status_calc_int(&bl, sc, b_status->int_);
  4791. flag.set(SCB_MATK);
  4792. flag.set(SCB_MDEF2);
  4793. if( bl.type&(BL_PC|BL_HOM|BL_MER|BL_ELEM) )
  4794. flag.set(SCB_MAXSP);
  4795. if( bl.type == BL_HOM )
  4796. flag.set(SCB_MDEF);
  4797. }
  4798. if(flag[SCB_DEX]) {
  4799. status->dex = status_calc_dex(&bl, sc, b_status->dex);
  4800. flag.set(SCB_BATK);
  4801. flag.set(SCB_HIT);
  4802. #ifdef RENEWAL
  4803. flag.set(SCB_MATK);
  4804. flag.set(SCB_MDEF2);
  4805. #endif
  4806. if( bl.type&(BL_PC|BL_HOM) )
  4807. flag.set(SCB_ASPD);
  4808. if( bl.type == BL_HOM )
  4809. flag.set(SCB_WATK);
  4810. }
  4811. if(flag[SCB_LUK]) {
  4812. status->luk = status_calc_luk(&bl, sc, b_status->luk);
  4813. flag.set(SCB_BATK);
  4814. flag.set(SCB_CRI);
  4815. flag.set(SCB_FLEE2);
  4816. #ifdef RENEWAL
  4817. flag.set(SCB_MATK);
  4818. flag.set(SCB_HIT);
  4819. flag.set(SCB_FLEE);
  4820. #endif
  4821. }
  4822. #ifdef RENEWAL
  4823. if (flag[SCB_POW]) {
  4824. status->pow = status_calc_pow(&bl, sc, b_status->pow);
  4825. flag.set(SCB_BATK);
  4826. flag.set(SCB_PATK);
  4827. }
  4828. if (flag[SCB_STA]) {
  4829. status->sta = status_calc_sta(&bl, sc, b_status->sta);
  4830. flag.set(SCB_RES);
  4831. }
  4832. if (flag[SCB_WIS]) {
  4833. status->wis = status_calc_wis(&bl, sc, b_status->wis);
  4834. flag.set(SCB_MRES);
  4835. }
  4836. if (flag[SCB_SPL]) {
  4837. status->spl = status_calc_spl(&bl, sc, b_status->spl);
  4838. flag.set(SCB_MATK);
  4839. flag.set(SCB_SMATK);
  4840. }
  4841. if (flag[SCB_CON]) {
  4842. status->con = status_calc_con(&bl, sc, b_status->con);
  4843. flag.set(SCB_HIT);
  4844. flag.set(SCB_FLEE);
  4845. flag.set(SCB_PATK);
  4846. flag.set(SCB_SMATK);
  4847. }
  4848. if (flag[SCB_CRT]) {
  4849. status->crt = status_calc_crt(&bl, sc, b_status->crt);
  4850. flag.set(SCB_HPLUS);
  4851. flag.set(SCB_CRATE);
  4852. }
  4853. #endif
  4854. if(flag[SCB_BATK] && b_status->batk) {
  4855. int32 lv = status_get_lv(&bl);
  4856. status->batk = status_base_atk(&bl, status, lv);
  4857. temp = b_status->batk - status_base_atk(&bl, b_status, lv);
  4858. if (temp) {
  4859. temp += status->batk;
  4860. status->batk = cap_value(temp, 0, USHRT_MAX);
  4861. }
  4862. status->batk = status_calc_batk(&bl, sc, status->batk);
  4863. }
  4864. if(flag[SCB_WATK]) {
  4865. #ifndef RENEWAL
  4866. status->rhw.atk = status_calc_watk(&bl, sc, b_status->rhw.atk);
  4867. if (!sd) // Should not affect weapon refine bonus
  4868. status->rhw.atk2 = status_calc_watk(&bl, sc, b_status->rhw.atk2);
  4869. if (sd && sd->bonus.weapon_atk_rate)
  4870. status->rhw.atk += status->rhw.atk * sd->bonus.weapon_atk_rate / 100;
  4871. if(b_status->lhw.atk) {
  4872. if (sd) {
  4873. sd->state.lr_flag = LR_FLAG_WEAPON;
  4874. status->lhw.atk = status_calc_watk(&bl, sc, b_status->lhw.atk);
  4875. sd->state.lr_flag = LR_FLAG_NONE;
  4876. } else {
  4877. status->lhw.atk = status_calc_watk(&bl, sc, b_status->lhw.atk);
  4878. status->lhw.atk2= status_calc_watk(&bl, sc, b_status->lhw.atk2);
  4879. }
  4880. }
  4881. #else
  4882. if(!b_status->watk) { // We only have left-hand weapon
  4883. status->watk = 0;
  4884. status->watk2 = status_calc_watk(&bl, sc, b_status->watk2);
  4885. }
  4886. else status->watk = status_calc_watk(&bl, sc, b_status->watk);
  4887. #endif
  4888. }
  4889. if(flag[SCB_HIT]) {
  4890. if (status->dex == b_status->dex
  4891. #ifdef RENEWAL
  4892. && status->luk == b_status->luk && status->con == b_status->con
  4893. #endif
  4894. )
  4895. status->hit = status_calc_hit(&bl, sc, b_status->hit);
  4896. else
  4897. status->hit = status_calc_hit(&bl, sc, b_status->hit + (status->dex - b_status->dex)
  4898. #ifdef RENEWAL
  4899. + (status->luk/3 - b_status->luk/3) + 2 * (status->con - b_status->con)
  4900. #endif
  4901. );
  4902. }
  4903. if(flag[SCB_FLEE]) {
  4904. if (status->agi == b_status->agi
  4905. #ifdef RENEWAL
  4906. && status->luk == b_status->luk && status->con == b_status->con
  4907. #endif
  4908. )
  4909. status->flee = status_calc_flee(&bl, sc, b_status->flee);
  4910. else
  4911. status->flee = status_calc_flee(&bl, sc, b_status->flee +(status->agi - b_status->agi)
  4912. #ifdef RENEWAL
  4913. + (status->luk/5 - b_status->luk/5) + 2 * (status->con - b_status->con)
  4914. #endif
  4915. );
  4916. }
  4917. if(flag[SCB_DEF]) {
  4918. status->def = status_calc_def(&bl, sc, b_status->def);
  4919. if( bl.type == BL_HOM )
  4920. status->def += (status->vit/5 - b_status->vit/5);
  4921. }
  4922. if(flag[SCB_DEF2]) {
  4923. if (status->vit == b_status->vit
  4924. #ifdef RENEWAL
  4925. && status->agi == b_status->agi
  4926. #endif
  4927. )
  4928. status->def2 = status_calc_def2(&bl, sc, b_status->def2);
  4929. else
  4930. status->def2 = status_calc_def2(&bl, sc, b_status->def2
  4931. #ifdef RENEWAL
  4932. + (int32)( ((float)status->vit/2 - (float)b_status->vit/2) + ((float)status->agi/5 - (float)b_status->agi/5) )
  4933. #else
  4934. + (status->vit - b_status->vit)
  4935. #endif
  4936. );
  4937. }
  4938. if(flag[SCB_MDEF]) {
  4939. status->mdef = status_calc_mdef(&bl, sc, b_status->mdef);
  4940. if( bl.type == BL_HOM )
  4941. status->mdef += (status->int_/5 - b_status->int_/5);
  4942. }
  4943. if(flag[SCB_MDEF2]) {
  4944. if (status->int_ == b_status->int_ && status->vit == b_status->vit
  4945. #ifdef RENEWAL
  4946. && status->dex == b_status->dex
  4947. #endif
  4948. )
  4949. status->mdef2 = status_calc_mdef2(&bl, sc, b_status->mdef2);
  4950. else
  4951. status->mdef2 = status_calc_mdef2(&bl, sc, b_status->mdef2 +(status->int_ - b_status->int_)
  4952. #ifdef RENEWAL
  4953. + (int32)( ((float)status->dex/5 - (float)b_status->dex/5) + ((float)status->vit/5 - (float)b_status->vit/5) )
  4954. #else
  4955. + ((status->vit - b_status->vit) / 2)
  4956. #endif
  4957. );
  4958. }
  4959. if(flag[SCB_SPEED]) {
  4960. status->speed = status_calc_speed(&bl, sc, b_status->speed);
  4961. switch (bl.type) {
  4962. case BL_PC:
  4963. if (!sd->state.permanent_speed && status->speed < battle_config.max_walk_speed)
  4964. status->speed = battle_config.max_walk_speed;
  4965. #ifdef RENEWAL
  4966. // Recalculate homunculus speed if the player receives a speed buff/debuff
  4967. if (hom_is_active(sd->hd)) {
  4968. if (battle_config.hom_setting & HOMSET_COPY_SPEED)
  4969. sd->hd->battle_status.speed = status_get_speed(&sd->bl);
  4970. // Homunculus speed buff/debuffs applies over the current speed
  4971. sd->hd->battle_status.speed = status_calc_speed(&sd->hd->bl, &sd->hd->sc, sd->hd->battle_status.speed);
  4972. }
  4973. #endif
  4974. break;
  4975. case BL_PET:{
  4976. pet_data* pd = reinterpret_cast<pet_data*>(&bl);
  4977. if (pd->master != nullptr)
  4978. status->speed = status_get_speed(&pd->master->bl);
  4979. } break;
  4980. case BL_HOM:{
  4981. homun_data* hd = reinterpret_cast<homun_data*>(&bl);
  4982. if (hd->master != nullptr) {
  4983. if (battle_config.hom_setting & HOMSET_COPY_SPEED)
  4984. status->speed = status_get_speed(&hd->master->bl);
  4985. // Homunculus speed buff/debuffs applies over the current speed
  4986. status->speed = status_calc_speed(&bl, &hd->sc, status->speed);
  4987. }
  4988. } break;
  4989. case BL_MER:{
  4990. s_mercenary_data* mc = reinterpret_cast<s_mercenary_data*>(&bl);
  4991. if (mc->master != nullptr)
  4992. status->speed = status_get_speed(&mc->master->bl);
  4993. } break;
  4994. case BL_ELEM:{
  4995. s_elemental_data* ed = reinterpret_cast<s_elemental_data*>(&bl);
  4996. if (ed->master != nullptr)
  4997. status->speed = status_get_speed(&ed->master->bl);
  4998. } break;
  4999. }
  5000. }
  5001. if(flag[SCB_CRI] && b_status->cri) {
  5002. if (status->luk == b_status->luk)
  5003. status->cri = status_calc_critical(&bl, sc, b_status->cri);
  5004. else
  5005. #ifdef RENEWAL
  5006. status->cri = status_calc_critical(&bl, sc, b_status->cri + 3*(status->luk - b_status->luk));
  5007. #else
  5008. status->cri = status_calc_critical(&bl, sc, b_status->cri + (status->luk - b_status->luk)*10/3);
  5009. #endif
  5010. /// After status_calc_critical so the bonus is applied despite if you have or not a sc bugreport:5240
  5011. if (sd) {
  5012. if (sd->status.weapon == W_KATAR)
  5013. status->cri *= 2;
  5014. }
  5015. }
  5016. if(flag[SCB_FLEE2] && b_status->flee2) {
  5017. if (status->luk == b_status->luk)
  5018. status->flee2 = status_calc_flee2(&bl, sc, b_status->flee2);
  5019. else
  5020. status->flee2 = status_calc_flee2(&bl, sc, b_status->flee2 +(status->luk - b_status->luk));
  5021. }
  5022. if(flag[SCB_ATK_ELE]) {
  5023. status->rhw.ele = status_calc_attack_element(&bl, sc, b_status->rhw.ele);
  5024. if (sd) sd->state.lr_flag = LR_FLAG_WEAPON;
  5025. status->lhw.ele = status_calc_attack_element(&bl, sc, b_status->lhw.ele);
  5026. if (sd) sd->state.lr_flag = LR_FLAG_NONE;
  5027. }
  5028. if(flag[SCB_DEF_ELE]) {
  5029. status->def_ele = status_calc_element(&bl, sc, b_status->def_ele);
  5030. status->ele_lv = status_calc_element_lv(&bl, sc, b_status->ele_lv);
  5031. }
  5032. if(flag[SCB_MODE]) {
  5033. status->mode = status_calc_mode(&bl, sc, b_status->mode);
  5034. if (status_has_mode(status, MD_STATUSIMMUNE|MD_SKILLIMMUNE))
  5035. status->class_ = CLASS_BATTLEFIELD;
  5036. else if (status_has_mode(status, MD_STATUSIMMUNE|MD_KNOCKBACKIMMUNE|MD_DETECTOR))
  5037. status->class_ = CLASS_BOSS;
  5038. else if (status_has_mode(status, MD_STATUSIMMUNE))
  5039. status->class_ = CLASS_GUARDIAN;
  5040. else
  5041. status->class_ = CLASS_NORMAL;
  5042. // Since mode changed, reset their state.
  5043. if (!status_has_mode(status,MD_CANATTACK))
  5044. unit_stop_attack(&bl);
  5045. if (!status_has_mode(status,MD_CANMOVE))
  5046. unit_stop_walking( &bl, USW_FIXPOS );
  5047. }
  5048. /**
  5049. * No status changes alter these yet.
  5050. * if(flag[SCB_SIZE])
  5051. * if(flag[SCB_RACE])
  5052. * if(flag[SCB_RANGE])
  5053. **/
  5054. if(flag[SCB_MAXHP]) {
  5055. if( bl.type == BL_PC ) {
  5056. status->max_hp = status_calc_maxhpsp_pc(sd,status->vit,true);
  5057. if(battle_config.hp_rate != 100)
  5058. status->max_hp = (uint32)(battle_config.hp_rate * (status->max_hp/100.));
  5059. if (sd->status.base_level < 100)
  5060. status->max_hp = umin(status->max_hp,(uint32)battle_config.max_hp_lv99);
  5061. else if (sd->status.base_level < 151)
  5062. status->max_hp = umin(status->max_hp,(uint32)battle_config.max_hp_lv150);
  5063. else
  5064. status->max_hp = umin(status->max_hp,(uint32)battle_config.max_hp);
  5065. }
  5066. else
  5067. status->max_hp = status_calc_maxhp(&bl, b_status->max_hp);
  5068. if( status->hp > status->max_hp ) { // !FIXME: Should perhaps a status_zap should be issued?
  5069. status->hp = status->max_hp;
  5070. if( sd ) clif_updatestatus(*sd,SP_HP);
  5071. }
  5072. }
  5073. if(flag[SCB_MAXSP]) {
  5074. if( bl.type == BL_PC ) {
  5075. status->max_sp = status_calc_maxhpsp_pc(sd,status->int_,false);
  5076. if(battle_config.sp_rate != 100)
  5077. status->max_sp = (uint32)(battle_config.sp_rate * (status->max_sp/100.));
  5078. status->max_sp = umin(status->max_sp,(uint32)battle_config.max_sp);
  5079. }
  5080. else
  5081. status->max_sp = status_calc_maxsp(&bl, b_status->max_sp);
  5082. if( status->sp > status->max_sp ) {
  5083. status->sp = status->max_sp;
  5084. if( sd ) clif_updatestatus(*sd,SP_SP);
  5085. }
  5086. }
  5087. if(flag[SCB_MATK]) {
  5088. #ifndef RENEWAL
  5089. int32 matk_min = status_base_matk_min(status);
  5090. int32 matk_max = status_base_matk_max(status);
  5091. matk_min += (sd != nullptr ? sd->bonus.ematk : 0);
  5092. matk_max += (sd != nullptr ? sd->bonus.ematk : 0);
  5093. if (sd != nullptr && sd->matk_rate != 100) {
  5094. matk_min = matk_min * sd->matk_rate / 100;
  5095. matk_max = matk_max * sd->matk_rate / 100;
  5096. }
  5097. // Apply Recognized Spell buff - custom support (renewal status change)
  5098. // Also update homunculus MATK, hom Min Matk is always the same as Max Matk
  5099. if ((bl.type == BL_HOM && battle_config.hom_setting&HOMSET_SAME_MATK) || (sc && sc->getSCE(SC_RECOGNIZEDSPELL))) {
  5100. matk_min = std::max( matk_min, matk_max );
  5101. }
  5102. matk_min = status_calc_pseudobuff_matk( sd, sc, matk_min );
  5103. matk_max = status_calc_pseudobuff_matk( sd, sc, matk_max );
  5104. matk_min = status_calc_consumablematk( sc, matk_min );
  5105. matk_max = status_calc_consumablematk( sc, matk_max );
  5106. if (sc && sc->getSCE(SC_MAGICPOWER) && sc->getSCE(SC_MAGICPOWER)->val4) {
  5107. matk_min += matk_min * sc->getSCE(SC_MAGICPOWER)->val3 / 100;
  5108. matk_max += matk_max * sc->getSCE(SC_MAGICPOWER)->val3 / 100;
  5109. }
  5110. // Custom since JOB_SOUL_REAPER does not exist in pre-renewal
  5111. if (sd != nullptr) {
  5112. matk_min += 3 * sd->soulball;
  5113. matk_max += 3 * sd->soulball;
  5114. }
  5115. status->matk_min = static_cast<uint16>( cap_value(matk_min,0,USHRT_MAX) );
  5116. status->matk_max = static_cast<uint16>( cap_value(matk_max,0,USHRT_MAX) );
  5117. #else
  5118. // MATK = StatusMATK + WeaponMATK + ExtraMATK
  5119. int32 lv = status_get_lv(&bl);
  5120. // StatusMATK
  5121. int32 matk_min = status_base_matk_min(&bl, status, lv);
  5122. int32 matk_max = status_base_matk_max(&bl, status, lv);
  5123. if (sd != nullptr) {
  5124. // Soul energy spheres increase MATK (not displayed in status window).
  5125. matk_min += 3 * sd->soulball;
  5126. matk_max += 3 * sd->soulball;
  5127. // Weapon magic attack modifiers. WeaponMATK = BaseWeaponDamage + Variance + RefinementBonus
  5128. // RefinementBonus is currently included with BaseWeaponDamage in status->lhw.matk and status->rhw.matk
  5129. // BaseWeaponDamage and RefinementBonus are visible on the player status window.
  5130. if (b_status->lhw.matk > 0)
  5131. status->lhw.matk = b_status->lhw.matk;
  5132. if (b_status->rhw.matk > 0)
  5133. status->rhw.matk = b_status->rhw.matk;
  5134. int32 wMatk = 0;
  5135. int32 variance = 0;
  5136. if (status->rhw.matk > 0) {
  5137. wMatk = status->rhw.matk;
  5138. variance = status->rhw.matk * status->rhw.wlv / 10;
  5139. }
  5140. if (status->lhw.matk > 0) {
  5141. wMatk += status->lhw.matk;
  5142. variance += status->lhw.matk * status->lhw.wlv / 10;
  5143. }
  5144. matk_min += wMatk - variance;
  5145. matk_max += wMatk + variance;
  5146. }
  5147. // Apply Recognized Spell buff
  5148. // Also update homunculus MATK, hom Min Matk is always the same as Max Matk
  5149. if ((bl.type == BL_HOM && battle_config.hom_setting&HOMSET_SAME_MATK) || (sc && sc->getSCE(SC_RECOGNIZEDSPELL))) {
  5150. matk_min = std::max( matk_min, matk_max );
  5151. }
  5152. if (sd != nullptr && sd->right_weapon.overrefine > 0) {
  5153. matk_min++;
  5154. matk_max += sd->right_weapon.overrefine - 1;
  5155. }
  5156. // Apply MATK % from skill Mystical Amplification
  5157. if (sc && sc->getSCE(SC_MAGICPOWER)) {
  5158. matk_min += matk_min * sc->getSCE(SC_MAGICPOWER)->val3 / 100;
  5159. matk_max += matk_max * sc->getSCE(SC_MAGICPOWER)->val3 / 100;
  5160. }
  5161. // ExtraMATK = EquipMATK + ConsumableMATK + PseudoBuffMATK
  5162. // Bonuses from ExtraMATK are separated in order to order them (order has no impact)
  5163. // EquipMATK (flat MATK from equipments)
  5164. if (sd != nullptr && sd->bonus.ematk > 0) {
  5165. matk_min += sd->bonus.ematk;
  5166. matk_max += sd->bonus.ematk;
  5167. }
  5168. // PseudoBuffMATK (flat MATK from skills)
  5169. matk_min = status_calc_pseudobuff_matk( sd, sc, matk_min );
  5170. matk_max = status_calc_pseudobuff_matk( sd, sc, matk_max );
  5171. // ConsumableMATK (flat MATK from consumables)
  5172. matk_min = status_calc_consumablematk( sc, matk_min );
  5173. matk_max = status_calc_consumablematk( sc, matk_max );
  5174. // Apply MATK % (from equipments, usable items...)
  5175. if (sd != nullptr && sd->matk_rate != 100) {
  5176. matk_min = matk_min * sd->matk_rate / 100;
  5177. matk_max = matk_max * sd->matk_rate / 100;
  5178. }
  5179. status->matk_min = static_cast<uint16>( cap_value(matk_min,0,USHRT_MAX) );
  5180. status->matk_max = static_cast<uint16>( cap_value(matk_max,0,USHRT_MAX) );
  5181. #endif
  5182. }
  5183. if(flag[SCB_ASPD]) {
  5184. int32 amotion;
  5185. if ( bl.type == BL_HOM ) {
  5186. #ifdef RENEWAL_ASPD
  5187. amotion = (reinterpret_cast<homun_data*>(&bl))->homunculusDB->baseASPD;
  5188. amotion = amotion - amotion * status_get_homdex(&bl) / 1000 - status_get_homagi(&bl) * amotion / 250;
  5189. amotion = (amotion * status_calc_aspd(&bl, sc, true) + status_calc_aspd(&bl, sc, false)) / - 100 + amotion;
  5190. #else
  5191. amotion = (1000 - 4 * status->agi - status->dex) * (reinterpret_cast<homun_data*>(&bl))->homunculusDB->baseASPD / 1000;
  5192. amotion = status_calc_aspd_rate(&bl, sc, amotion);
  5193. amotion = amotion * status->aspd_rate / 1000;
  5194. #endif
  5195. amotion = status_calc_fix_aspd(&bl, sc, amotion);
  5196. status->amotion = cap_value(amotion, battle_config.max_aspd, 2000);
  5197. status->adelay = status->amotion;
  5198. } else if ( bl.type == BL_PC ) {
  5199. uint16 skill_lv;
  5200. amotion = status_base_amotion_pc(sd,status);
  5201. #ifndef RENEWAL_ASPD
  5202. status->aspd_rate = status_calc_aspd_rate(&bl, sc, b_status->aspd_rate);
  5203. #endif
  5204. // Absolute ASPD % modifiers
  5205. amotion = amotion * status->aspd_rate / 1000;
  5206. if (sd->ud.skilltimer != INVALID_TIMER && (skill_lv = pc_checkskill(sd, SA_FREECAST)) > 0)
  5207. #ifdef RENEWAL_ASPD
  5208. amotion = amotion * 5 * (skill_lv + 10) / 100;
  5209. #else
  5210. amotion += (2000 - amotion) * ( 55 - 5 * ( skill_lv + 1 ) ) / 100; //Increases amotion to reduce ASPD to the corresponding absolute percentage for each level (overriding other adjustments)
  5211. #endif
  5212. #ifdef RENEWAL_ASPD
  5213. // RE ASPD % modifier
  5214. amotion += (max(0xc3 - amotion, 2) * (status->aspd_rate2 + status_calc_aspd(&bl, sc, false))) / 100;
  5215. amotion = 10 * (200 - amotion);
  5216. amotion += sd->bonus.aspd_add;
  5217. #endif
  5218. amotion = status_calc_fix_aspd(&bl, sc, amotion);
  5219. status->amotion = cap_value(amotion,pc_maxaspd(sd),2000);
  5220. status->adelay = 2 * status->amotion;
  5221. } else { // Mercenary and mobs
  5222. amotion = b_status->amotion;
  5223. status->aspd_rate = status_calc_aspd_rate(&bl, sc, b_status->aspd_rate);
  5224. amotion = amotion*status->aspd_rate/1000;
  5225. amotion = status_calc_fix_aspd(&bl, sc, amotion);
  5226. status->amotion = cap_value(amotion, battle_config.monster_max_aspd, 2000);
  5227. temp = b_status->adelay*status->aspd_rate/1000;
  5228. status->adelay = cap_value(temp, battle_config.monster_max_aspd*2, 4000);
  5229. }
  5230. }
  5231. if(flag[SCB_DSPD]) {
  5232. int32 dmotion;
  5233. if( bl.type == BL_PC ) {
  5234. if (b_status->agi == status->agi)
  5235. status->dmotion = status_calc_dmotion(&bl, sc, b_status->dmotion);
  5236. else {
  5237. dmotion = 800-status->agi*4;
  5238. status->dmotion = cap_value(dmotion, 400, 800);
  5239. if(battle_config.pc_damage_delay_rate != 100)
  5240. status->dmotion = status->dmotion*battle_config.pc_damage_delay_rate/100;
  5241. // It's safe to ignore b_status->dmotion since no bonus affects it.
  5242. status->dmotion = status_calc_dmotion(&bl, sc, status->dmotion);
  5243. }
  5244. } else if( bl.type == BL_HOM ) {
  5245. dmotion = 800-status->agi*4;
  5246. status->dmotion = cap_value(dmotion, 400, 800);
  5247. status->dmotion = status_calc_dmotion(&bl, sc, b_status->dmotion);
  5248. } else { // Mercenary and mobs
  5249. status->dmotion = status_calc_dmotion(&bl, sc, b_status->dmotion);
  5250. }
  5251. }
  5252. #ifdef RENEWAL
  5253. if (flag[SCB_PATK]) {
  5254. if (status->pow == b_status->pow && status->con == b_status->con)
  5255. status->patk = status_calc_patk(&bl, sc, b_status->patk);
  5256. else
  5257. status->patk = status_calc_patk(&bl, sc, b_status->patk + (status->pow - b_status->pow) / 3 + (status->con - b_status->con) / 5);
  5258. }
  5259. if (flag[SCB_SMATK]) {
  5260. if (status->spl == b_status->spl && status->con == b_status->con)
  5261. status->smatk = status_calc_smatk(&bl, sc, b_status->smatk);
  5262. else
  5263. status->smatk = status_calc_smatk(&bl, sc, b_status->smatk) + (status->spl - b_status->spl) / 3 + (status->con - b_status->con) / 5;
  5264. }
  5265. if (flag[SCB_RES]) {
  5266. if (status->sta == b_status->sta)
  5267. status->res = status_calc_res(&bl, sc, b_status->res);
  5268. else
  5269. status->res = status_calc_res(&bl, sc, b_status->res + (status->sta - b_status->sta) + (status->sta - b_status->sta) / 3 * 5);
  5270. }
  5271. if (flag[SCB_MRES]) {
  5272. if (status->wis == b_status->wis)
  5273. status->mres = status_calc_mres(&bl, sc, b_status->mres);
  5274. else
  5275. status->mres = status_calc_mres(&bl, sc, b_status->mres + (status->wis - b_status->wis) + (status->wis - b_status->wis) / 3 * 5);
  5276. }
  5277. if (flag[SCB_HPLUS]) {
  5278. if (status->crt == b_status->crt)
  5279. status->hplus = status_calc_hplus(&bl, sc, b_status->hplus);
  5280. else
  5281. status->hplus = status_calc_hplus(&bl, sc, b_status->hplus + (status->crt - b_status->crt));
  5282. }
  5283. if (flag[SCB_CRATE]) {
  5284. if (status->crt == b_status->crt)
  5285. status->crate = status_calc_crate(&bl, sc, b_status->crate);
  5286. else
  5287. status->crate = status_calc_crate(&bl, sc, b_status->crate + (status->crt - b_status->crt) / 3);
  5288. }
  5289. if (flag[SCB_MAXAP]) {
  5290. if (bl.type == BL_PC) {
  5291. status->max_ap = status_calc_maxap_pc(sd);
  5292. if (battle_config.ap_rate != 100)
  5293. status->max_ap = (uint32)(battle_config.ap_rate * (status->max_ap / 100.));
  5294. status->max_ap = umin(status->max_ap, (uint32)battle_config.max_ap);
  5295. } else
  5296. status->max_ap = status_calc_maxap(&bl, b_status->max_ap);
  5297. if (status->ap > status->max_ap) {
  5298. status->ap = status->max_ap;
  5299. if (sd) clif_updatestatus(*sd, SP_AP);
  5300. }
  5301. }
  5302. #endif
  5303. if((flag[SCB_VIT] || flag[SCB_MAXHP] || flag[SCB_INT] || flag[SCB_MAXSP]) && bl.type & BL_REGEN)
  5304. status_calc_regen(&bl, status, status_get_regen_data(&bl));
  5305. if(flag[SCB_REGEN] && bl.type & BL_REGEN)
  5306. status_calc_regen_rate(&bl, status_get_regen_data(&bl), sc);
  5307. }
  5308. /**
  5309. * Recalculates parts of an objects status according to specified flags
  5310. * Also sends updates to the client when necessary
  5311. * See [set_sc] [add_sc]
  5312. * @param bl: Object whose status has changed [PC|MOB|HOM|MER|ELEM]
  5313. * @param flag: Which status has changed on bl
  5314. * @param opt: If true, will cause status_calc_* functions to run their base status initialization code
  5315. */
  5316. void status_calc_bl_(struct block_list* bl, std::bitset<SCB_MAX> flag, uint8 opt)
  5317. {
  5318. if (bl->type == BL_PC) {
  5319. map_session_data *sd = BL_CAST(BL_PC, bl);
  5320. if (sd->delayed_damage != 0) {
  5321. if (opt&SCO_FORCE)
  5322. sd->state.hold_recalc = false; // Clear and move on
  5323. else {
  5324. sd->state.hold_recalc = true; // Flag and stop
  5325. return;
  5326. }
  5327. }
  5328. }
  5329. // Pointer to current battle status
  5330. status_data* status = status_get_status_data(*bl);
  5331. // Previous battle status
  5332. status_data b_status;
  5333. // Remember previous values
  5334. memcpy(&b_status, status, sizeof(b_status));
  5335. if( flag[SCB_BASE] ) { // Calculate the object's base status too
  5336. switch( bl->type ) {
  5337. case BL_PC: status_calc_pc_(BL_CAST(BL_PC,bl), opt); break;
  5338. case BL_MOB: status_calc_mob_(BL_CAST(BL_MOB,bl), opt); break;
  5339. case BL_PET: status_calc_pet_(BL_CAST(BL_PET,bl), opt); break;
  5340. case BL_HOM: status_calc_homunculus_(BL_CAST(BL_HOM,bl), opt); break;
  5341. case BL_MER: status_calc_mercenary_(BL_CAST(BL_MER,bl), opt); break;
  5342. case BL_ELEM: status_calc_elemental_(BL_CAST(BL_ELEM,bl), opt); break;
  5343. case BL_NPC: status_calc_npc_(BL_CAST(BL_NPC,bl), opt); break;
  5344. }
  5345. }
  5346. if( bl->type == BL_PET )
  5347. return; // Pets are not affected by statuses
  5348. if (opt&SCO_FIRST && bl->type == BL_MOB)
  5349. return; // Assume there will be no statuses active
  5350. status_calc_bl_main(*bl, flag);
  5351. if (opt&SCO_FIRST && bl->type == BL_HOM)
  5352. return; // Client update handled by caller
  5353. // Compare against new values and send client updates
  5354. if( bl->type == BL_PC ) {
  5355. TBL_PC* sd = BL_CAST(BL_PC, bl);
  5356. if(b_status.str != status->str)
  5357. clif_updatestatus(*sd,SP_STR);
  5358. if(b_status.agi != status->agi)
  5359. clif_updatestatus(*sd,SP_AGI);
  5360. if(b_status.vit != status->vit)
  5361. clif_updatestatus(*sd,SP_VIT);
  5362. if(b_status.int_ != status->int_)
  5363. clif_updatestatus(*sd,SP_INT);
  5364. if(b_status.dex != status->dex)
  5365. clif_updatestatus(*sd,SP_DEX);
  5366. if(b_status.luk != status->luk)
  5367. clif_updatestatus(*sd,SP_LUK);
  5368. if(b_status.hit != status->hit)
  5369. clif_updatestatus(*sd,SP_HIT);
  5370. if(b_status.flee != status->flee)
  5371. clif_updatestatus(*sd,SP_FLEE1);
  5372. if(b_status.amotion != status->amotion)
  5373. clif_updatestatus(*sd,SP_ASPD);
  5374. if(b_status.speed != status->speed)
  5375. clif_updatestatus(*sd,SP_SPEED);
  5376. if(b_status.batk != status->batk
  5377. #ifndef RENEWAL
  5378. || b_status.rhw.atk != status->rhw.atk || b_status.lhw.atk != status->lhw.atk
  5379. #endif
  5380. )
  5381. clif_updatestatus(*sd,SP_ATK1);
  5382. if(b_status.def != status->def) {
  5383. clif_updatestatus(*sd,SP_DEF1);
  5384. #ifdef RENEWAL
  5385. clif_updatestatus(*sd,SP_DEF2);
  5386. #endif
  5387. }
  5388. if(
  5389. #ifdef RENEWAL
  5390. b_status.watk != status->watk || b_status.watk2 != status->watk2 || b_status.eatk != status->eatk
  5391. #else
  5392. b_status.rhw.atk2 != status->rhw.atk2 || b_status.lhw.atk2 != status->lhw.atk2
  5393. #endif
  5394. )
  5395. clif_updatestatus(*sd,SP_ATK2);
  5396. if(b_status.def2 != status->def2) {
  5397. clif_updatestatus(*sd,SP_DEF2);
  5398. #ifdef RENEWAL
  5399. clif_updatestatus(*sd,SP_DEF1);
  5400. #endif
  5401. }
  5402. if(b_status.flee2 != status->flee2)
  5403. clif_updatestatus(*sd,SP_FLEE2);
  5404. if(b_status.cri != status->cri)
  5405. clif_updatestatus(*sd,SP_CRITICAL);
  5406. #ifndef RENEWAL
  5407. if(b_status.matk_max != status->matk_max)
  5408. clif_updatestatus(*sd,SP_MATK1);
  5409. if(b_status.matk_min != status->matk_min)
  5410. clif_updatestatus(*sd,SP_MATK2);
  5411. #else
  5412. if(b_status.matk_max != status->matk_max || b_status.matk_min != status->matk_min) {
  5413. clif_updatestatus(*sd,SP_MATK2);
  5414. clif_updatestatus(*sd,SP_MATK1);
  5415. }
  5416. #endif
  5417. if(b_status.mdef != status->mdef) {
  5418. clif_updatestatus(*sd,SP_MDEF1);
  5419. #ifdef RENEWAL
  5420. clif_updatestatus(*sd,SP_MDEF2);
  5421. #endif
  5422. }
  5423. if(b_status.mdef2 != status->mdef2) {
  5424. clif_updatestatus(*sd,SP_MDEF2);
  5425. #ifdef RENEWAL
  5426. clif_updatestatus(*sd,SP_MDEF1);
  5427. #endif
  5428. }
  5429. if(b_status.rhw.range != status->rhw.range)
  5430. clif_updatestatus(*sd,SP_ATTACKRANGE);
  5431. if(b_status.max_hp != status->max_hp)
  5432. clif_updatestatus(*sd,SP_MAXHP);
  5433. if(b_status.max_sp != status->max_sp)
  5434. clif_updatestatus(*sd,SP_MAXSP);
  5435. if(b_status.hp != status->hp)
  5436. clif_updatestatus(*sd,SP_HP);
  5437. if(b_status.sp != status->sp)
  5438. clif_updatestatus(*sd,SP_SP);
  5439. #ifdef RENEWAL
  5440. if (b_status.pow != status->pow)
  5441. clif_updatestatus(*sd,SP_POW);
  5442. if (b_status.sta != status->sta)
  5443. clif_updatestatus(*sd,SP_STA);
  5444. if (b_status.wis != status->wis)
  5445. clif_updatestatus(*sd,SP_WIS);
  5446. if (b_status.spl != status->spl)
  5447. clif_updatestatus(*sd,SP_SPL);
  5448. if (b_status.con != status->con)
  5449. clif_updatestatus(*sd,SP_CON);
  5450. if (b_status.crt != status->crt)
  5451. clif_updatestatus(*sd,SP_CRT);
  5452. if (b_status.patk != status->patk)
  5453. clif_updatestatus(*sd, SP_PATK);
  5454. if (b_status.smatk != status->smatk)
  5455. clif_updatestatus(*sd, SP_SMATK);
  5456. if (b_status.res != status->res)
  5457. clif_updatestatus(*sd, SP_RES);
  5458. if (b_status.mres != status->mres)
  5459. clif_updatestatus(*sd, SP_MRES);
  5460. if (b_status.hplus != status->hplus)
  5461. clif_updatestatus(*sd, SP_HPLUS);
  5462. if (b_status.crate != status->crate)
  5463. clif_updatestatus(*sd, SP_CRATE);
  5464. if (b_status.max_ap != status->max_ap)
  5465. clif_updatestatus(*sd, SP_MAXAP);
  5466. if (b_status.ap != status->ap)
  5467. clif_updatestatus(*sd, SP_AP);
  5468. #endif
  5469. } else if( bl->type == BL_HOM ) {
  5470. TBL_HOM* hd = BL_CAST(BL_HOM, bl);
  5471. if( hd->master && memcmp(&b_status, status, sizeof(struct status_data)) != 0 )
  5472. clif_hominfo(hd->master,hd,0);
  5473. } else if( bl->type == BL_MER ) {
  5474. TBL_MER* md = BL_CAST(BL_MER, bl);
  5475. if (!md->master)
  5476. return;
  5477. if( b_status.rhw.atk != status->rhw.atk || b_status.rhw.atk2 != status->rhw.atk2 )
  5478. clif_mercenary_updatestatus(md->master, SP_ATK1);
  5479. if( b_status.matk_max != status->matk_max )
  5480. clif_mercenary_updatestatus(md->master, SP_MATK1);
  5481. if( b_status.hit != status->hit )
  5482. clif_mercenary_updatestatus(md->master, SP_HIT);
  5483. if( b_status.cri != status->cri )
  5484. clif_mercenary_updatestatus(md->master, SP_CRITICAL);
  5485. if( b_status.def != status->def )
  5486. clif_mercenary_updatestatus(md->master, SP_DEF1);
  5487. if( b_status.mdef != status->mdef )
  5488. clif_mercenary_updatestatus(md->master, SP_MDEF1);
  5489. if( b_status.flee != status->flee )
  5490. clif_mercenary_updatestatus(md->master, SP_MERCFLEE);
  5491. if( b_status.amotion != status->amotion )
  5492. clif_mercenary_updatestatus(md->master, SP_ASPD);
  5493. if( b_status.max_hp != status->max_hp )
  5494. clif_mercenary_updatestatus(md->master, SP_MAXHP);
  5495. if( b_status.max_sp != status->max_sp )
  5496. clif_mercenary_updatestatus(md->master, SP_MAXSP);
  5497. if( b_status.hp != status->hp )
  5498. clif_mercenary_updatestatus(md->master, SP_HP);
  5499. if( b_status.sp != status->sp )
  5500. clif_mercenary_updatestatus(md->master, SP_SP);
  5501. } else if( bl->type == BL_ELEM ) {
  5502. TBL_ELEM* ed = BL_CAST(BL_ELEM, bl);
  5503. if (!ed->master)
  5504. return;
  5505. if( b_status.max_hp != status->max_hp )
  5506. clif_elemental_updatestatus(*ed->master, SP_MAXHP);
  5507. if( b_status.max_sp != status->max_sp )
  5508. clif_elemental_updatestatus(*ed->master, SP_MAXSP);
  5509. if( b_status.hp != status->hp )
  5510. clif_elemental_updatestatus(*ed->master, SP_HP);
  5511. if( b_status.sp != status->sp )
  5512. clif_elemental_updatestatus(*ed->master, SP_SP);
  5513. }
  5514. }
  5515. /**
  5516. * Adds strength modifications based on status changes
  5517. * @param bl: Object to change str [PC|MOB|HOM|MER|ELEM]
  5518. * @param sc: Object's status change information
  5519. * @param str: Initial str
  5520. * @return modified str with cap_value(str,0,USHRT_MAX)
  5521. */
  5522. static uint16 status_calc_str(struct block_list *bl, status_change *sc, int32 str)
  5523. {
  5524. if(sc == nullptr || sc->empty())
  5525. return cap_value(str,0,USHRT_MAX);
  5526. if(sc->getSCE(SC_HARMONIZE)) {
  5527. str -= sc->getSCE(SC_HARMONIZE)->val2;
  5528. return (uint16)cap_value(str,0,USHRT_MAX);
  5529. }
  5530. if(sc->getSCE(SC_INCALLSTATUS))
  5531. str += sc->getSCE(SC_INCALLSTATUS)->val1;
  5532. if(sc->getSCE(SC_CHASEWALK2))
  5533. str += sc->getSCE(SC_CHASEWALK2)->val1;
  5534. if(sc->getSCE(SC_BATTLEORDERS))
  5535. str += 5;
  5536. if(sc->getSCE(SC_LEADERSHIP))
  5537. str += sc->getSCE(SC_LEADERSHIP)->val1;
  5538. if(sc->getSCE(SC_LOUD))
  5539. str += 4;
  5540. if(sc->getSCE(SC_TRUESIGHT))
  5541. str += 5;
  5542. if(sc->getSCE(SC_SPURT))
  5543. str += 10;
  5544. if(sc->getSCE(SC_NEN))
  5545. str += sc->getSCE(SC_NEN)->val1;
  5546. if(sc->getSCE(SC_BLESSING)) {
  5547. if(sc->getSCE(SC_BLESSING)->val2)
  5548. str += sc->getSCE(SC_BLESSING)->val2;
  5549. else
  5550. str -= str / 2;
  5551. }
  5552. if(sc->getSCE(SC_MARIONETTE))
  5553. str -= ((sc->getSCE(SC_MARIONETTE)->val3)>>16)&0xFF;
  5554. if(sc->getSCE(SC_MARIONETTE2))
  5555. str += ((sc->getSCE(SC_MARIONETTE2)->val3)>>16)&0xFF;
  5556. if(sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_HIGH)
  5557. str += ((sc->getSCE(SC_SPIRIT)->val3)>>16)&0xFF;
  5558. if(sc->getSCE(SC_GIANTGROWTH))
  5559. str += sc->getSCE(SC_GIANTGROWTH)->val2;
  5560. if(sc->getSCE(SC_BEYONDOFWARCRY))
  5561. str -= sc->getSCE(SC_BEYONDOFWARCRY)->val2;
  5562. if(sc->getSCE(SC_INSPIRATION))
  5563. str += sc->getSCE(SC_INSPIRATION)->val3;
  5564. if(sc->getSCE(SC_STOMACHACHE))
  5565. str -= sc->getSCE(SC_STOMACHACHE)->val1;
  5566. if(sc->getSCE(SC_KYOUGAKU))
  5567. str -= sc->getSCE(SC_KYOUGAKU)->val2;
  5568. if(sc->getSCE(SC_SWORDCLAN))
  5569. str += 1;
  5570. if(sc->getSCE(SC_JUMPINGCLAN))
  5571. str += 1;
  5572. if(sc->getSCE(SC_FULL_THROTTLE))
  5573. str += str * sc->getSCE(SC_FULL_THROTTLE)->val3 / 100;
  5574. if(sc->getSCE(SC_CHEERUP))
  5575. str += 3;
  5576. #ifdef RENEWAL
  5577. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_ALLSTAT)
  5578. str += 15;
  5579. #endif
  5580. if (sc->getSCE(SC_UNIVERSESTANCE))
  5581. str += sc->getSCE(SC_UNIVERSESTANCE)->val2;
  5582. if (sc->getSCE(SC_ALL_STAT_DOWN))
  5583. str -= sc->getSCE(SC_ALL_STAT_DOWN)->val2;
  5584. //TODO: Stat points should be able to be decreased below 0
  5585. return (uint16)cap_value(str,0,USHRT_MAX);
  5586. }
  5587. /**
  5588. * Adds agility modifications based on status changes
  5589. * @param bl: Object to change agi [PC|MOB|HOM|MER|ELEM]
  5590. * @param sc: Object's status change information
  5591. * @param agi: Initial agi
  5592. * @return modified agi with cap_value(agi,0,USHRT_MAX)
  5593. */
  5594. static uint16 status_calc_agi(struct block_list *bl, status_change *sc, int32 agi)
  5595. {
  5596. if(sc == nullptr || sc->empty())
  5597. return cap_value(agi,0,USHRT_MAX);
  5598. if(sc->getSCE(SC_HARMONIZE)) {
  5599. agi -= sc->getSCE(SC_HARMONIZE)->val2;
  5600. return (uint16)cap_value(agi,0,USHRT_MAX);
  5601. }
  5602. if(sc->getSCE(SC_CONCENTRATE) && !sc->getSCE(SC_QUAGMIRE))
  5603. agi += (agi-sc->getSCE(SC_CONCENTRATE)->val3)*sc->getSCE(SC_CONCENTRATE)->val2/100;
  5604. if(sc->getSCE(SC_INCALLSTATUS))
  5605. agi += sc->getSCE(SC_INCALLSTATUS)->val1;
  5606. if(sc->getSCE(SC_SOULCOLD))
  5607. agi += sc->getSCE(SC_SOULCOLD)->val1;
  5608. if(sc->getSCE(SC_TRUESIGHT))
  5609. agi += 5;
  5610. if(sc->getSCE(SC_INCREASEAGI))
  5611. agi += sc->getSCE(SC_INCREASEAGI)->val2;
  5612. if(sc->getSCE(SC_INCREASING))
  5613. agi += 4; // Added based on skill updates [Reddozen]
  5614. if(sc->getSCE(SC_DECREASEAGI))
  5615. agi -= sc->getSCE(SC_DECREASEAGI)->val2;
  5616. if(sc->getSCE(SC_QUAGMIRE))
  5617. agi -= sc->getSCE(SC_QUAGMIRE)->val2;
  5618. if(sc->getSCE(SC_SUITON) && sc->getSCE(SC_SUITON)->val3)
  5619. agi -= sc->getSCE(SC_SUITON)->val2;
  5620. if(sc->getSCE(SC_MARIONETTE))
  5621. agi -= ((sc->getSCE(SC_MARIONETTE)->val3)>>8)&0xFF;
  5622. if(sc->getSCE(SC_MARIONETTE2))
  5623. agi += ((sc->getSCE(SC_MARIONETTE2)->val3)>>8)&0xFF;
  5624. if(sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_HIGH)
  5625. agi += ((sc->getSCE(SC_SPIRIT)->val3)>>8)&0xFF;
  5626. if(sc->getSCE(SC_ADORAMUS))
  5627. agi -= sc->getSCE(SC_ADORAMUS)->val2;
  5628. if(sc->getSCE(SC_MARSHOFABYSS))
  5629. agi -= agi * sc->getSCE(SC_MARSHOFABYSS)->val2 / 100;
  5630. if(sc->getSCE(SC_INSPIRATION))
  5631. agi += sc->getSCE(SC_INSPIRATION)->val3;
  5632. if(sc->getSCE(SC_STOMACHACHE))
  5633. agi -= sc->getSCE(SC_STOMACHACHE)->val1;
  5634. if(sc->getSCE(SC_KYOUGAKU))
  5635. agi -= sc->getSCE(SC_KYOUGAKU)->val2;
  5636. if(sc->getSCE(SC_CROSSBOWCLAN))
  5637. agi += 1;
  5638. if(sc->getSCE(SC_JUMPINGCLAN))
  5639. agi += 1;
  5640. if(sc->getSCE(SC_FULL_THROTTLE))
  5641. agi += agi * sc->getSCE(SC_FULL_THROTTLE)->val3 / 100;
  5642. if (sc->getSCE(SC_ARCLOUSEDASH))
  5643. agi += sc->getSCE(SC_ARCLOUSEDASH)->val2;
  5644. if(sc->getSCE(SC_CHEERUP))
  5645. agi += 3;
  5646. #ifdef RENEWAL
  5647. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_ALLSTAT)
  5648. agi += 15;
  5649. #endif
  5650. if (sc->getSCE(SC_UNIVERSESTANCE))
  5651. agi += sc->getSCE(SC_UNIVERSESTANCE)->val2;
  5652. if (sc->getSCE(SC_ALL_STAT_DOWN))
  5653. agi -= sc->getSCE(SC_ALL_STAT_DOWN)->val2;
  5654. //TODO: Stat points should be able to be decreased below 0
  5655. return (uint16)cap_value(agi,0,USHRT_MAX);
  5656. }
  5657. /**
  5658. * Adds vitality modifications based on status changes
  5659. * @param bl: Object to change vit [PC|MOB|HOM|MER|ELEM]
  5660. * @param sc: Object's status change information
  5661. * @param vit: Initial vit
  5662. * @return modified vit with cap_value(vit,0,USHRT_MAX)
  5663. */
  5664. static uint16 status_calc_vit(struct block_list *bl, status_change *sc, int32 vit)
  5665. {
  5666. if(sc == nullptr || sc->empty())
  5667. return cap_value(vit,0,USHRT_MAX);
  5668. if(sc->getSCE(SC_HARMONIZE)) {
  5669. vit -= sc->getSCE(SC_HARMONIZE)->val2;
  5670. return (uint16)cap_value(vit,0,USHRT_MAX);
  5671. }
  5672. if(sc->getSCE(SC_INCALLSTATUS))
  5673. vit += sc->getSCE(SC_INCALLSTATUS)->val1;
  5674. if(sc->getSCE(SC_CHANGE))
  5675. vit += sc->getSCE(SC_CHANGE)->val2;
  5676. if(sc->getSCE(SC_GLORYWOUNDS))
  5677. vit += sc->getSCE(SC_GLORYWOUNDS)->val1;
  5678. if(sc->getSCE(SC_TRUESIGHT))
  5679. vit += 5;
  5680. if(sc->getSCE(SC_MARIONETTE))
  5681. vit -= sc->getSCE(SC_MARIONETTE)->val3&0xFF;
  5682. if(sc->getSCE(SC_MARIONETTE2))
  5683. vit += sc->getSCE(SC_MARIONETTE2)->val3&0xFF;
  5684. if(sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_HIGH)
  5685. vit += sc->getSCE(SC_SPIRIT)->val3&0xFF;
  5686. if(sc->getSCE(SC_INSPIRATION))
  5687. vit += sc->getSCE(SC_INSPIRATION)->val3;
  5688. if(sc->getSCE(SC_STOMACHACHE))
  5689. vit -= sc->getSCE(SC_STOMACHACHE)->val1;
  5690. if(sc->getSCE(SC_KYOUGAKU))
  5691. vit -= sc->getSCE(SC_KYOUGAKU)->val2;
  5692. if(sc->getSCE(SC_SWORDCLAN))
  5693. vit += 1;
  5694. if(sc->getSCE(SC_JUMPINGCLAN))
  5695. vit += 1;
  5696. if(sc->getSCE(SC_STRIPARMOR) && bl->type != BL_PC)
  5697. vit -= vit * sc->getSCE(SC_STRIPARMOR)->val2/100;
  5698. if(sc->getSCE(SC_FULL_THROTTLE))
  5699. vit += vit * sc->getSCE(SC_FULL_THROTTLE)->val3 / 100;
  5700. if(bl->type == BL_PC && sc->getSCE(SC_DEFENCE))
  5701. vit += sc->getSCE(SC_DEFENCE)->val2;
  5702. if(sc->getSCE(SC_CHEERUP))
  5703. vit += 3;
  5704. #ifdef RENEWAL
  5705. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_ALLSTAT)
  5706. vit += 15;
  5707. #endif
  5708. if (sc->getSCE(SC_UNIVERSESTANCE))
  5709. vit += sc->getSCE(SC_UNIVERSESTANCE)->val2;
  5710. if (sc->getSCE(SC_ALL_STAT_DOWN))
  5711. vit -= sc->getSCE(SC_ALL_STAT_DOWN)->val2;
  5712. //TODO: Stat points should be able to be decreased below 0
  5713. return (uint16)cap_value(vit,0,USHRT_MAX);
  5714. }
  5715. /**
  5716. * Adds intelligence modifications based on status changes
  5717. * @param bl: Object to change int32 [PC|MOB|HOM|MER|ELEM]
  5718. * @param sc: Object's status change information
  5719. * @param int_: Initial int32
  5720. * @return modified int32 with cap_value(int_,0,USHRT_MAX)
  5721. */
  5722. static uint16 status_calc_int(struct block_list *bl, status_change *sc, int32 int_)
  5723. {
  5724. if(sc == nullptr || sc->empty())
  5725. return cap_value(int_,0,USHRT_MAX);
  5726. if(sc->getSCE(SC_HARMONIZE)) {
  5727. int_ -= sc->getSCE(SC_HARMONIZE)->val2;
  5728. return (uint16)cap_value(int_,0,USHRT_MAX);
  5729. }
  5730. if(sc->getSCE(SC_INCALLSTATUS))
  5731. int_ += sc->getSCE(SC_INCALLSTATUS)->val1;
  5732. if(sc->getSCE(SC_CHANGE))
  5733. int_ += sc->getSCE(SC_CHANGE)->val3;
  5734. if(sc->getSCE(SC_BATTLEORDERS))
  5735. int_ += 5;
  5736. if(sc->getSCE(SC_TRUESIGHT))
  5737. int_ += 5;
  5738. if(sc->getSCE(SC_BLESSING)) {
  5739. if (sc->getSCE(SC_BLESSING)->val2)
  5740. int_ += sc->getSCE(SC_BLESSING)->val2;
  5741. else
  5742. int_ -= int_ / 2;
  5743. }
  5744. if(sc->getSCE(SC_NEN))
  5745. int_ += sc->getSCE(SC_NEN)->val1;
  5746. if(sc->getSCE(SC_MARIONETTE))
  5747. int_ -= ((sc->getSCE(SC_MARIONETTE)->val4)>>16)&0xFF;
  5748. if(sc->getSCE(SC_MARIONETTE2))
  5749. int_ += ((sc->getSCE(SC_MARIONETTE2)->val4)>>16)&0xFF;
  5750. if(sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_HIGH)
  5751. int_ += ((sc->getSCE(SC_SPIRIT)->val4)>>16)&0xFF;
  5752. if(sc->getSCE(SC_INSPIRATION))
  5753. int_ += sc->getSCE(SC_INSPIRATION)->val3;
  5754. if(sc->getSCE(SC_MELODYOFSINK))
  5755. int_ -= sc->getSCE(SC_MELODYOFSINK)->val2;
  5756. if(sc->getSCE(SC_MANDRAGORA))
  5757. int_ -= 4 * sc->getSCE(SC_MANDRAGORA)->val1;
  5758. if(sc->getSCE(SC_STOMACHACHE))
  5759. int_ -= sc->getSCE(SC_STOMACHACHE)->val1;
  5760. if(sc->getSCE(SC_KYOUGAKU))
  5761. int_ -= sc->getSCE(SC_KYOUGAKU)->val2;
  5762. if(sc->getSCE(SC_ARCWANDCLAN))
  5763. int_ += 1;
  5764. if(sc->getSCE(SC_GOLDENMACECLAN))
  5765. int_ += 1;
  5766. if(sc->getSCE(SC_JUMPINGCLAN))
  5767. int_ += 1;
  5768. if(sc->getSCE(SC_FULL_THROTTLE))
  5769. int_ += int_ * sc->getSCE(SC_FULL_THROTTLE)->val3 / 100;
  5770. if(sc->getSCE(SC_CHEERUP))
  5771. int_ += 3;
  5772. if (sc->getSCE(SC_UNIVERSESTANCE))
  5773. int_ += sc->getSCE(SC_UNIVERSESTANCE)->val2;
  5774. if(bl->type != BL_PC) {
  5775. if(sc->getSCE(SC_STRIPHELM))
  5776. int_ -= int_ * sc->getSCE(SC_STRIPHELM)->val2/100;
  5777. if(sc->getSCE(SC__STRIPACCESSORY))
  5778. int_ -= int_ * sc->getSCE(SC__STRIPACCESSORY)->val2 / 100;
  5779. }
  5780. #ifdef RENEWAL
  5781. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_ALLSTAT)
  5782. int_ += 15;
  5783. #endif
  5784. if (sc->getSCE(SC_ALL_STAT_DOWN))
  5785. int_ -= sc->getSCE(SC_ALL_STAT_DOWN)->val2;
  5786. //TODO: Stat points should be able to be decreased below 0
  5787. return (uint16)cap_value(int_,0,USHRT_MAX);
  5788. }
  5789. /**
  5790. * Adds dexterity modifications based on status changes
  5791. * @param bl: Object to change dex [PC|MOB|HOM|MER|ELEM]
  5792. * @param sc: Object's status change information
  5793. * @param dex: Initial dex
  5794. * @return modified dex with cap_value(dex,0,USHRT_MAX)
  5795. */
  5796. static uint16 status_calc_dex(struct block_list *bl, status_change *sc, int32 dex)
  5797. {
  5798. if(sc == nullptr || sc->empty())
  5799. return cap_value(dex,0,USHRT_MAX);
  5800. if(sc->getSCE(SC_HARMONIZE)) {
  5801. dex -= sc->getSCE(SC_HARMONIZE)->val2;
  5802. return (uint16)cap_value(dex,0,USHRT_MAX);
  5803. }
  5804. if(sc->getSCE(SC_CONCENTRATE) && !sc->getSCE(SC_QUAGMIRE))
  5805. dex += (dex-sc->getSCE(SC_CONCENTRATE)->val4)*sc->getSCE(SC_CONCENTRATE)->val2/100;
  5806. if(sc->getSCE(SC_INCALLSTATUS))
  5807. dex += sc->getSCE(SC_INCALLSTATUS)->val1;
  5808. if(sc->getSCE(SC_BATTLEORDERS))
  5809. dex += 5;
  5810. if(sc->getSCE(SC_HAWKEYES))
  5811. dex += sc->getSCE(SC_HAWKEYES)->val1;
  5812. if(sc->getSCE(SC_TRUESIGHT))
  5813. dex += 5;
  5814. if(sc->getSCE(SC_QUAGMIRE))
  5815. dex -= sc->getSCE(SC_QUAGMIRE)->val2;
  5816. if(sc->getSCE(SC_BLESSING)) {
  5817. if (sc->getSCE(SC_BLESSING)->val2)
  5818. dex += sc->getSCE(SC_BLESSING)->val2;
  5819. else
  5820. dex -= dex / 2;
  5821. }
  5822. if(sc->getSCE(SC_INCREASING))
  5823. dex += 4; // Added based on skill updates [Reddozen]
  5824. if(sc->getSCE(SC_MARIONETTE))
  5825. dex -= ((sc->getSCE(SC_MARIONETTE)->val4)>>8)&0xFF;
  5826. if(sc->getSCE(SC_MARIONETTE2))
  5827. dex += ((sc->getSCE(SC_MARIONETTE2)->val4)>>8)&0xFF;
  5828. if(sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_HIGH)
  5829. dex += ((sc->getSCE(SC_SPIRIT)->val4)>>8)&0xFF;
  5830. if(sc->getSCE(SC_INSPIRATION))
  5831. dex += sc->getSCE(SC_INSPIRATION)->val3;
  5832. if(sc->getSCE(SC_STOMACHACHE))
  5833. dex -= sc->getSCE(SC_STOMACHACHE)->val1;
  5834. if(sc->getSCE(SC_KYOUGAKU))
  5835. dex -= sc->getSCE(SC_KYOUGAKU)->val2;
  5836. if(sc->getSCE(SC_ARCWANDCLAN))
  5837. dex += 1;
  5838. if(sc->getSCE(SC_CROSSBOWCLAN))
  5839. dex += 1;
  5840. if(sc->getSCE(SC_JUMPINGCLAN))
  5841. dex += 1;
  5842. if(sc->getSCE(SC__STRIPACCESSORY) && bl->type != BL_PC)
  5843. dex -= dex * sc->getSCE(SC__STRIPACCESSORY)->val2 / 100;
  5844. if(sc->getSCE(SC_MARSHOFABYSS))
  5845. dex -= dex * sc->getSCE(SC_MARSHOFABYSS)->val2 / 100;
  5846. if(sc->getSCE(SC_FULL_THROTTLE))
  5847. dex += dex * sc->getSCE(SC_FULL_THROTTLE)->val3 / 100;
  5848. if(sc->getSCE(SC_CHEERUP))
  5849. dex += 3;
  5850. #ifdef RENEWAL
  5851. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_ALLSTAT)
  5852. dex += 15;
  5853. #endif
  5854. if (sc->getSCE(SC_UNIVERSESTANCE))
  5855. dex += sc->getSCE(SC_UNIVERSESTANCE)->val2;
  5856. if (sc->getSCE(SC_ALL_STAT_DOWN))
  5857. dex -= sc->getSCE(SC_ALL_STAT_DOWN)->val2;
  5858. //TODO: Stat points should be able to be decreased below 0
  5859. return (uint16)cap_value(dex,0,USHRT_MAX);
  5860. }
  5861. /**
  5862. * Adds luck modifications based on status changes
  5863. * @param bl: Object to change luk [PC|MOB|HOM|MER|ELEM]
  5864. * @param sc: Object's status change information
  5865. * @param luk: Initial luk
  5866. * @return modified luk with cap_value(luk,0,USHRT_MAX)
  5867. */
  5868. static uint16 status_calc_luk(struct block_list *bl, status_change *sc, int32 luk)
  5869. {
  5870. if(sc == nullptr || sc->empty())
  5871. return cap_value(luk,0,USHRT_MAX);
  5872. if(sc->getSCE(SC_HARMONIZE)) {
  5873. luk -= sc->getSCE(SC_HARMONIZE)->val2;
  5874. return (uint16)cap_value(luk,0,USHRT_MAX);
  5875. }
  5876. if(sc->getSCE(SC_CURSE))
  5877. return 0;
  5878. if(sc->getSCE(SC_INCALLSTATUS))
  5879. luk += sc->getSCE(SC_INCALLSTATUS)->val1;
  5880. if(sc->getSCE(SC_TRUESIGHT))
  5881. luk += 5;
  5882. if(sc->getSCE(SC_GLORIA))
  5883. luk += 30;
  5884. if(sc->getSCE(SC_MARIONETTE))
  5885. luk -= sc->getSCE(SC_MARIONETTE)->val4&0xFF;
  5886. if(sc->getSCE(SC_MARIONETTE2))
  5887. luk += sc->getSCE(SC_MARIONETTE2)->val4&0xFF;
  5888. if(sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_HIGH)
  5889. luk += sc->getSCE(SC_SPIRIT)->val4&0xFF;
  5890. if(sc->getSCE(SC_INSPIRATION))
  5891. luk += sc->getSCE(SC_INSPIRATION)->val3;
  5892. if(sc->getSCE(SC_STOMACHACHE))
  5893. luk -= sc->getSCE(SC_STOMACHACHE)->val1;
  5894. if(sc->getSCE(SC_KYOUGAKU))
  5895. luk -= sc->getSCE(SC_KYOUGAKU)->val2;
  5896. if(sc->getSCE(SC__STRIPACCESSORY) && bl->type != BL_PC)
  5897. luk -= luk * sc->getSCE(SC__STRIPACCESSORY)->val2 / 100;
  5898. if(sc->getSCE(SC_BANANA_BOMB))
  5899. luk -= 75;
  5900. if(sc->getSCE(SC_GOLDENMACECLAN))
  5901. luk += 1;
  5902. if(sc->getSCE(SC_JUMPINGCLAN))
  5903. luk += 1;
  5904. if(sc->getSCE(SC_FULL_THROTTLE))
  5905. luk += luk * sc->getSCE(SC_FULL_THROTTLE)->val3 / 100;
  5906. if(sc->getSCE(SC_CHEERUP))
  5907. luk += 3;
  5908. #ifdef RENEWAL
  5909. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_ALLSTAT)
  5910. luk += 15;
  5911. #endif
  5912. if (sc->getSCE(SC_UNIVERSESTANCE))
  5913. luk += sc->getSCE(SC_UNIVERSESTANCE)->val2;
  5914. if (sc->getSCE(SC_ALL_STAT_DOWN))
  5915. luk -= sc->getSCE(SC_ALL_STAT_DOWN)->val2;
  5916. //TODO: Stat points should be able to be decreased below 0
  5917. return (uint16)cap_value(luk,0,USHRT_MAX);
  5918. }
  5919. /**
  5920. * Adds power modifications based on status changes
  5921. * @param bl: Object to change pow [PC|MOB|HOM|MER|ELEM]
  5922. * @param sc: Object's status change information
  5923. * @param pow: Initial pow
  5924. * @return modified pow with cap_value(pow,0,USHRT_MAX)
  5925. */
  5926. static uint16 status_calc_pow(struct block_list *bl, status_change *sc, int32 pow)
  5927. {
  5928. if (sc == nullptr || sc->empty())
  5929. return cap_value(pow, 0, USHRT_MAX);
  5930. if (sc->getSCE(SC_BENEDICTUM))
  5931. pow += sc->getSCE(SC_BENEDICTUM)->val2;
  5932. if (sc->getSCE(SC_MARINE_FESTIVAL) != nullptr)
  5933. pow += sc->getSCE(SC_MARINE_FESTIVAL)->val2;
  5934. return (uint16)cap_value(pow, 0, USHRT_MAX);
  5935. }
  5936. /**
  5937. * Adds stamina modifications based on status changes
  5938. * @param bl: Object to change sta [PC|MOB|HOM|MER|ELEM]
  5939. * @param sc: Object's status change information
  5940. * @param sta: Initial sta
  5941. * @return modified sta with cap_value(sta,0,USHRT_MAX)
  5942. */
  5943. static uint16 status_calc_sta(struct block_list *bl, status_change *sc, int32 sta)
  5944. {
  5945. if (sc == nullptr || sc->empty())
  5946. return cap_value(sta, 0, USHRT_MAX);
  5947. if (sc->getSCE(SC_RELIGIO))
  5948. sta += sc->getSCE(SC_RELIGIO)->val2;
  5949. if (sc->getSCE(SC_SANDY_FESTIVAL) != nullptr)
  5950. sta += sc->getSCE(SC_SANDY_FESTIVAL)->val2;
  5951. return (uint16)cap_value(sta, 0, USHRT_MAX);
  5952. }
  5953. /**
  5954. * Adds wisdom modifications based on status changes
  5955. * @param bl: Object to change wis [PC|MOB|HOM|MER|ELEM]
  5956. * @param sc: Object's status change information
  5957. * @param wis: Initial wis
  5958. * @return modified wis with cap_value(wis,0,USHRT_MAX)
  5959. */
  5960. static uint16 status_calc_wis(struct block_list *bl, status_change *sc, int32 wis)
  5961. {
  5962. if (sc == nullptr || sc->empty())
  5963. return cap_value(wis, 0, USHRT_MAX);
  5964. if (sc->getSCE(SC_RELIGIO))
  5965. wis += sc->getSCE(SC_RELIGIO)->val2;
  5966. if (sc->getSCE(SC_SANDY_FESTIVAL) != nullptr)
  5967. wis += sc->getSCE(SC_SANDY_FESTIVAL)->val2;
  5968. return (uint16)cap_value(wis, 0, USHRT_MAX);
  5969. }
  5970. /**
  5971. * Adds spell modifications based on status changes
  5972. * @param bl: Object to change spl [PC|MOB|HOM|MER|ELEM]
  5973. * @param sc: Object's status change information
  5974. * @param spl: Initial spl
  5975. * @return modified spl with cap_value(spl,0,USHRT_MAX)
  5976. */
  5977. static uint16 status_calc_spl(struct block_list *bl, status_change *sc, int32 spl)
  5978. {
  5979. if (sc == nullptr || sc->empty())
  5980. return cap_value(spl, 0, USHRT_MAX);
  5981. if (sc->getSCE(SC_RELIGIO))
  5982. spl += sc->getSCE(SC_RELIGIO)->val2;
  5983. if (sc->getSCE(SC_SANDY_FESTIVAL) != nullptr)
  5984. spl += sc->getSCE(SC_SANDY_FESTIVAL)->val2;
  5985. return (uint16)cap_value(spl, 0, USHRT_MAX);
  5986. }
  5987. /**
  5988. * Adds concentration modifications based on status changes
  5989. * @param bl: Object to change con [PC|MOB|HOM|MER|ELEM]
  5990. * @param sc: Object's status change information
  5991. * @param con: Initial con
  5992. * @return modified con with cap_value(con,0,USHRT_MAX)
  5993. */
  5994. static uint16 status_calc_con(struct block_list *bl, status_change *sc, int32 con)
  5995. {
  5996. if (sc == nullptr || sc->empty())
  5997. return cap_value(con, 0, USHRT_MAX);
  5998. if (sc->getSCE(SC_BENEDICTUM))
  5999. con += sc->getSCE(SC_BENEDICTUM)->val2;
  6000. if (sc->getSCE(SC_MARINE_FESTIVAL) != nullptr)
  6001. con += sc->getSCE(SC_MARINE_FESTIVAL)->val2;
  6002. return (uint16)cap_value(con, 0, USHRT_MAX);
  6003. }
  6004. /**
  6005. * Adds creative modifications based on status changes
  6006. * @param bl: Object to change crt [PC|MOB|HOM|MER|ELEM]
  6007. * @param sc: Object's status change information
  6008. * @param crt: Initial crt
  6009. * @return modified crt with cap_value(crt,0,USHRT_MAX)
  6010. */
  6011. static uint16 status_calc_crt(struct block_list *bl, status_change *sc, int32 crt)
  6012. {
  6013. if (sc == nullptr || sc->empty())
  6014. return cap_value(crt, 0, USHRT_MAX);
  6015. if (sc->getSCE(SC_BENEDICTUM))
  6016. crt += sc->getSCE(SC_BENEDICTUM)->val2;
  6017. if (sc->getSCE(SC_MARINE_FESTIVAL) != nullptr)
  6018. crt += sc->getSCE(SC_MARINE_FESTIVAL)->val2;
  6019. return (uint16)cap_value(crt, 0, USHRT_MAX);
  6020. }
  6021. /**
  6022. * Adds base attack modifications based on status changes
  6023. * @param bl: Object to change batk [PC|MOB|HOM|MER|ELEM]
  6024. * @param sc: Object's status change information
  6025. * @param batk: Initial batk
  6026. * @return modified batk with cap_value(batk,0,USHRT_MAX)
  6027. */
  6028. static uint16 status_calc_batk(struct block_list *bl, status_change *sc, int32 batk)
  6029. {
  6030. if(sc == nullptr || sc->empty())
  6031. return cap_value(batk,0,USHRT_MAX);
  6032. if (sc->getSCE(SC_VOLCANO))
  6033. batk += sc->getSCE(SC_VOLCANO)->val2;
  6034. #ifndef RENEWAL
  6035. if(sc->getSCE(SC_GATLINGFEVER))
  6036. batk += sc->getSCE(SC_GATLINGFEVER)->val3;
  6037. if(sc->getSCE(SC_MADNESSCANCEL))
  6038. batk += 100;
  6039. #endif
  6040. if(sc->getSCE(SC_ASH))
  6041. batk -= batk * sc->getSCE(SC_ASH)->val4 / 100;
  6042. if(bl->type == BL_HOM && sc->getSCE(SC_PYROCLASTIC))
  6043. batk += sc->getSCE(SC_PYROCLASTIC)->val2;
  6044. if (sc->getSCE(SC_ANGRIFFS_MODUS))
  6045. batk += sc->getSCE(SC_ANGRIFFS_MODUS)->val2;
  6046. if(sc->getSCE(SC__ENERVATION))
  6047. batk -= batk * sc->getSCE(SC__ENERVATION)->val2 / 100;
  6048. if( sc->getSCE(SC_ZANGETSU) )
  6049. batk += sc->getSCE(SC_ZANGETSU)->val2;
  6050. #ifdef RENEWAL
  6051. if (sc->getSCE(SC_LOUD))
  6052. batk += 30;
  6053. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_ATKRATE)
  6054. batk += batk * 20 / 100;
  6055. #endif
  6056. if (sc->getSCE(SC_SUNSTANCE))
  6057. batk += batk * sc->getSCE(SC_SUNSTANCE)->val2 / 100;
  6058. if (sc->getSCE(SC_INTENSIVE_AIM))
  6059. batk += 150;
  6060. return (uint16)cap_value(batk,0,USHRT_MAX);
  6061. }
  6062. /**
  6063. * Adds weapon attack modifications based on status changes
  6064. * @param bl: Object to change watk [PC]
  6065. * @param sc: Object's status change information
  6066. * @param watk: Initial watk
  6067. * @return modified watk with cap_value(watk,0,USHRT_MAX)
  6068. */
  6069. static uint16 status_calc_watk(struct block_list *bl, status_change *sc, int32 watk)
  6070. {
  6071. if(sc == nullptr || sc->empty())
  6072. return cap_value(watk,0,USHRT_MAX);
  6073. #ifndef RENEWAL
  6074. if(sc->getSCE(SC_DRUMBATTLE))
  6075. watk += sc->getSCE(SC_DRUMBATTLE)->val2;
  6076. #endif
  6077. if (sc->getSCE(SC_IMPOSITIO))
  6078. watk += sc->getSCE(SC_IMPOSITIO)->val2;
  6079. if(sc->getSCE(SC_WATKFOOD))
  6080. watk += sc->getSCE(SC_WATKFOOD)->val1;
  6081. if (sc->getSCE(SC_VOLCANO) && bl->type == BL_MOB)
  6082. watk += sc->getSCE(SC_VOLCANO)->val2;
  6083. if(sc->getSCE(SC_MERC_ATKUP))
  6084. watk += sc->getSCE(SC_MERC_ATKUP)->val2;
  6085. if(sc->getSCE(SC_WATER_BARRIER))
  6086. watk -= sc->getSCE(SC_WATER_BARRIER)->val2;
  6087. #ifndef RENEWAL
  6088. if(sc->getSCE(SC_NIBELUNGEN)) {
  6089. if (bl->type != BL_PC)
  6090. watk += sc->getSCE(SC_NIBELUNGEN)->val2;
  6091. else {
  6092. TBL_PC *sd = (TBL_PC*)bl;
  6093. int16 index = sd->equip_index[sd->state.lr_flag != LR_FLAG_NONE ? EQI_HAND_L : EQI_HAND_R];
  6094. if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON && sd->inventory_data[index]->weapon_level == 4)
  6095. watk += sc->getSCE(SC_NIBELUNGEN)->val2;
  6096. }
  6097. }
  6098. #endif
  6099. if(sc->getSCE(SC_FIGHTINGSPIRIT))
  6100. watk += sc->getSCE(SC_FIGHTINGSPIRIT)->val1;
  6101. if (sc->getSCE(SC_SHIELDSPELL_ATK))
  6102. watk += sc->getSCE(SC_SHIELDSPELL_ATK)->val2;
  6103. if(sc->getSCE(SC_INSPIRATION))
  6104. watk += sc->getSCE(SC_INSPIRATION)->val2;
  6105. if(sc->getSCE(SC_GT_CHANGE))
  6106. watk += sc->getSCE(SC_GT_CHANGE)->val2;
  6107. if(sc->getSCE(SC__ENERVATION))
  6108. watk -= watk * sc->getSCE(SC__ENERVATION)->val2 / 100;
  6109. if(sc->getSCE(SC_STRIKING))
  6110. watk += sc->getSCE(SC_STRIKING)->val2;
  6111. if(sc->getSCE(SC_RUSHWINDMILL))
  6112. watk += sc->getSCE(SC_RUSHWINDMILL)->val3;
  6113. if(sc->getSCE(SC_FIRE_INSIGNIA) && sc->getSCE(SC_FIRE_INSIGNIA)->val1 == 2)
  6114. watk += 50;
  6115. if((sc->getSCE(SC_FIRE_INSIGNIA) && sc->getSCE(SC_FIRE_INSIGNIA)->val1 == 2)
  6116. || (sc->getSCE(SC_WATER_INSIGNIA) && sc->getSCE(SC_WATER_INSIGNIA)->val1 == 2)
  6117. || (sc->getSCE(SC_WIND_INSIGNIA) && sc->getSCE(SC_WIND_INSIGNIA)->val1 == 2)
  6118. || (sc->getSCE(SC_EARTH_INSIGNIA) && sc->getSCE(SC_EARTH_INSIGNIA)->val1 == 2))
  6119. watk += watk * 10 / 100;
  6120. if(sc->getSCE(SC_PYROTECHNIC_OPTION))
  6121. watk += sc->getSCE(SC_PYROTECHNIC_OPTION)->val2;
  6122. if(sc->getSCE(SC_HEATER_OPTION))
  6123. watk += sc->getSCE(SC_HEATER_OPTION)->val2;
  6124. if(sc->getSCE(SC_TROPIC_OPTION))
  6125. watk += sc->getSCE(SC_TROPIC_OPTION)->val2;
  6126. if( sc && sc->getSCE(SC_TIDAL_WEAPON) )
  6127. watk += watk * sc->getSCE(SC_TIDAL_WEAPON)->val2 / 100;
  6128. if(bl->type == BL_PC && sc->getSCE(SC_PYROCLASTIC))
  6129. watk += sc->getSCE(SC_PYROCLASTIC)->val2;
  6130. if(sc->getSCE(SC_ANGRIFFS_MODUS))
  6131. watk += watk * sc->getSCE(SC_ANGRIFFS_MODUS)->val2/100;
  6132. if(sc->getSCE(SC_ODINS_POWER))
  6133. watk += 40 + 30 * sc->getSCE(SC_ODINS_POWER)->val1;
  6134. if (sc->getSCE(SC_FLASHCOMBO))
  6135. watk += sc->getSCE(SC_FLASHCOMBO)->val2;
  6136. if (sc->getSCE(SC_CATNIPPOWDER))
  6137. watk += watk * sc->getSCE(SC_CATNIPPOWDER)->val2 / 100;
  6138. if (sc->getSCE(SC_CHATTERING))
  6139. watk += sc->getSCE(SC_CHATTERING)->val2;
  6140. if (sc->getSCE(SC_SUNSTANCE))
  6141. watk += watk * sc->getSCE(SC_SUNSTANCE)->val2 / 100;
  6142. if (sc->getSCE(SC_SOULFALCON))
  6143. watk += sc->getSCE(SC_SOULFALCON)->val2;
  6144. if (sc->getSCE(SC_POWERFUL_FAITH))
  6145. watk += sc->getSCE(SC_POWERFUL_FAITH)->val2;
  6146. if (sc->getSCE(SC_GUARD_STANCE))
  6147. watk -= sc->getSCE(SC_GUARD_STANCE)->val3;
  6148. return (uint16)cap_value(watk,0,USHRT_MAX);
  6149. }
  6150. /**
  6151. * Adds flat magic attack modifications from skills
  6152. * @param sd: Object to change matk [PC]
  6153. * @param sc: Object's status change information
  6154. * @param matk: Initial matk
  6155. * @return modified matk with cap_value(matk,0,USHRT_MAX)
  6156. */
  6157. uint16 status_calc_pseudobuff_matk( map_session_data* sd, status_change *sc, int32 matk ){
  6158. // Flat MATK bonus from skills without sc
  6159. if (uint16 skill_lv = pc_checkskill(sd, NV_TRANSCENDENCE); skill_lv > 0) {
  6160. matk += 15 * skill_lv + (skill_lv > 4 ? 25 : 0);
  6161. }
  6162. if (sc == nullptr || sc->empty())
  6163. return static_cast<uint16>( cap_value(matk,0,USHRT_MAX) );
  6164. struct status_change_entry* sce;
  6165. // Flat MATK bonus from skills with sc
  6166. #ifdef RENEWAL
  6167. // Bonuses only in renewal
  6168. if (sce = sc->getSCE(SC_IMPOSITIO))
  6169. matk += sce->val2;
  6170. if (sce = sc->getSCE(SC_VOLCANO))
  6171. matk += sce->val2;
  6172. #endif
  6173. if (sce = sc->getSCE(SC_DORAM_MATK))
  6174. matk += sce->val1;
  6175. if (sce = sc->getSCE(SC_AQUAPLAY_OPTION))
  6176. matk += sce->val2;
  6177. if (sce = sc->getSCE(SC_CHILLY_AIR_OPTION))
  6178. matk += sce->val2;
  6179. if (sce = sc->getSCE(SC_COOLER_OPTION))
  6180. matk += sce->val2;
  6181. if (sce = sc->getSCE(SC_SOULFAIRY))
  6182. matk += sce->val2;
  6183. if (sce = sc->getSCE(SC_INSPIRATION))
  6184. matk += sce->val2;
  6185. if (sce = sc->getSCE(SC_SHIELDSPELL_ATK))
  6186. matk += sce->val2;
  6187. if (sce = sc->getSCE(SC_ZANGETSU))
  6188. matk += sce->val3;
  6189. if (sce = sc->getSCE(SC_MOONLITSERENADE))
  6190. matk += sce->val3;
  6191. if (sce = sc->getSCE(SC__AUTOSHADOWSPELL))
  6192. matk += sce->val4;
  6193. if (sce = sc->getSCE(SC_ODINS_POWER))
  6194. matk += 40 + 30 * sce->val1;
  6195. if (sce = sc->getSCE(SC_IZAYOI))
  6196. matk += 25 * sce->val1;
  6197. if ((sce = sc->getSCE(SC_FIRE_INSIGNIA)) && sce->val1 == 3)
  6198. matk += 50;
  6199. if (sc->getSCE(SC_CLIMAX_DES_HU))
  6200. matk += 100;
  6201. return static_cast<uint16>( cap_value(matk,0,USHRT_MAX) );
  6202. }
  6203. /**
  6204. * Adds flat magic attack modifications from consumables based on status changes
  6205. * @param sc: Object's status change information
  6206. * @param matk: Initial matk
  6207. * @return modified matk with cap_value(matk,0,USHRT_MAX)
  6208. */
  6209. uint16 status_calc_consumablematk( status_change *sc, int32 matk ){
  6210. if (sc == nullptr || sc->empty())
  6211. return static_cast<uint16>( cap_value(matk,0,USHRT_MAX) );
  6212. // struct status_change_entry* sce;
  6213. return static_cast<uint16>( cap_value(matk,0,USHRT_MAX) );
  6214. }
  6215. /**
  6216. * Adds critical modifications based on status changes
  6217. * @param bl: Object to change critical [PC|MOB|HOM|MER|ELEM]
  6218. * @param sc: Object's status change information
  6219. * @param critical: Initial critical
  6220. * @return modified critical with cap_value(critical,10,USHRT_MAX)
  6221. */
  6222. static int16 status_calc_critical(struct block_list *bl, status_change *sc, int32 critical)
  6223. {
  6224. if(sc == nullptr || sc->empty())
  6225. return cap_value(critical,10,SHRT_MAX);
  6226. if (sc->getSCE(SC_EXPLOSIONSPIRITS))
  6227. critical += sc->getSCE(SC_EXPLOSIONSPIRITS)->val2;
  6228. if (sc->getSCE(SC_FORTUNE))
  6229. critical += sc->getSCE(SC_FORTUNE)->val2;
  6230. if (sc->getSCE(SC_TRUESIGHT))
  6231. critical += sc->getSCE(SC_TRUESIGHT)->val2;
  6232. if (sc->getSCE(SC_CLOAKING))
  6233. critical += critical;
  6234. #ifdef RENEWAL
  6235. if (sc->getSCE(SC_SPEARQUICKEN))
  6236. critical += 3*sc->getSCE(SC_SPEARQUICKEN)->val1*10;
  6237. if (sc->getSCE(SC_TWOHANDQUICKEN))
  6238. critical += (2 + sc->getSCE(SC_TWOHANDQUICKEN)->val1) * 10;
  6239. #endif
  6240. if (sc->getSCE(SC__INVISIBILITY))
  6241. critical += sc->getSCE(SC__INVISIBILITY)->val3 * 10;
  6242. if (sc->getSCE(SC__UNLUCKY))
  6243. critical -= sc->getSCE(SC__UNLUCKY)->val2;
  6244. if (sc->getSCE(SC_SOULSHADOW))
  6245. critical += 10 * sc->getSCE(SC_SOULSHADOW)->val3;
  6246. if(sc->getSCE(SC_BEYONDOFWARCRY))
  6247. critical += sc->getSCE(SC_BEYONDOFWARCRY)->val3;
  6248. if (sc->getSCE(SC_INTENSIVE_AIM))
  6249. critical += 300;
  6250. return (int16)cap_value(critical,10,SHRT_MAX);
  6251. }
  6252. /**
  6253. * Adds hit modifications based on status changes
  6254. * @param bl: Object to change hit [PC|MOB|HOM|MER|ELEM]
  6255. * @param sc: Object's status change information
  6256. * @param hit: Initial hit
  6257. * @return modified hit with cap_value(hit,1,USHRT_MAX)
  6258. */
  6259. static int16 status_calc_hit(struct block_list *bl, status_change *sc, int32 hit)
  6260. {
  6261. if(sc == nullptr || sc->empty())
  6262. return cap_value(hit,1,SHRT_MAX);
  6263. if(sc->getSCE(SC_INCHIT))
  6264. hit += sc->getSCE(SC_INCHIT)->val1;
  6265. if(sc->getSCE(SC_TRUESIGHT))
  6266. hit += sc->getSCE(SC_TRUESIGHT)->val3;
  6267. if(sc->getSCE(SC_HUMMING))
  6268. hit += sc->getSCE(SC_HUMMING)->val2;
  6269. if(sc->getSCE(SC_CONCENTRATION))
  6270. hit += sc->getSCE(SC_CONCENTRATION)->val3;
  6271. if(sc->getSCE(SC_INSPIRATION))
  6272. hit += 12 * sc->getSCE(SC_INSPIRATION)->val1;
  6273. if(sc->getSCE(SC_ADJUSTMENT))
  6274. hit -= 30;
  6275. if(sc->getSCE(SC_INCREASING))
  6276. hit += 20; // RockmanEXE; changed based on updated [Reddozen]
  6277. if(sc->getSCE(SC_MERC_HITUP))
  6278. hit += sc->getSCE(SC_MERC_HITUP)->val2;
  6279. if(sc->getSCE(SC_INCHITRATE))
  6280. hit += hit * sc->getSCE(SC_INCHITRATE)->val1/100;
  6281. if (sc->getSCE(SC_POWERUP))
  6282. hit += hit * sc->getSCE(SC_POWERUP)->val2 / 100;
  6283. if(sc->getSCE(SC_BLIND))
  6284. hit -= hit * 25/100;
  6285. if(sc->getSCE(SC_HEAT_BARREL))
  6286. hit -= sc->getSCE(SC_HEAT_BARREL)->val4;
  6287. if(sc->getSCE(SC__GROOMY))
  6288. hit -= hit * sc->getSCE(SC__GROOMY)->val3 / 100;
  6289. if(sc->getSCE(SC_FEAR))
  6290. hit -= hit * 20 / 100;
  6291. if (sc->getSCE(SC_ASH))
  6292. hit -= hit * sc->getSCE(SC_ASH)->val2 / 100;
  6293. if (sc->getSCE(SC_TEARGAS))
  6294. hit -= hit * 50 / 100;
  6295. if(sc->getSCE(SC_ILLUSIONDOPING))
  6296. hit -= sc->getSCE(SC_ILLUSIONDOPING)->val2;
  6297. #ifdef RENEWAL
  6298. if (sc->getSCE(SC_BLESSING))
  6299. hit += sc->getSCE(SC_BLESSING)->val1 * 2;
  6300. if (sc->getSCE(SC_TWOHANDQUICKEN))
  6301. hit += sc->getSCE(SC_TWOHANDQUICKEN)->val1 * 2;
  6302. if (sc->getSCE(SC_ADRENALINE))
  6303. hit += sc->getSCE(SC_ADRENALINE)->val1 * 3 + 5;
  6304. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_HIT)
  6305. hit += 50;
  6306. #endif
  6307. if (sc->getSCE(SC_SOULFALCON))
  6308. hit += sc->getSCE(SC_SOULFALCON)->val3;
  6309. if (sc->getSCE(SC_SATURDAYNIGHTFEVER))
  6310. hit -= 50 + 50 * sc->getSCE(SC_SATURDAYNIGHTFEVER)->val1;
  6311. if (sc->getSCE(SC_ABYSS_SLAYER))
  6312. hit += sc->getSCE(SC_ABYSS_SLAYER)->val3;
  6313. if (sc->getSCE(SC_INTENSIVE_AIM))
  6314. hit += 250;
  6315. return (int16)cap_value(hit,1,SHRT_MAX);
  6316. }
  6317. /**
  6318. * Adds flee modifications based on status changes
  6319. * @param bl: Object to change flee [PC|MOB|HOM|MER|ELEM]
  6320. * @param sc: Object's status change information
  6321. * @param flee: Initial flee
  6322. * @return modified flee with cap_value(flee,1,USHRT_MAX)
  6323. */
  6324. static int16 status_calc_flee(struct block_list *bl, status_change *sc, int32 flee)
  6325. {
  6326. if( bl->type == BL_PC ) {
  6327. struct map_data *mapdata = map_getmapdata(bl->m);
  6328. if( mapdata_flag_gvg(mapdata) )
  6329. flee -= flee * battle_config.gvg_flee_penalty/100;
  6330. else if( mapdata->getMapFlag(MF_BATTLEGROUND) )
  6331. flee -= flee * battle_config.bg_flee_penalty/100;
  6332. }
  6333. if(sc == nullptr || sc->empty())
  6334. return cap_value(flee,1,SHRT_MAX);
  6335. if (sc->getSCE(SC_POISON_MIST))
  6336. return 0;
  6337. if(sc->getSCE(SC_OVERED_BOOST)) //Should be final and unmodifiable by any means
  6338. return sc->getSCE(SC_OVERED_BOOST)->val2;
  6339. // Fixed value
  6340. if(sc->getSCE(SC_INCFLEE))
  6341. flee += sc->getSCE(SC_INCFLEE)->val1;
  6342. if(sc->getSCE(SC_WHISTLE))
  6343. flee += sc->getSCE(SC_WHISTLE)->val2;
  6344. if(sc->getSCE(SC_WINDWALK))
  6345. flee += sc->getSCE(SC_WINDWALK)->val2;
  6346. if(sc->getSCE(SC_VIOLENTGALE))
  6347. flee += sc->getSCE(SC_VIOLENTGALE)->val2;
  6348. if(sc->getSCE(SC_MOON_COMFORT)) // SG skill [Komurka]
  6349. flee += sc->getSCE(SC_MOON_COMFORT)->val2;
  6350. if(sc->getSCE(SC_CLOSECONFINE))
  6351. flee += sc->getSCE(SC_CLOSECONFINE)->val3;
  6352. if (sc->getSCE(SC_ANGRIFFS_MODUS))
  6353. flee -= sc->getSCE(SC_ANGRIFFS_MODUS)->val3;
  6354. if(sc->getSCE(SC_ADJUSTMENT))
  6355. flee += 30;
  6356. if(sc->getSCE(SC_SPEED))
  6357. flee += 10 + sc->getSCE(SC_SPEED)->val1 * 10;
  6358. if(sc->getSCE(SC_GATLINGFEVER))
  6359. flee -= sc->getSCE(SC_GATLINGFEVER)->val4;
  6360. if(sc->getSCE(SC_PARTYFLEE))
  6361. flee += sc->getSCE(SC_PARTYFLEE)->val1 * 10;
  6362. if(sc->getSCE(SC_MERC_FLEEUP))
  6363. flee += sc->getSCE(SC_MERC_FLEEUP)->val2;
  6364. if( sc->getSCE(SC_HALLUCINATIONWALK) )
  6365. flee += sc->getSCE(SC_HALLUCINATIONWALK)->val2;
  6366. if( sc->getSCE(SC_NPC_HALLUCINATIONWALK) )
  6367. flee += sc->getSCE(SC_NPC_HALLUCINATIONWALK)->val2;
  6368. if( sc->getSCE(SC_WATER_BARRIER) )
  6369. flee -= sc->getSCE(SC_WATER_BARRIER)->val2;
  6370. if( sc->getSCE(SC_C_MARKER) )
  6371. flee -= sc->getSCE(SC_C_MARKER)->val3;
  6372. #ifdef RENEWAL
  6373. if( sc->getSCE(SC_SPEARQUICKEN) )
  6374. flee += 2 * sc->getSCE(SC_SPEARQUICKEN)->val1;
  6375. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_FLEE)
  6376. flee += 50;
  6377. #endif
  6378. // Rate value
  6379. if(sc->getSCE(SC_INCFLEERATE))
  6380. flee += flee * sc->getSCE(SC_INCFLEERATE)->val1/100;
  6381. if (sc->getSCE(SC_AGIUP))
  6382. flee += flee * sc->getSCE(SC_AGIUP)->val2 / 100;
  6383. if(sc->getSCE(SC_SPIDERWEB) || sc->getSCE(SC_WIDEWEB))
  6384. flee -= flee * 50/100;
  6385. if(sc->getSCE(SC_BERSERK))
  6386. flee -= flee * 50/100;
  6387. if(sc->getSCE(SC_BLIND))
  6388. flee -= flee * 25/100;
  6389. if(sc->getSCE(SC_FEAR))
  6390. flee -= flee * 20 / 100;
  6391. if(sc->getSCE(SC_PARALYSE) && sc->getSCE(SC_PARALYSE)->val3 == 1)
  6392. flee -= flee * 10 / 100;
  6393. if(sc->getSCE(SC_INFRAREDSCAN))
  6394. flee -= flee * 30 / 100;
  6395. if( sc->getSCE(SC__LAZINESS) )
  6396. flee -= flee * sc->getSCE(SC__LAZINESS)->val3 / 100;
  6397. if( sc->getSCE(SC_GLOOMYDAY) )
  6398. flee -= flee * sc->getSCE(SC_GLOOMYDAY)->val2 / 100;
  6399. if( sc->getSCE(SC_SATURDAYNIGHTFEVER) )
  6400. flee -= 20 + 30 * sc->getSCE(SC_SATURDAYNIGHTFEVER)->val1;
  6401. if( sc->getSCE(SC_WIND_STEP_OPTION) )
  6402. flee += flee * sc->getSCE(SC_WIND_STEP_OPTION)->val2 / 100;
  6403. if( sc->getSCE(SC_TINDER_BREAKER) || sc->getSCE(SC_TINDER_BREAKER2) )
  6404. flee -= flee * 50 / 100;
  6405. if( sc->getSCE(SC_ZEPHYR) )
  6406. flee += sc->getSCE(SC_ZEPHYR)->val2;
  6407. if(sc->getSCE(SC_ASH))
  6408. flee -= flee * sc->getSCE(SC_ASH)->val4 / 100;
  6409. if (sc->getSCE(SC_GOLDENE_FERSE))
  6410. flee += flee * sc->getSCE(SC_GOLDENE_FERSE)->val2 / 100;
  6411. if (sc->getSCE(SC_SMOKEPOWDER))
  6412. flee += flee * 20 / 100;
  6413. if (sc->getSCE(SC_TEARGAS))
  6414. flee -= flee * 50 / 100;
  6415. //if( sc->getSCE(SC_C_MARKER) )
  6416. // flee -= (flee * sc->getSCE(SC_C_MARKER)->val3) / 100;
  6417. if (sc->getSCE(SC_GROOMING))
  6418. flee += sc->getSCE(SC_GROOMING)->val2;
  6419. return (int16)cap_value(flee,1,SHRT_MAX);
  6420. }
  6421. /**
  6422. * Adds perfect flee modifications based on status changes
  6423. * @param bl: Object to change flee2 [PC|MOB|HOM|MER|ELEM]
  6424. * @param sc: Object's status change information
  6425. * @param flee2: Initial flee2
  6426. * @return modified flee2 with cap_value(flee2,10,USHRT_MAX)
  6427. */
  6428. static int16 status_calc_flee2(struct block_list *bl, status_change *sc, int32 flee2)
  6429. {
  6430. if(sc == nullptr || sc->empty())
  6431. return cap_value(flee2,10,SHRT_MAX);
  6432. if(sc->getSCE(SC_WHISTLE))
  6433. flee2 += sc->getSCE(SC_WHISTLE)->val3*10;
  6434. if(sc->getSCE(SC__UNLUCKY))
  6435. flee2 -= flee2 * sc->getSCE(SC__UNLUCKY)->val2 / 100;
  6436. if (sc->getSCE(SC_HISS))
  6437. flee2 += sc->getSCE(SC_HISS)->val2*10;
  6438. if (sc->getSCE(SC_DORAM_FLEE2))
  6439. flee2 += sc->getSCE(SC_DORAM_FLEE2)->val1;
  6440. return (int16)cap_value(flee2,10,SHRT_MAX);
  6441. }
  6442. /**
  6443. * Adds defense (left-side) modifications based on status changes
  6444. * @param bl: Object to change def [PC|MOB|HOM|MER|ELEM]
  6445. * @param sc: Object's status change information
  6446. * @param def: Initial def
  6447. * @return modified def with cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX)
  6448. */
  6449. static defType status_calc_def(struct block_list *bl, status_change *sc, int32 def)
  6450. {
  6451. if(sc == nullptr || sc->empty())
  6452. return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX);
  6453. if(sc->getSCE(SC_BERSERK))
  6454. return 0;
  6455. #ifdef RENEWAL
  6456. if(sc->getSCE(SC_ETERNALCHAOS))
  6457. return 0;
  6458. #endif
  6459. if(sc->getSCE(SC_BARRIER))
  6460. return 100;
  6461. if(sc->getSCE(SC_KEEPING))
  6462. return 90;
  6463. #ifndef RENEWAL /// Steel Body does not provide 90 DEF in [RENEWAL]
  6464. if(sc->getSCE(SC_STEELBODY))
  6465. return 90;
  6466. #endif
  6467. if (sc->getSCE(SC_NYANGGRASS)) {
  6468. if (bl->type == BL_PC)
  6469. return 0;
  6470. else
  6471. return def /= 2;
  6472. }
  6473. if(sc->getSCE(SC_DEFSET))
  6474. return sc->getSCE(SC_DEFSET)->val1;
  6475. if(sc->getSCE(SC_DRUMBATTLE))
  6476. def += sc->getSCE(SC_DRUMBATTLE)->val3;
  6477. #ifdef RENEWAL
  6478. if (sc->getSCE(SC_ASSUMPTIO))
  6479. def += sc->getSCE(SC_ASSUMPTIO)->val1 * 50;
  6480. #endif
  6481. if (bl->type == BL_HOM && sc->getSCE(SC_DEFENCE))
  6482. def += sc->getSCE(SC_DEFENCE)->val2;
  6483. if(sc->getSCE(SC_INCDEFRATE))
  6484. def += def * sc->getSCE(SC_INCDEFRATE)->val1/100;
  6485. if(sc->getSCE(SC_EARTH_INSIGNIA) && sc->getSCE(SC_EARTH_INSIGNIA)->val1 == 2)
  6486. def += 50;
  6487. if(sc->getSCE(SC_ODINS_POWER))
  6488. def -= 20 * sc->getSCE(SC_ODINS_POWER)->val1;
  6489. if( sc->getSCE(SC_ANGRIFFS_MODUS) )
  6490. def -= 20 + 10 * sc->getSCE(SC_ANGRIFFS_MODUS)->val1;
  6491. if(sc->getSCE(SC_STONEHARDSKIN))
  6492. def += sc->getSCE(SC_STONEHARDSKIN)->val1;
  6493. if(sc->getSCE(SC_STONE))
  6494. def /= 2;
  6495. if(sc->getSCE(SC_FREEZE))
  6496. def /= 2;
  6497. if(sc->getSCE(SC_POISON) || sc->getSCE(SC_DPOISON) && bl->type != BL_PC)
  6498. def = def * 75 / 100; //Should round down
  6499. if(sc->getSCE(SC_SIGNUMCRUCIS))
  6500. def -= def * sc->getSCE(SC_SIGNUMCRUCIS)->val2/100;
  6501. if(sc->getSCE(SC_CONCENTRATION))
  6502. def -= def * sc->getSCE(SC_CONCENTRATION)->val4/100;
  6503. if(sc->getSCE(SC_SKE))
  6504. def /= 2;
  6505. if(sc->getSCE(SC_PROVOKE) && bl->type != BL_PC) // Provoke doesn't alter player defense->
  6506. def -= def * sc->getSCE(SC_PROVOKE)->val3/100;
  6507. if(sc->getSCE(SC_STRIPSHIELD) && bl->type != BL_PC) // Player doesn't have def reduction only equip removed
  6508. def -= def * sc->getSCE(SC_STRIPSHIELD)->val2/100;
  6509. if (sc->getSCE(SC_FLING))
  6510. def -= def * (sc->getSCE(SC_FLING)->val2)/100;
  6511. if( sc->getSCE(SC_FREEZING) )
  6512. def -= def * (bl->type == BL_PC ? 30 : 10) / 100;
  6513. if( sc->getSCE(SC_ANALYZE) )
  6514. def -= def * (14 * sc->getSCE(SC_ANALYZE)->val1) / 100;
  6515. if( sc->getSCE(SC_NEUTRALBARRIER) )
  6516. def += def * sc->getSCE(SC_NEUTRALBARRIER)->val2 / 100;
  6517. if( sc->getSCE(SC_PRESTIGE) )
  6518. def += sc->getSCE(SC_PRESTIGE)->val3;
  6519. if( sc->getSCE(SC_BANDING) && sc->getSCE(SC_BANDING)->val2 > 1 )
  6520. def += 6 * sc->getSCE(SC_BANDING)->val1;
  6521. if( sc->getSCE(SC_ECHOSONG) )
  6522. def += sc->getSCE(SC_ECHOSONG)->val3;
  6523. if( sc->getSCE(SC_CAMOUFLAGE) )
  6524. def -= def * 5 * sc->getSCE(SC_CAMOUFLAGE)->val3 / 100;
  6525. if( sc->getSCE(SC_SOLID_SKIN_OPTION) )
  6526. def += def * sc->getSCE(SC_SOLID_SKIN_OPTION)->val2 / 100;
  6527. if( sc->getSCE(SC_ROCK_CRUSHER) )
  6528. def -= def * sc->getSCE(SC_ROCK_CRUSHER)->val2 / 100;
  6529. if( sc->getSCE(SC_POWER_OF_GAIA) )
  6530. def += def * sc->getSCE(SC_POWER_OF_GAIA)->val2 / 100;
  6531. if(sc->getSCE(SC_ASH))
  6532. def -= def * sc->getSCE(SC_ASH)->val3/100;
  6533. if( sc->getSCE(SC_OVERED_BOOST) && bl->type == BL_HOM )
  6534. def -= def * sc->getSCE(SC_OVERED_BOOST)->val4 / 100;
  6535. if (sc->getSCE(SC_SOULGOLEM))
  6536. def += sc->getSCE(SC_SOULGOLEM)->val2;
  6537. if (sc->getSCE(SC_STONE_WALL))
  6538. def += sc->getSCE(SC_STONE_WALL)->val2;
  6539. if (sc->getSCE(SC_D_MACHINE))
  6540. def += sc->getSCE(SC_D_MACHINE)->val2;
  6541. if (sc->getSCE(SC_CLIMAX_CRYIMP))
  6542. def += 300;
  6543. if (sc->getSCE(SC_GUARD_STANCE))
  6544. def += sc->getSCE(SC_GUARD_STANCE)->val2;
  6545. if (sc->getSCE(SC_ATTACK_STANCE))
  6546. def -= sc->getSCE(SC_ATTACK_STANCE)->val2;
  6547. return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX);
  6548. }
  6549. /**
  6550. * Adds defense (right-side) modifications based on status changes
  6551. * @param bl: Object to change def2 [PC|MOB|HOM|MER|ELEM]
  6552. * @param sc: Object's status change information
  6553. * @param def2: Initial def2
  6554. * @return modified def2 with cap_value(def2,SHRT_MIN,SHRT_MAX)
  6555. */
  6556. static int16 status_calc_def2(struct block_list *bl, status_change *sc, int32 def2)
  6557. {
  6558. if(sc == nullptr || sc->empty())
  6559. #ifdef RENEWAL
  6560. return (int16)cap_value(def2,SHRT_MIN,SHRT_MAX);
  6561. #else
  6562. return (int16)cap_value(def2,1,SHRT_MAX);
  6563. #endif
  6564. if(sc->getSCE(SC_BERSERK))
  6565. return 0;
  6566. if(sc->getSCE(SC_ETERNALCHAOS))
  6567. return 0;
  6568. if(sc->getSCE(SC_DEFSET))
  6569. return sc->getSCE(SC_DEFSET)->val1;
  6570. if(sc->getSCE(SC_SUN_COMFORT))
  6571. def2 += sc->getSCE(SC_SUN_COMFORT)->val2;
  6572. #ifdef RENEWAL
  6573. if (sc->getSCE(SC_SKA))
  6574. def2 += 80;
  6575. #endif
  6576. if(sc->getSCE(SC_ANGELUS))
  6577. #ifdef RENEWAL /// The VIT stat bonus is boosted by angelus [RENEWAL]
  6578. def2 += status_get_vit(bl) / 2 * sc->getSCE(SC_ANGELUS)->val2/100;
  6579. #else
  6580. def2 += def2 * sc->getSCE(SC_ANGELUS)->val2/100;
  6581. if(sc->getSCE(SC_CONCENTRATION))
  6582. def2 -= def2 * sc->getSCE(SC_CONCENTRATION)->val4/100;
  6583. #endif
  6584. if(sc->getSCE(SC_POISON) || sc->getSCE(SC_DPOISON))
  6585. def2 = def2 * 75 / 100; //Should round down
  6586. if(sc->getSCE(SC_SKE))
  6587. def2 -= def2 * 50/100;
  6588. if(sc->getSCE(SC_PROVOKE))
  6589. def2 -= def2 * sc->getSCE(SC_PROVOKE)->val3/100;
  6590. if(sc->getSCE(SC_JOINTBEAT))
  6591. def2 -= def2 * ( sc->getSCE(SC_JOINTBEAT)->val2&BREAK_SHOULDER ? 50 : 0 ) / 100
  6592. + def2 * ( sc->getSCE(SC_JOINTBEAT)->val2&BREAK_WAIST ? 25 : 0 ) / 100;
  6593. if(sc->getSCE(SC_FLING))
  6594. def2 -= def2 * (sc->getSCE(SC_FLING)->val3)/100;
  6595. if(sc->getSCE(SC_ANALYZE))
  6596. def2 -= def2 * (14 * sc->getSCE(SC_ANALYZE)->val1) / 100;
  6597. if(sc->getSCE(SC_ASH))
  6598. def2 -= def2 * sc->getSCE(SC_ASH)->val3/100;
  6599. if (sc->getSCE(SC_PARALYSIS))
  6600. def2 -= def2 * sc->getSCE(SC_PARALYSIS)->val2 / 100;
  6601. if(sc->getSCE(SC_EQC))
  6602. def2 -= def2 * sc->getSCE(SC_EQC)->val2 / 100;
  6603. if( sc->getSCE(SC_CAMOUFLAGE) )
  6604. def2 -= def2 * 5 * sc->getSCE(SC_CAMOUFLAGE)->val3 / 100;
  6605. #ifdef RENEWAL
  6606. return (int16)cap_value(def2,SHRT_MIN,SHRT_MAX);
  6607. #else
  6608. return (int16)cap_value(def2,1,SHRT_MAX);
  6609. #endif
  6610. }
  6611. /**
  6612. * Adds magic defense (left-side) modifications based on status changes
  6613. * @param bl: Object to change mdef [PC|MOB|HOM|MER|ELEM]
  6614. * @param sc: Object's status change information
  6615. * @param mdef: Initial mdef
  6616. * @return modified mdef with cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX)
  6617. */
  6618. static defType status_calc_mdef(struct block_list *bl, status_change *sc, int32 mdef)
  6619. {
  6620. if(sc == nullptr || sc->empty())
  6621. return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX);
  6622. if(sc->getSCE(SC_BERSERK))
  6623. return 0;
  6624. if(sc->getSCE(SC_BARRIER))
  6625. return 100;
  6626. #ifndef RENEWAL /// Steel Body does not provide 90 MDEF in [RENEWAL]
  6627. if(sc->getSCE(SC_STEELBODY))
  6628. return 90;
  6629. #endif
  6630. if (sc->getSCE(SC_NYANGGRASS)) {
  6631. if (bl->type == BL_PC)
  6632. return 0;
  6633. else
  6634. return mdef / 2;
  6635. }
  6636. if(sc->getSCE(SC_MDEFSET))
  6637. return sc->getSCE(SC_MDEFSET)->val1;
  6638. if(sc->getSCE(SC_EARTH_INSIGNIA) && sc->getSCE(SC_EARTH_INSIGNIA)->val1 == 3)
  6639. mdef += 50;
  6640. if(sc->getSCE(SC_ENDURE) && !sc->getSCE(SC_ENDURE)->val3) // It has been confirmed that Eddga card grants 1 MDEF, not 0, not 10, but 1.
  6641. mdef += (sc->getSCE(SC_ENDURE)->val4 == 0) ? sc->getSCE(SC_ENDURE)->val1 : 1;
  6642. if(sc->getSCE(SC_STONEHARDSKIN))
  6643. mdef += sc->getSCE(SC_STONEHARDSKIN)->val1;
  6644. if(sc->getSCE(SC_STONE))
  6645. mdef += 25 * mdef / 100;
  6646. if(sc->getSCE(SC_FREEZE))
  6647. mdef += 25 * mdef / 100;
  6648. if(sc->getSCE(SC_BURNING))
  6649. mdef -= 25 * mdef / 100;
  6650. if( sc->getSCE(SC_NEUTRALBARRIER) )
  6651. mdef += mdef * sc->getSCE(SC_NEUTRALBARRIER)->val2 / 100;
  6652. if(sc->getSCE(SC_ANALYZE))
  6653. mdef -= mdef * ( 14 * sc->getSCE(SC_ANALYZE)->val1 ) / 100;
  6654. if(sc->getSCE(SC_SYMPHONYOFLOVER))
  6655. mdef += mdef * sc->getSCE(SC_SYMPHONYOFLOVER)->val3 / 100;
  6656. if (sc->getSCE(SC_ODINS_POWER))
  6657. mdef -= 20 * sc->getSCE(SC_ODINS_POWER)->val1;
  6658. if (sc->getSCE(SC_SOULGOLEM))
  6659. mdef += sc->getSCE(SC_SOULGOLEM)->val3;
  6660. if (sc->getSCE(SC_STONE_WALL))
  6661. mdef += sc->getSCE(SC_STONE_WALL)->val3;
  6662. if (sc->getSCE(SC_CLIMAX_CRYIMP))
  6663. mdef += 100;
  6664. return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX);
  6665. }
  6666. /**
  6667. * Adds magic defense (right-side) modifications based on status changes
  6668. * @param bl: Object to change mdef2 [PC|MOB|HOM|MER|ELEM]
  6669. * @param sc: Object's status change information
  6670. * @param mdef2: Initial mdef2
  6671. * @return modified mdef2 with cap_value(mdef2,SHRT_MIN,SHRT_MAX)
  6672. */
  6673. static int16 status_calc_mdef2(struct block_list *bl, status_change *sc, int32 mdef2)
  6674. {
  6675. if(sc == nullptr || sc->empty())
  6676. #ifdef RENEWAL
  6677. return (int16)cap_value(mdef2,SHRT_MIN,SHRT_MAX);
  6678. #else
  6679. return (int16)cap_value(mdef2,1,SHRT_MAX);
  6680. #endif
  6681. if(sc->getSCE(SC_BERSERK))
  6682. return 0;
  6683. if(sc->getSCE(SC_SKA))
  6684. return 90;
  6685. if(sc->getSCE(SC_MDEFSET))
  6686. return sc->getSCE(SC_MDEFSET)->val1;
  6687. if(sc->getSCE(SC_MINDBREAKER))
  6688. mdef2 -= mdef2 * sc->getSCE(SC_MINDBREAKER)->val3/100;
  6689. if(sc->getSCE(SC_BURNING))
  6690. mdef2 -= mdef2 * 25 / 100;
  6691. if(sc->getSCE(SC_ANALYZE))
  6692. mdef2 -= mdef2 * (14 * sc->getSCE(SC_ANALYZE)->val1) / 100;
  6693. #ifdef RENEWAL
  6694. return (int16)cap_value(mdef2,SHRT_MIN,SHRT_MAX);
  6695. #else
  6696. return (int16)cap_value(mdef2,1,SHRT_MAX);
  6697. #endif
  6698. }
  6699. /**
  6700. * Adds speed modifications based on status changes
  6701. * @param bl: Object to change speed [PC|MOB|HOM|MER|ELEM]
  6702. * @param sc: Object's status change information
  6703. * @param speed: Initial speed
  6704. * @return modified speed with cap_value(speed,10,USHRT_MAX)
  6705. */
  6706. static uint16 status_calc_speed(struct block_list *bl, status_change *sc, int32 speed)
  6707. {
  6708. TBL_PC* sd = BL_CAST(BL_PC, bl);
  6709. int32 speed_rate = 100;
  6710. if (sc == nullptr || (sd && sd->state.permanent_speed))
  6711. return (uint16)cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED);
  6712. if (sd && pc_ismadogear(sd)) { // Mado speed is not affected by other statuses
  6713. int32 val = 0;
  6714. if (pc_checkskill(sd, NC_MADOLICENCE) < 5)
  6715. val = 50 - 10 * pc_checkskill(sd, NC_MADOLICENCE);
  6716. else
  6717. val -= 25;
  6718. if (sc->getSCE(SC_ACCELERATION))
  6719. val -= 25;
  6720. speed += speed * val / 100;
  6721. return (uint16)cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED);
  6722. }
  6723. if( sd && sd->ud.skilltimer != INVALID_TIMER && (pc_checkskill(sd,SA_FREECAST) > 0 || sd->ud.skill_id == LG_EXEEDBREAK) ) {
  6724. if( sd->ud.skill_id == LG_EXEEDBREAK )
  6725. speed_rate = 160 - 10 * sd->ud.skill_lv;
  6726. else
  6727. speed_rate = 175 - 5 * pc_checkskill(sd,SA_FREECAST);
  6728. } else {
  6729. int32 val = 0;
  6730. // GetMoveHasteValue2()
  6731. if( sc->getSCE(SC_FUSION) )
  6732. val = 25;
  6733. else if( sd ) {
  6734. if( pc_isriding(sd) || sd->sc.option&OPTION_DRAGON )
  6735. val = 25; // Same bonus
  6736. else if( pc_isridingwug(sd) )
  6737. val = 15 + 5 * pc_checkskill(sd, RA_WUGRIDER);
  6738. else if( sc->getSCE(SC_ALL_RIDING) )
  6739. val = battle_config.rental_mount_speed_boost;
  6740. }
  6741. speed_rate -= val;
  6742. // GetMoveSlowValue()
  6743. if( sd && sc->getSCE(SC_HIDING) && pc_checkskill(sd,RG_TUNNELDRIVE) > 0 )
  6744. val = 120 - 6 * pc_checkskill(sd,RG_TUNNELDRIVE);
  6745. else if( sd && sc->getSCE(SC_CHASEWALK) && sc->getSCE(SC_CHASEWALK)->val3 < 0 )
  6746. val = sc->getSCE(SC_CHASEWALK)->val3;
  6747. else {
  6748. val = 0;
  6749. // Longing for Freedom/Special Singer cancels song/dance penalty
  6750. #ifdef RENEWAL
  6751. if (sc->getSCE(SC_ENSEMBLEFATIGUE))
  6752. val = max(val, sc->getSCE(SC_ENSEMBLEFATIGUE)->val2);
  6753. #else
  6754. if( sc->getSCE(SC_LONGING) )
  6755. val = max( val, 50 - 10 * sc->getSCE(SC_LONGING)->val1 );
  6756. #endif
  6757. else
  6758. if( sd && sc->getSCE(SC_DANCING) )
  6759. val = max( val, 500 - (40 + 10 * (sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_BARDDANCER)) * pc_checkskill(sd,(sd->status.sex?BA_MUSICALLESSON:DC_DANCINGLESSON)) );
  6760. if( sc->getSCE(SC_DECREASEAGI) )
  6761. val = max( val, 25 );
  6762. if( sc->getSCE(SC_QUAGMIRE) || sc->getSCE(SC_HALLUCINATIONWALK_POSTDELAY) || (sc->getSCE(SC_GLOOMYDAY) && sc->getSCE(SC_GLOOMYDAY)->val4) )
  6763. val = max( val, 50 );
  6764. if( sc->getSCE(SC_DONTFORGETME) )
  6765. val = max( val, sc->getSCE(SC_DONTFORGETME)->val3 );
  6766. if( sc->getSCE(SC_CURSE) )
  6767. val = max( val, 300 );
  6768. if( sc->getSCE(SC_CHASEWALK) )
  6769. val = max( val, sc->getSCE(SC_CHASEWALK)->val3 );
  6770. if( sc->getSCE(SC_WEDDING) )
  6771. val = max( val, 100 );
  6772. if( sc->getSCE(SC_JOINTBEAT) && sc->getSCE(SC_JOINTBEAT)->val2&(BREAK_ANKLE|BREAK_KNEE) )
  6773. val = max( val, (sc->getSCE(SC_JOINTBEAT)->val2&BREAK_ANKLE ? 50 : 0) + (sc->getSCE(SC_JOINTBEAT)->val2&BREAK_KNEE ? 30 : 0) );
  6774. if( sc->getSCE(SC_CLOAKING) && (sc->getSCE(SC_CLOAKING)->val4&1) == 0 )
  6775. val = max( val, sc->getSCE(SC_CLOAKING)->val1 < 3 ? 300 : 30 - 3 * sc->getSCE(SC_CLOAKING)->val1 );
  6776. if( sc->getSCE(SC_GOSPEL) && sc->getSCE(SC_GOSPEL)->val4 == BCT_ENEMY )
  6777. val = max( val, 75 );
  6778. if( sc->getSCE(SC_SLOWDOWN) ) // Slow Potion
  6779. val = max( val, sc->getSCE(SC_SLOWDOWN)->val1 );
  6780. if( sc->getSCE(SC_GATLINGFEVER) )
  6781. val = max( val, 100 );
  6782. if( sc->getSCE(SC_SUITON) )
  6783. val = max( val, sc->getSCE(SC_SUITON)->val3 );
  6784. if( sc->getSCE(SC_SWOO) )
  6785. val = max( val, 300 );
  6786. if( sc->getSCE(SC_SKA) )
  6787. val = max( val, 25 );
  6788. if( sc->getSCE(SC_FREEZING) )
  6789. val = max( val, 30 );
  6790. if( sc->getSCE(SC_MARSHOFABYSS) )
  6791. val = max( val, sc->getSCE(SC_MARSHOFABYSS)->val3 );
  6792. if( sc->getSCE(SC_CAMOUFLAGE) && sc->getSCE(SC_CAMOUFLAGE)->val1 > 2 )
  6793. val = max( val, 25 * (5 - sc->getSCE(SC_CAMOUFLAGE)->val1) );
  6794. if( sc->getSCE(SC_STEALTHFIELD) )
  6795. val = max( val, 20 );
  6796. if( sc->getSCE(SC__LAZINESS) )
  6797. val = max( val, 25 );
  6798. if( sc->getSCE(SC_ROCK_CRUSHER_ATK) )
  6799. val = max( val, sc->getSCE(SC_ROCK_CRUSHER_ATK)->val2 );
  6800. if( sc->getSCE(SC_POWER_OF_GAIA) )
  6801. val = max( val, sc->getSCE(SC_POWER_OF_GAIA)->val2 );
  6802. if( sc->getSCE(SC_MELON_BOMB) )
  6803. val = max( val, sc->getSCE(SC_MELON_BOMB)->val2 );
  6804. if( sc->getSCE(SC_REBOUND) )
  6805. val = max( val, 25 );
  6806. if( sc->getSCE(SC_B_TRAP) )
  6807. val = max( val, sc->getSCE(SC_B_TRAP)->val3 );
  6808. if (sc->getSCE(SC_CATNIPPOWDER))
  6809. val = max(val, sc->getSCE(SC_CATNIPPOWDER)->val3);
  6810. if (sc->getSCE(SC_SP_SHA))
  6811. val = max(val, sc->getSCE(SC_SP_SHA)->val2);
  6812. if (sc->getSCE(SC_CREATINGSTAR))
  6813. val = max(val, 90);
  6814. if (sc->getSCE(SC_SHIELDCHAINRUSH))
  6815. val = max(val, 20);
  6816. if (sc->getSCE(SC_GROUNDGRAVITY))
  6817. val = max(val, 20);
  6818. if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate > 0 ) // Permanent item-based speedup
  6819. val = max( val, sd->bonus.speed_rate + sd->bonus.speed_add_rate );
  6820. }
  6821. speed_rate += val;
  6822. val = 0;
  6823. if( sc->getSCE(SC_MARSHOFABYSS) && speed_rate > 150 )
  6824. speed_rate = 150;
  6825. // GetMoveHasteValue1()
  6826. if (sc->getSCE(SC_AGIUP))
  6827. val = max(val, sc->getSCE(SC_AGIUP)->val1);
  6828. if( sc->getSCE(SC_INCREASEAGI) )
  6829. val = max( val, 25 );
  6830. if( sc->getSCE(SC_WINDWALK) )
  6831. val = max( val, 2 * sc->getSCE(SC_WINDWALK)->val1 );
  6832. if( sc->getSCE(SC_CARTBOOST) )
  6833. val = max( val, 20 );
  6834. if( sd && (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN && pc_checkskill(sd,TF_MISS) > 0 )
  6835. val = max( val, 1 * pc_checkskill(sd,TF_MISS) );
  6836. if( sc->getSCE(SC_CLOAKING) && (sc->getSCE(SC_CLOAKING)->val4&1) == 1 )
  6837. val = max( val, sc->getSCE(SC_CLOAKING)->val1 >= 10 ? 25 : 3 * sc->getSCE(SC_CLOAKING)->val1 - 3 );
  6838. if( sc->getSCE(SC_BERSERK) )
  6839. val = max( val, 25 );
  6840. if( sc->getSCE(SC_RUN) )
  6841. val = max( val, 55 );
  6842. if( sc->getSCE(SC_AVOID) )
  6843. val = max( val, sc->getSCE(SC_AVOID)->val2 );
  6844. if (sc->getSCE(SC_INVINCIBLE))
  6845. val = max(val, sc->getSCE(SC_INVINCIBLE)->val3);
  6846. if( sc->getSCE(SC_CLOAKINGEXCEED) )
  6847. val = max( val, sc->getSCE(SC_CLOAKINGEXCEED)->val3);
  6848. if (sc->getSCE(SC_PARALYSE) && sc->getSCE(SC_PARALYSE)->val3 == 0)
  6849. val = max(val, 50);
  6850. if( sc->getSCE(SC_HOVERING) )
  6851. val = max( val, 10 );
  6852. if( sc->getSCE(SC_GN_CARTBOOST) )
  6853. val = max( val, sc->getSCE(SC_GN_CARTBOOST)->val2 );
  6854. if( sc->getSCE(SC_SWINGDANCE) )
  6855. val = max( val, sc->getSCE(SC_SWINGDANCE)->val3 );
  6856. if( sc->getSCE(SC_WIND_STEP_OPTION) )
  6857. val = max( val, sc->getSCE(SC_WIND_STEP_OPTION)->val2 );
  6858. if( sc->getSCE(SC_FULL_THROTTLE) )
  6859. val = max( val, 25 );
  6860. if (sc->getSCE(SC_ARCLOUSEDASH))
  6861. val = max(val, sc->getSCE(SC_ARCLOUSEDASH)->val3);
  6862. if( sc->getSCE(SC_DORAM_WALKSPEED) )
  6863. val = max(val, sc->getSCE(SC_DORAM_WALKSPEED)->val1);
  6864. if (sc->getSCE(SC_RUSHWINDMILL))
  6865. val = max(val, 25); // !TODO: Confirm bonus movement speed
  6866. if (sc->getSCE(SC_EMERGENCY_MOVE))
  6867. val = max(val, sc->getSCE(SC_EMERGENCY_MOVE)->val2);
  6868. if( sc->getSCE(SC_JAWAII_SERENADE) ){
  6869. val = max( val, 25 );
  6870. }
  6871. // !FIXME: official items use a single bonus for this [ultramage]
  6872. if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate < 0 ) // Permanent item-based speedup
  6873. val = max( val, -(sd->bonus.speed_rate + sd->bonus.speed_add_rate) );
  6874. speed_rate -= val;
  6875. if( speed_rate < 40 )
  6876. speed_rate = 40;
  6877. }
  6878. // GetSpeed()
  6879. if( sd && pc_iscarton(sd) )
  6880. speed += speed * (50 - 5 * pc_checkskill(sd,MC_PUSHCART)) / 100;
  6881. if( sc->getSCE(SC_PARALYSE) && sc->getSCE(SC_PARALYSE)->val3 == 1 )
  6882. speed += speed * 50 / 100;
  6883. if( speed_rate != 100 )
  6884. speed = speed * speed_rate / 100;
  6885. if( sc->getSCE(SC_STEELBODY) )
  6886. speed = 200;
  6887. if( sc->getSCE(SC_DEFENDER) )
  6888. speed = max(speed, 200);
  6889. if (sc->getSCE(SC_ARMOR))
  6890. speed = max(speed, 200);
  6891. if( sc->getSCE(SC_WALKSPEED) && sc->getSCE(SC_WALKSPEED)->val1 > 0 ) // ChangeSpeed
  6892. speed = speed * 100 / sc->getSCE(SC_WALKSPEED)->val1;
  6893. return (uint16)cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED);
  6894. }
  6895. #ifdef RENEWAL_ASPD
  6896. /**
  6897. * Renewal attack speed modifiers based on status changes
  6898. * This function only affects RENEWAL players and comes after base calculation
  6899. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  6900. * @param sc: Object's status change information
  6901. * @param fixed: True - fixed value [malufett]
  6902. * False - percentage value
  6903. * @return modified aspd
  6904. */
  6905. static int16 status_calc_aspd(struct block_list *bl, status_change *sc, bool fixed)
  6906. {
  6907. int32 bonus = 0;
  6908. if (sc == nullptr || sc->empty())
  6909. return 0;
  6910. if (fixed) {
  6911. enum sc_type sc_val;
  6912. if (!sc->getSCE(SC_QUAGMIRE)) {
  6913. // !TODO: How does Two-Hand Quicken, Adrenaline Rush, and Spear quick change? (+10%)
  6914. if (bonus < 7 && (sc->getSCE(SC_TWOHANDQUICKEN) || sc->getSCE(SC_ONEHAND) || sc->getSCE(SC_MERC_QUICKEN) || sc->getSCE(SC_ADRENALINE) || sc->getSCE(SC_SPEARQUICKEN)))
  6915. bonus = 7;
  6916. else if (bonus < 6 && sc->getSCE(SC_ADRENALINE2))
  6917. bonus = 6;
  6918. else if (bonus < 5 && sc->getSCE(SC_FLEET))
  6919. bonus = 5;
  6920. }
  6921. if (sc->getSCE(SC_ASSNCROS) && bonus < sc->getSCE(SC_ASSNCROS)->val2) {
  6922. #ifdef RENEWAL
  6923. bonus += sc->getSCE(SC_ASSNCROS)->val2;
  6924. #else
  6925. if (bl->type != BL_PC)
  6926. bonus += sc->getSCE(SC_ASSNCROS)->val2;
  6927. else {
  6928. switch(((TBL_PC*)bl)->status.weapon) {
  6929. case W_BOW:
  6930. case W_REVOLVER:
  6931. case W_RIFLE:
  6932. case W_GATLING:
  6933. case W_SHOTGUN:
  6934. case W_GRENADE:
  6935. break;
  6936. default:
  6937. bonus += sc->getSCE(SC_ASSNCROS)->val2;
  6938. break;
  6939. }
  6940. }
  6941. #endif
  6942. }
  6943. if (bonus < 20 && sc->getSCE(SC_MADNESSCANCEL))
  6944. bonus = 20;
  6945. else if (bonus < 15 && sc->getSCE(SC_BERSERK))
  6946. bonus = 15;
  6947. if (sc->getSCE(sc_val = SC_ASPDPOTION3) || sc->getSCE(sc_val = SC_ASPDPOTION2) || sc->getSCE(sc_val = SC_ASPDPOTION1) || sc->getSCE(sc_val = SC_ASPDPOTION0))
  6948. bonus += sc->getSCE(sc_val)->val1;
  6949. } else {
  6950. if (sc->getSCE(SC_DONTFORGETME))
  6951. bonus -= sc->getSCE(SC_DONTFORGETME)->val2 / 10;
  6952. #ifdef RENEWAL
  6953. if (sc->getSCE(SC_ENSEMBLEFATIGUE))
  6954. bonus -= sc->getSCE(SC_ENSEMBLEFATIGUE)->val2 / 10;
  6955. #else
  6956. if (sc->getSCE(SC_LONGING))
  6957. bonus -= sc->getSCE(SC_LONGING)->val2 / 10;
  6958. #endif
  6959. if (sc->getSCE(SC_STEELBODY))
  6960. bonus -= 25;
  6961. if (sc->getSCE(SC_SKA))
  6962. bonus -= 25;
  6963. if (sc->getSCE(SC_DEFENDER))
  6964. bonus -= sc->getSCE(SC_DEFENDER)->val4 / 10;
  6965. if (sc->getSCE(SC_GOSPEL) && sc->getSCE(SC_GOSPEL)->val4 == BCT_ENEMY)
  6966. bonus -= 75;
  6967. #ifndef RENEWAL
  6968. if (sc->getSCE(SC_GRAVITATION))
  6969. bonus -= sc->getSCE(SC_GRAVITATION)->val2 / 10; // Needs more info
  6970. #endif
  6971. if (sc->getSCE(SC_JOINTBEAT)) { // Needs more info
  6972. if (sc->getSCE(SC_JOINTBEAT)->val2&BREAK_WRIST)
  6973. bonus -= 25;
  6974. if (sc->getSCE(SC_JOINTBEAT)->val2&BREAK_KNEE)
  6975. bonus -= 10;
  6976. }
  6977. if (sc->getSCE(SC_FREEZING))
  6978. bonus -= 30;
  6979. if (sc->getSCE(SC_HALLUCINATIONWALK_POSTDELAY))
  6980. bonus -= 50;
  6981. if (sc->getSCE(SC_PARALYSE) && sc->getSCE(SC_PARALYSE)->val3 == 1)
  6982. bonus -= 10;
  6983. if (sc->getSCE(SC__BODYPAINT))
  6984. bonus -= 5 * sc->getSCE(SC__BODYPAINT)->val1;
  6985. if (sc->getSCE(SC__INVISIBILITY))
  6986. bonus -= sc->getSCE(SC__INVISIBILITY)->val2;
  6987. if (sc->getSCE(SC__GROOMY))
  6988. bonus -= sc->getSCE(SC__GROOMY)->val2;
  6989. if (sc->getSCE(SC_SWINGDANCE))
  6990. bonus += sc->getSCE(SC_SWINGDANCE)->val3;
  6991. if (sc->getSCE(SC_DANCEWITHWUG))
  6992. bonus += sc->getSCE(SC_DANCEWITHWUG)->val3;
  6993. if (sc->getSCE(SC_GLOOMYDAY))
  6994. bonus -= sc->getSCE(SC_GLOOMYDAY)->val3;
  6995. if (sc->getSCE(SC_GT_CHANGE))
  6996. bonus += sc->getSCE(SC_GT_CHANGE)->val3;
  6997. if (sc->getSCE(SC_MELON_BOMB))
  6998. bonus -= sc->getSCE(SC_MELON_BOMB)->val3;
  6999. if (sc->getSCE(SC_GOLDENE_FERSE))
  7000. bonus += sc->getSCE(SC_GOLDENE_FERSE)->val3;
  7001. if (sc->getSCE(SC_INCASPDRATE))
  7002. bonus += sc->getSCE(SC_INCASPDRATE)->val1;
  7003. if (sc->getSCE(SC_GATLINGFEVER))
  7004. bonus += sc->getSCE(SC_GATLINGFEVER)->val1;
  7005. if (sc->getSCE(SC_STAR_COMFORT))
  7006. bonus += 3 * sc->getSCE(SC_STAR_COMFORT)->val1;
  7007. if (sc->getSCE(SC_WIND_INSIGNIA) && sc->getSCE(SC_WIND_INSIGNIA)->val1 == 2)
  7008. bonus += 10;
  7009. if (sc->getSCE(SC_INCREASEAGI))
  7010. bonus += sc->getSCE(SC_INCREASEAGI)->val1;
  7011. if (sc->getSCE(SC_NIBELUNGEN) && sc->getSCE(SC_NIBELUNGEN)->val2 == RINGNBL_ASPDRATE)
  7012. bonus += 20;
  7013. if (sc->getSCE(SC_STARSTANCE))
  7014. bonus += sc->getSCE(SC_STARSTANCE)->val2;
  7015. map_session_data* sd = BL_CAST(BL_PC, bl);
  7016. uint8 skill_lv;
  7017. if (sd) {
  7018. if ((skill_lv = pc_checkskill(sd, BA_MUSICALLESSON)) > 0)
  7019. bonus += skill_lv;
  7020. if ((skill_lv = pc_checkskill(sd, RG_PLAGIARISM)) > 0)
  7021. bonus += skill_lv;
  7022. }
  7023. }
  7024. return bonus;
  7025. }
  7026. #endif
  7027. /**
  7028. * Modifies ASPD by a number, rather than a percentage (10 = 1 ASPD)
  7029. * A subtraction reduces the delay, meaning an increase in ASPD
  7030. * This comes after the percentage changes and is based on status changes
  7031. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  7032. * @param sc: Object's status change information
  7033. * @param aspd: Object's current ASPD
  7034. * @return modified aspd
  7035. */
  7036. static int16 status_calc_fix_aspd(struct block_list *bl, status_change *sc, int32 aspd)
  7037. {
  7038. if (sc == nullptr || sc->empty())
  7039. return cap_value(aspd, 0, 2000);
  7040. if (sc->getSCE(SC_OVERED_BOOST))
  7041. return cap_value(2000 - sc->getSCE(SC_OVERED_BOOST)->val3 * 10, 0, 2000);
  7042. if ((sc->getSCE(SC_GUST_OPTION) || sc->getSCE(SC_BLAST_OPTION) || sc->getSCE(SC_WILD_STORM_OPTION)))
  7043. aspd -= 50; // +5 ASPD
  7044. if (sc->getSCE(SC_FIGHTINGSPIRIT))
  7045. aspd -= sc->getSCE(SC_FIGHTINGSPIRIT)->val2;
  7046. if (sc->getSCE(SC_SOULSHADOW))
  7047. aspd -= 10 * sc->getSCE(SC_SOULSHADOW)->val2;
  7048. if (sc->getSCE(SC_HEAT_BARREL))
  7049. aspd -= sc->getSCE(SC_HEAT_BARREL)->val1 * 10;
  7050. if (sc->getSCE(SC_SINCERE_FAITH))
  7051. aspd -= 10 * sc->getSCE(SC_SINCERE_FAITH)->val2;
  7052. return cap_value(aspd, 0, 2000); // Will be recap for proper bl anyway
  7053. }
  7054. /**
  7055. * Calculates an object's ASPD modifier based on status changes (alters amotion value)
  7056. * Note: The scale of aspd_rate is 1000 = 100%
  7057. * Note2: This only affects Homunculus, Mercenaries, and Pre-renewal Players
  7058. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  7059. * @param sc: Object's status change information
  7060. * @param aspd_rate: Object's current ASPD
  7061. * @return modified aspd_rate
  7062. */
  7063. static int16 status_calc_aspd_rate(struct block_list *bl, status_change *sc, int32 aspd_rate)
  7064. {
  7065. int32 i;
  7066. if(sc == nullptr || sc->empty())
  7067. return cap_value(aspd_rate,0,SHRT_MAX);
  7068. int32 max = 0;
  7069. if (sc->getSCE(SC_STAR_COMFORT))
  7070. max = sc->getSCE(SC_STAR_COMFORT)->val2;
  7071. if (sc->getSCE(SC_TWOHANDQUICKEN) &&
  7072. max < sc->getSCE(SC_TWOHANDQUICKEN)->val2)
  7073. max = sc->getSCE(SC_TWOHANDQUICKEN)->val2;
  7074. if (sc->getSCE(SC_ONEHAND) &&
  7075. max < sc->getSCE(SC_ONEHAND)->val2)
  7076. max = sc->getSCE(SC_ONEHAND)->val2;
  7077. if (sc->getSCE(SC_MERC_QUICKEN) &&
  7078. max < sc->getSCE(SC_MERC_QUICKEN)->val2)
  7079. max = sc->getSCE(SC_MERC_QUICKEN)->val2;
  7080. if (sc->getSCE(SC_ADRENALINE2) &&
  7081. max < sc->getSCE(SC_ADRENALINE2)->val3)
  7082. max = sc->getSCE(SC_ADRENALINE2)->val3;
  7083. if (sc->getSCE(SC_ADRENALINE) &&
  7084. max < sc->getSCE(SC_ADRENALINE)->val3)
  7085. max = sc->getSCE(SC_ADRENALINE)->val3;
  7086. if (sc->getSCE(SC_SPEARQUICKEN) &&
  7087. max < sc->getSCE(SC_SPEARQUICKEN)->val2)
  7088. max = sc->getSCE(SC_SPEARQUICKEN)->val2;
  7089. if (sc->getSCE(SC_GATLINGFEVER) &&
  7090. max < sc->getSCE(SC_GATLINGFEVER)->val2)
  7091. max = sc->getSCE(SC_GATLINGFEVER)->val2;
  7092. if (sc->getSCE(SC_FLEET) &&
  7093. max < sc->getSCE(SC_FLEET)->val2)
  7094. max = sc->getSCE(SC_FLEET)->val2;
  7095. if (sc->getSCE(SC_INVINCIBLE) &&
  7096. max < sc->getSCE(SC_INVINCIBLE)->val4)
  7097. max = sc->getSCE(SC_INVINCIBLE)->val4;
  7098. if (sc->getSCE(SC_ASSNCROS) && max < sc->getSCE(SC_ASSNCROS)->val2) {
  7099. if (bl->type != BL_PC)
  7100. max = sc->getSCE(SC_ASSNCROS)->val2;
  7101. else
  7102. switch (((TBL_PC*)bl)->status.weapon) {
  7103. case W_BOW:
  7104. case W_REVOLVER:
  7105. case W_RIFLE:
  7106. case W_GATLING:
  7107. case W_SHOTGUN:
  7108. case W_GRENADE:
  7109. break;
  7110. default:
  7111. max = sc->getSCE(SC_ASSNCROS)->val2;
  7112. }
  7113. }
  7114. aspd_rate -= max;
  7115. if (sc->getSCE(SC_BERSERK))
  7116. aspd_rate -= 300;
  7117. else if (sc->getSCE(SC_MADNESSCANCEL))
  7118. aspd_rate -= 200;
  7119. if( sc->getSCE(i=SC_ASPDPOTION3) ||
  7120. sc->getSCE(i=SC_ASPDPOTION2) ||
  7121. sc->getSCE(i=SC_ASPDPOTION1) ||
  7122. sc->getSCE(i=SC_ASPDPOTION0) )
  7123. aspd_rate -= sc->getSCE(i)->val2;
  7124. if(sc->getSCE(SC_DONTFORGETME))
  7125. aspd_rate += sc->getSCE(SC_DONTFORGETME)->val2;
  7126. #ifdef RENEWAL
  7127. if (sc->getSCE(SC_ENSEMBLEFATIGUE))
  7128. aspd_rate += sc->getSCE(SC_ENSEMBLEFATIGUE)->val2;
  7129. #else
  7130. if(sc->getSCE(SC_LONGING))
  7131. aspd_rate += sc->getSCE(SC_LONGING)->val2;
  7132. #endif
  7133. if(sc->getSCE(SC_STEELBODY))
  7134. aspd_rate += 250;
  7135. if(sc->getSCE(SC_SKA))
  7136. aspd_rate += 250;
  7137. if(sc->getSCE(SC_DEFENDER))
  7138. aspd_rate += sc->getSCE(SC_DEFENDER)->val4;
  7139. if(sc->getSCE(SC_GOSPEL) && sc->getSCE(SC_GOSPEL)->val4 == BCT_ENEMY)
  7140. aspd_rate += 250;
  7141. #ifndef RENEWAL
  7142. if(sc->getSCE(SC_GRAVITATION))
  7143. aspd_rate += sc->getSCE(SC_GRAVITATION)->val2;
  7144. #endif
  7145. if(sc->getSCE(SC_JOINTBEAT)) {
  7146. if( sc->getSCE(SC_JOINTBEAT)->val2&BREAK_WRIST )
  7147. aspd_rate += 250;
  7148. if( sc->getSCE(SC_JOINTBEAT)->val2&BREAK_KNEE )
  7149. aspd_rate += 100;
  7150. }
  7151. if( sc->getSCE(SC_FREEZING) )
  7152. aspd_rate += 300;
  7153. if( sc->getSCE(SC_HALLUCINATIONWALK_POSTDELAY) )
  7154. aspd_rate += 500;
  7155. if( sc->getSCE(SC_PARALYSE) && sc->getSCE(SC_PARALYSE)->val3 == 1 )
  7156. aspd_rate += 100;
  7157. if( sc->getSCE(SC__BODYPAINT) )
  7158. aspd_rate += 50 * sc->getSCE(SC__BODYPAINT)->val1;
  7159. if( sc->getSCE(SC__INVISIBILITY) )
  7160. aspd_rate += sc->getSCE(SC__INVISIBILITY)->val2 * 10;
  7161. if( sc->getSCE(SC__GROOMY) )
  7162. aspd_rate += sc->getSCE(SC__GROOMY)->val2 * 10;
  7163. if( sc->getSCE(SC_SWINGDANCE) )
  7164. aspd_rate -= sc->getSCE(SC_SWINGDANCE)->val3 * 10;
  7165. if( sc->getSCE(SC_DANCEWITHWUG) )
  7166. aspd_rate -= sc->getSCE(SC_DANCEWITHWUG)->val3 * 10;
  7167. if( sc->getSCE(SC_GLOOMYDAY) )
  7168. aspd_rate += sc->getSCE(SC_GLOOMYDAY)->val3 * 10;
  7169. if( sc->getSCE(SC_GT_CHANGE) )
  7170. aspd_rate -= sc->getSCE(SC_GT_CHANGE)->val3 * 10;
  7171. if( sc->getSCE(SC_MELON_BOMB) )
  7172. aspd_rate += sc->getSCE(SC_MELON_BOMB)->val3 * 10;
  7173. if( sc->getSCE(SC_INCASPDRATE) )
  7174. aspd_rate -= sc->getSCE(SC_INCASPDRATE)->val1 * 10;
  7175. if( sc->getSCE(SC_GOLDENE_FERSE))
  7176. aspd_rate -= sc->getSCE(SC_GOLDENE_FERSE)->val3 * 10;
  7177. if (sc->getSCE(SC_WIND_INSIGNIA) && sc->getSCE(SC_WIND_INSIGNIA)->val1 == 2)
  7178. aspd_rate -= 100;
  7179. if (sc->getSCE(SC_STARSTANCE))
  7180. aspd_rate -= 10 * sc->getSCE(SC_STARSTANCE)->val2;
  7181. return (int16)cap_value(aspd_rate,0,SHRT_MAX);
  7182. }
  7183. /**
  7184. * Modifies the damage delay time based on status changes
  7185. * The lower your delay, the quicker you can act after taking damage
  7186. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  7187. * @param sc: Object's status change information
  7188. * @param dmotion: Object's current damage delay
  7189. * @return modified delay rate
  7190. */
  7191. static uint16 status_calc_dmotion(struct block_list *bl, status_change *sc, int32 dmotion)
  7192. {
  7193. /// It has been confirmed on official servers that MvP mobs have no dmotion even without endure
  7194. if( bl->type == BL_MOB && status_get_class_(bl) == CLASS_BOSS )
  7195. return 0;
  7196. if (bl->type == BL_PC) {
  7197. if (map_flag_gvg2(bl->m) || map_getmapflag(bl->m, MF_BATTLEGROUND))
  7198. return (uint16)cap_value(dmotion, 0, USHRT_MAX);
  7199. if (((TBL_PC *)bl)->special_state.no_walk_delay)
  7200. return 0;
  7201. }
  7202. if (sc != nullptr && !sc->empty() && (sc->getSCE(SC_ENDURE) || sc->getSCE(SC_RUN) || sc->getSCE(SC_WUGDASH)))
  7203. return 0;
  7204. return (uint16)cap_value(dmotion,0,USHRT_MAX);
  7205. }
  7206. /**
  7207. * Adds power atk modifications based on status changes
  7208. * @param bl: Object to change patk [PC|MOB|HOM|MER|ELEM]
  7209. * @param sc: Object's status change information
  7210. * @param patk: Initial patk
  7211. * @return modified patk with cap_value(patk,0,USHRT_MAX)
  7212. */
  7213. static int16 status_calc_patk(struct block_list *bl, status_change *sc, int32 patk)
  7214. {
  7215. if (sc == nullptr || sc->empty())
  7216. return cap_value(patk, 0, SHRT_MAX);
  7217. if (sc->getSCE(SC_POWERFUL_FAITH))
  7218. patk += sc->getSCE(SC_POWERFUL_FAITH)->val3;
  7219. if (sc->getSCE(SC_COMPETENTIA))
  7220. patk += sc->getSCE(SC_COMPETENTIA)->val2;
  7221. if (sc->getSCE(SC_ABYSS_SLAYER))
  7222. patk += sc->getSCE(SC_ABYSS_SLAYER)->val2;
  7223. if (sc->getSCE(SC_PRON_MARCH))
  7224. patk += sc->getSCE(SC_PRON_MARCH)->val2;
  7225. if (sc->getSCE(SC_TEMPERING))
  7226. patk += sc->getSCE(SC_TEMPERING)->val2;
  7227. if( sc->getSCE( SC_ATTACK_STANCE ) ){
  7228. patk += sc->getSCE( SC_ATTACK_STANCE )->val3;
  7229. }
  7230. if (sc->getSCE(SC_HIDDEN_CARD))
  7231. patk += sc->getSCE(SC_HIDDEN_CARD)->val2;
  7232. if (sc->getSCE(SC_TALISMAN_OF_WARRIOR) != nullptr)
  7233. patk += sc->getSCE(SC_TALISMAN_OF_WARRIOR)->val2;
  7234. if (sc->getSCE(SC_TEMPORARY_COMMUNION) != nullptr)
  7235. patk += sc->getSCE(SC_TEMPORARY_COMMUNION)->val2;
  7236. if (sc->getSCE(SC_BLESSING_OF_M_CREATURES) != nullptr)
  7237. patk += sc->getSCE(SC_BLESSING_OF_M_CREATURES)->val2;
  7238. return (int16)cap_value(patk, 0, SHRT_MAX);
  7239. }
  7240. /**
  7241. * Adds spell matk modifications based on status changes
  7242. * @param bl: Object to change smatk [PC|MOB|HOM|MER|ELEM]
  7243. * @param sc: Object's status change information
  7244. * @param smatk: Initial smatk
  7245. * @return modified smatk with cap_value(smatk,0,USHRT_MAX)
  7246. */
  7247. static int16 status_calc_smatk(struct block_list *bl, status_change *sc, int32 smatk)
  7248. {
  7249. if (sc == nullptr || sc->empty())
  7250. return cap_value(smatk, 0, SHRT_MAX);
  7251. if (sc->getSCE(SC_COMPETENTIA))
  7252. smatk += sc->getSCE(SC_COMPETENTIA)->val2;
  7253. if (sc->getSCE(SC_ABYSS_SLAYER))
  7254. smatk += sc->getSCE(SC_ABYSS_SLAYER)->val2;
  7255. if (sc->getSCE(SC_JAWAII_SERENADE))
  7256. smatk += sc->getSCE(SC_JAWAII_SERENADE)->val2;
  7257. if (sc->getSCE(SC_SPELL_ENCHANTING))
  7258. smatk += sc->getSCE(SC_SPELL_ENCHANTING)->val2;
  7259. if( sc->getSCE( SC_ATTACK_STANCE ) ){
  7260. smatk += sc->getSCE( SC_ATTACK_STANCE )->val3;
  7261. }
  7262. if (sc->getSCE(SC_TALISMAN_OF_MAGICIAN) != nullptr)
  7263. smatk += sc->getSCE(SC_TALISMAN_OF_MAGICIAN)->val2;
  7264. if (sc->getSCE(SC_T_FIFTH_GOD) != nullptr)
  7265. smatk += sc->getSCE(SC_T_FIFTH_GOD)->val2;
  7266. if (sc->getSCE(SC_TEMPORARY_COMMUNION) != nullptr)
  7267. smatk += sc->getSCE(SC_TEMPORARY_COMMUNION)->val2;
  7268. if (sc->getSCE(SC_BLESSING_OF_M_CREATURES) != nullptr)
  7269. smatk += sc->getSCE(SC_BLESSING_OF_M_CREATURES)->val2;
  7270. return (int16)cap_value(smatk, 0, SHRT_MAX);
  7271. }
  7272. /**
  7273. * Adds resist modifications based on status changes
  7274. * @param bl: Object to change res [PC|MOB|HOM|MER|ELEM]
  7275. * @param sc: Object's status change information
  7276. * @param res: Initial res
  7277. * @return modified res with cap_value(res,0,USHRT_MAX)
  7278. */
  7279. static int16 status_calc_res(struct block_list *bl, status_change *sc, int32 res)
  7280. {
  7281. if (sc == nullptr || sc->empty())
  7282. return cap_value(res, 0, SHRT_MAX);
  7283. if (sc->getSCE(SC_FIRM_FAITH))
  7284. res += sc->getSCE(SC_FIRM_FAITH)->val3;
  7285. if (sc->getSCE(SC_D_MACHINE))
  7286. res += sc->getSCE(SC_D_MACHINE)->val3;
  7287. if (sc->getSCE(SC_MUSICAL_INTERLUDE))
  7288. res += sc->getSCE(SC_MUSICAL_INTERLUDE)->val2;
  7289. if (sc->getSCE(SC_GOLDENE_TONE))
  7290. res += sc->getSCE(SC_GOLDENE_TONE)->val2;
  7291. if (sc->getSCE(SC_SHADOW_STRIP) && bl->type != BL_PC)
  7292. res -= res * sc->getSCE(SC_SHADOW_STRIP)->val2 / 100;
  7293. if (sc->getSCE(SC_AIN_RHAPSODY))
  7294. res -= sc->getSCE(SC_AIN_RHAPSODY)->val2;
  7295. if (sc->getSCE(SC_TOXIN_OF_MANDARA))
  7296. res -= sc->getSCE(SC_TOXIN_OF_MANDARA)->val2;
  7297. return (int16)cap_value(res, 0, SHRT_MAX);
  7298. }
  7299. /**
  7300. * Adds magic resist modifications based on status changes
  7301. * @param bl: Object to change mres [PC|MOB|HOM|MER|ELEM]
  7302. * @param sc: Object's status change information
  7303. * @param mres: Initial mres
  7304. * @return modified mres with cap_value(mres,0,USHRT_MAX)
  7305. */
  7306. static int16 status_calc_mres(struct block_list *bl, status_change *sc, int32 mres)
  7307. {
  7308. if (sc == nullptr || sc->empty())
  7309. return cap_value(mres, 0, SHRT_MAX);
  7310. if (sc->getSCE(SC_GOLDENE_TONE))
  7311. mres += sc->getSCE(SC_GOLDENE_TONE)->val2;
  7312. if (sc->getSCE(SC_SHADOW_STRIP) && bl->type != BL_PC)
  7313. mres -= mres * sc->getSCE(SC_SHADOW_STRIP)->val2 / 100;
  7314. if (sc->getSCE(SC_GEF_NOCTURN))
  7315. mres -= sc->getSCE(SC_GEF_NOCTURN)->val2;
  7316. return (int16)cap_value(mres, 0, SHRT_MAX);
  7317. }
  7318. /**
  7319. * Adds heal plus modifications based on status changes
  7320. * @param bl: Object to change hplus [PC|MOB|HOM|MER|ELEM]
  7321. * @param sc: Object's status change information
  7322. * @param hplus: Initial hplus
  7323. * @return modified hplus with cap_value(hplus,0,USHRT_MAX)
  7324. */
  7325. static int16 status_calc_hplus(struct block_list *bl, status_change *sc, int32 hplus)
  7326. {
  7327. if (sc == nullptr || sc->empty())
  7328. return cap_value(hplus, 0, SHRT_MAX);
  7329. if (sc->getSCE(SC_TEMPORARY_COMMUNION) != nullptr)
  7330. hplus += sc->getSCE(SC_TEMPORARY_COMMUNION)->val2;
  7331. return (int16)cap_value(hplus, 0, SHRT_MAX);
  7332. }
  7333. /**
  7334. * Adds critical damage rate modifications based on status changes
  7335. * @param bl: Object to change crate [PC|MOB|HOM|MER|ELEM]
  7336. * @param sc: Object's status change information
  7337. * @param crate: Initial crate
  7338. * @return modified crate with cap_value(crate,0,USHRT_MAX)
  7339. */
  7340. static int16 status_calc_crate(struct block_list *bl, status_change *sc, int32 crate)
  7341. {
  7342. if (sc == nullptr || sc->empty())
  7343. return cap_value(crate, 0, SHRT_MAX);
  7344. if (sc->getSCE(SC_PRE_ACIES))
  7345. crate += sc->getSCE(SC_PRE_ACIES)->val2;
  7346. return (int16)cap_value(crate, 0, SHRT_MAX);
  7347. }
  7348. /**
  7349. * Calculates a max HP based on status changes
  7350. * Values can either be percentages or fixed, based on how equations are formulated
  7351. * @param bl: Object's block_list data
  7352. * @param maxhp: Object's current max HP
  7353. * @return modified maxhp
  7354. */
  7355. static uint32 status_calc_maxhp(struct block_list *bl, uint64 maxhp)
  7356. {
  7357. int32 rate = 100;
  7358. maxhp += status_get_hpbonus(bl,STATUS_BONUS_FIX);
  7359. if ((rate += status_get_hpbonus(bl,STATUS_BONUS_RATE)) != 100)
  7360. maxhp = maxhp * rate / 100;
  7361. return (uint32)cap_value(maxhp,1,UINT_MAX);
  7362. }
  7363. /**
  7364. * Calculates a max SP based on status changes
  7365. * Values can either be percentages or fixed, bas ed on how equations are formulated
  7366. * @param bl: Object's block_list data
  7367. * @param maxsp: Object's current max SP
  7368. * @return modified maxsp
  7369. */
  7370. static uint32 status_calc_maxsp(struct block_list *bl, uint64 maxsp)
  7371. {
  7372. int32 rate = 100;
  7373. maxsp += status_get_spbonus(bl,STATUS_BONUS_FIX);
  7374. if ((rate += status_get_spbonus(bl,STATUS_BONUS_RATE)) != 100)
  7375. maxsp = maxsp * rate / 100;
  7376. return (uint32)cap_value(maxsp,1,UINT_MAX);
  7377. }
  7378. /**
  7379. * Calculates a max AP based on status changes
  7380. * Values can either be percentages or fixed, bas ed on how equations are formulated
  7381. * @param bl: Object's block_list data
  7382. * @param maxap: Object's current max AP
  7383. * @return modified maxap
  7384. */
  7385. static uint32 status_calc_maxap(struct block_list *bl, uint64 maxap)
  7386. {
  7387. int32 rate = 100;
  7388. maxap += status_get_apbonus(bl, STATUS_BONUS_FIX);
  7389. if ((rate += status_get_apbonus(bl, STATUS_BONUS_RATE)) != 100)
  7390. maxap = maxap * rate / 100;
  7391. return (uint32)cap_value(maxap, 0, UINT_MAX);
  7392. }
  7393. /**
  7394. * Changes a player's element based on status changes
  7395. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  7396. * @param sc: Object's status change information
  7397. * @param element: Object's current element
  7398. * @return new element
  7399. */
  7400. static unsigned char status_calc_element(struct block_list *bl, status_change *sc, int32 element)
  7401. {
  7402. if(sc == nullptr || sc->empty())
  7403. return cap_value(element, 0, UCHAR_MAX);
  7404. if(sc->getSCE(SC_FREEZE) || sc->getSCE(SC_CRYSTAL_ARMOR_OPTION))
  7405. return ELE_WATER;
  7406. if(sc->getSCE(SC_STONE) || sc->getSCE(SC_STRONG_PROTECTION_OPTION))
  7407. return ELE_EARTH;
  7408. if(sc->getSCE(SC_FLAMEARMOR_OPTION))
  7409. return ELE_FIRE;
  7410. if(sc->getSCE(SC_EYES_OF_STORM_OPTION))
  7411. return ELE_WIND;
  7412. if(sc->getSCE(SC_POISON_SHIELD_OPTION))
  7413. return ELE_POISON;
  7414. if(sc->getSCE(SC_BENEDICTIO))
  7415. return ELE_HOLY;
  7416. if(sc->getSCE(SC_CHANGEUNDEAD))
  7417. return ELE_UNDEAD;
  7418. if(sc->getSCE(SC_ELEMENTALCHANGE))
  7419. return sc->getSCE(SC_ELEMENTALCHANGE)->val2;
  7420. if(sc->getSCE(SC_SHAPESHIFT))
  7421. return sc->getSCE(SC_SHAPESHIFT)->val2;
  7422. return (unsigned char)cap_value(element,0,UCHAR_MAX);
  7423. }
  7424. /**
  7425. * Changes a player's element level based on status changes
  7426. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  7427. * @param sc: Object's status change information
  7428. * @param lv: Object's current element level
  7429. * @return new element level
  7430. */
  7431. static unsigned char status_calc_element_lv(struct block_list *bl, status_change *sc, int32 lv)
  7432. {
  7433. if(sc == nullptr || sc->empty())
  7434. return cap_value(lv, 1, 4);
  7435. if(sc->getSCE(SC_FREEZE))
  7436. return 1;
  7437. if(sc->getSCE(SC_STONE))
  7438. return 1;
  7439. if(sc->getSCE(SC_BENEDICTIO))
  7440. return 1;
  7441. if(sc->getSCE(SC_CHANGEUNDEAD))
  7442. return 1;
  7443. if(sc->getSCE(SC_ELEMENTALCHANGE))
  7444. return sc->getSCE(SC_ELEMENTALCHANGE)->val1;
  7445. if(sc->getSCE(SC_SHAPESHIFT))
  7446. return 1;
  7447. if(sc->getSCE(SC__INVISIBILITY))
  7448. return 1;
  7449. if (sc->getSCE(SC_FLAMEARMOR_OPTION) || sc->getSCE(SC_CRYSTAL_ARMOR_OPTION) || sc->getSCE(SC_EYES_OF_STORM_OPTION) ||
  7450. sc->getSCE(SC_STRONG_PROTECTION_OPTION) || sc->getSCE(SC_POISON_SHIELD_OPTION))
  7451. return 1;
  7452. return (unsigned char)cap_value(lv,1,4);
  7453. }
  7454. /**
  7455. * Changes a player's attack element based on status changes
  7456. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  7457. * @param sc: Object's status change information
  7458. * @param element: Object's current attack element
  7459. * @return new attack element
  7460. */
  7461. unsigned char status_calc_attack_element(struct block_list *bl, status_change *sc, int32 element)
  7462. {
  7463. if(sc == nullptr || sc->empty())
  7464. return cap_value(element, 0, UCHAR_MAX);
  7465. if(sc->getSCE(SC_ENCHANTARMS))
  7466. return sc->getSCE(SC_ENCHANTARMS)->val1;
  7467. if(sc->getSCE(SC_WATERWEAPON)
  7468. || (sc->getSCE(SC_WATER_INSIGNIA) && sc->getSCE(SC_WATER_INSIGNIA)->val1 == 2) )
  7469. return ELE_WATER;
  7470. if(sc->getSCE(SC_EARTHWEAPON)
  7471. || (sc->getSCE(SC_EARTH_INSIGNIA) && sc->getSCE(SC_EARTH_INSIGNIA)->val1 == 2) )
  7472. return ELE_EARTH;
  7473. if(sc->getSCE(SC_FIREWEAPON)
  7474. || (sc->getSCE(SC_FIRE_INSIGNIA) && sc->getSCE(SC_FIRE_INSIGNIA)->val1 == 2) )
  7475. return ELE_FIRE;
  7476. if(sc->getSCE(SC_WINDWEAPON)
  7477. || (sc->getSCE(SC_WIND_INSIGNIA) && sc->getSCE(SC_WIND_INSIGNIA)->val1 == 2) )
  7478. return ELE_WIND;
  7479. if(sc->getSCE(SC_ENCPOISON))
  7480. return ELE_POISON;
  7481. if(sc->getSCE(SC_ASPERSIO))
  7482. return ELE_HOLY;
  7483. if(sc->getSCE(SC_SHADOWWEAPON))
  7484. return ELE_DARK;
  7485. if(sc->getSCE(SC_GHOSTWEAPON) || sc->getSCE(SC__INVISIBILITY))
  7486. return ELE_GHOST;
  7487. if(sc->getSCE(SC_TIDAL_WEAPON_OPTION) || sc->getSCE(SC_TIDAL_WEAPON) )
  7488. return ELE_WATER;
  7489. return (unsigned char)cap_value(element,0,UCHAR_MAX);
  7490. }
  7491. /**
  7492. * Changes the mode of an object
  7493. * @param bl: Object whose mode to change [PC|MOB|PET|HOM|NPC]
  7494. * @param sc: Object's status change data
  7495. * @param mode: Original mode
  7496. * @return mode with cap_value(mode, 0, INT_MAX)
  7497. */
  7498. static int32 status_calc_mode(struct block_list *bl, status_change *sc, int32 mode)
  7499. {
  7500. if(sc == nullptr || sc->empty())
  7501. return cap_value(mode, MD_NONE,INT_MAX);
  7502. if(sc->getSCE(SC_MODECHANGE)) {
  7503. if (sc->getSCE(SC_MODECHANGE)->val2)
  7504. mode = (mode&~MD_MASK)|sc->getSCE(SC_MODECHANGE)->val2; // Set mode
  7505. if (sc->getSCE(SC_MODECHANGE)->val3)
  7506. mode = mode|sc->getSCE(SC_MODECHANGE)->val3; // Add mode
  7507. if (sc->getSCE(SC_MODECHANGE)->val4)
  7508. mode = mode&~sc->getSCE(SC_MODECHANGE)->val4; // Del mode
  7509. }
  7510. return cap_value(mode, MD_NONE, INT_MAX);
  7511. }
  7512. /**
  7513. * Changes the mode of a slave mob
  7514. * @param md: Slave mob whose mode to change
  7515. */
  7516. void status_calc_slave_mode(mob_data& md)
  7517. {
  7518. switch (battle_config.slaves_inherit_mode) {
  7519. case 1: //Always aggressive
  7520. if (!status_has_mode(&md.status,MD_AGGRESSIVE))
  7521. sc_start4(nullptr, &md.bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 0);
  7522. break;
  7523. case 2: //Always passive
  7524. if (status_has_mode(&md.status,MD_AGGRESSIVE))
  7525. sc_start4(nullptr, &md.bl, SC_MODECHANGE, 100, 1, 0, 0, MD_AGGRESSIVE, 0);
  7526. break;
  7527. case 4: // Overwrite with slave mode
  7528. sc_start4(nullptr, &md.bl, SC_MODECHANGE, 100, 1, MD_CANMOVE|MD_NORANDOMWALK|MD_CANATTACK, 0, 0, 0);
  7529. break;
  7530. default: //Copy master
  7531. if (block_list* mbl = map_id2bl(md.master_id); mbl != nullptr && status_has_mode(status_get_status_data(*mbl), MD_AGGRESSIVE))
  7532. sc_start4(nullptr, &md.bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 0);
  7533. else
  7534. sc_start4(nullptr, &md.bl, SC_MODECHANGE, 100, 1, 0, 0, MD_AGGRESSIVE, 0);
  7535. break;
  7536. }
  7537. }
  7538. /**
  7539. * Gets the name of the given bl
  7540. * @param bl: Object whose name to get [PC|MOB|PET|HOM|NPC]
  7541. * @return name or "Unknown" if any other bl->type than noted above
  7542. */
  7543. const char* status_get_name( block_list& bl ){
  7544. switch( bl.type ){
  7545. case BL_PC: {
  7546. map_session_data& sd = reinterpret_cast<map_session_data&>( bl );
  7547. if( sd.fakename[0] != '\0' ){
  7548. return sd.fakename;
  7549. }else{
  7550. return sd.status.name;
  7551. }
  7552. } break;
  7553. case BL_MOB:
  7554. return reinterpret_cast<mob_data&>( bl ).name;
  7555. case BL_PET:
  7556. return reinterpret_cast<pet_data&>( bl ).pet.name;
  7557. case BL_HOM:
  7558. return reinterpret_cast<homun_data&>( bl ).homunculus.name;
  7559. case BL_MER:
  7560. // They only have database names which are global, not specific to GID.
  7561. return reinterpret_cast<s_mercenary_data&>( bl ).db->name.c_str();
  7562. case BL_NPC:
  7563. return reinterpret_cast<npc_data&>( bl ).name;
  7564. case BL_ELEM:
  7565. // They only have database names which are global, not specific to GID.
  7566. return reinterpret_cast<s_elemental_data&>( bl ).db->name.c_str();
  7567. }
  7568. return "Unknown";
  7569. }
  7570. /**
  7571. * Gets the class/sprite id of the given bl
  7572. * @param bl: Object whose class to get [PC|MOB|PET|HOM|MER|NPC|ELEM]
  7573. * @return class or 0 if any other bl->type than noted above
  7574. */
  7575. int32 status_get_class(struct block_list *bl)
  7576. {
  7577. nullpo_ret(bl);
  7578. switch( bl->type ) {
  7579. case BL_PC: return ((TBL_PC*)bl)->status.class_;
  7580. case BL_MOB: return ((TBL_MOB*)bl)->vd->class_; // Class used on all code should be the view class of the mob.
  7581. case BL_PET: return ((TBL_PET*)bl)->pet.class_;
  7582. case BL_HOM: return ((TBL_HOM*)bl)->homunculus.class_;
  7583. case BL_MER: return ((TBL_MER*)bl)->mercenary.class_;
  7584. case BL_NPC: return ((TBL_NPC*)bl)->class_;
  7585. case BL_ELEM: return ((TBL_ELEM*)bl)->elemental.class_;
  7586. }
  7587. return 0;
  7588. }
  7589. /**
  7590. * Gets the base level of the given bl
  7591. * @param bl: Object whose base level to get [PC|MOB|PET|HOM|MER|NPC|ELEM]
  7592. * @return base level or 1 if any other bl->type than noted above
  7593. */
  7594. int32 status_get_lv(struct block_list *bl)
  7595. {
  7596. nullpo_ret(bl);
  7597. switch (bl->type) {
  7598. case BL_PC: return ((TBL_PC*)bl)->status.base_level;
  7599. case BL_MOB: return ((TBL_MOB*)bl)->level;
  7600. case BL_PET: return ((TBL_PET*)bl)->pet.level;
  7601. case BL_HOM: return ((TBL_HOM*)bl)->homunculus.level;
  7602. case BL_MER: return ((TBL_MER*)bl)->db->lv;
  7603. case BL_ELEM: return ((TBL_ELEM*)bl)->db->lv;
  7604. case BL_NPC: return ((TBL_NPC*)bl)->level;
  7605. }
  7606. return 1;
  7607. }
  7608. /**
  7609. * Gets the regeneration info of the given bl
  7610. * @param bl: Object whose regen info to get [PC|HOM|MER|ELEM]
  7611. * @return regen data or nullptr if any other bl->type than noted above
  7612. */
  7613. struct regen_data *status_get_regen_data(struct block_list *bl)
  7614. {
  7615. nullpo_retr(nullptr, bl);
  7616. switch (bl->type) {
  7617. case BL_PC: return &((TBL_PC*)bl)->regen;
  7618. case BL_HOM: return &((TBL_HOM*)bl)->regen;
  7619. case BL_MER: return &((TBL_MER*)bl)->regen;
  7620. case BL_ELEM: return &((TBL_ELEM*)bl)->regen;
  7621. default:
  7622. return nullptr;
  7623. }
  7624. }
  7625. /**
  7626. * Gets the status data of the given bl
  7627. * @param bl: Object whose status to get [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7628. * @return status or "dummy_status" if any other bl->type than noted above
  7629. */
  7630. status_data* status_get_status_data(block_list& bl){
  7631. switch (bl.type) {
  7632. case BL_PC:
  7633. return &reinterpret_cast<map_session_data*>( &bl )->battle_status;
  7634. case BL_MOB:
  7635. return &reinterpret_cast<mob_data*>( &bl )->status;
  7636. case BL_PET:
  7637. return &reinterpret_cast<pet_data*>( &bl )->status;
  7638. case BL_HOM:
  7639. return &reinterpret_cast<homun_data*>( &bl )->battle_status;
  7640. case BL_MER:
  7641. return &reinterpret_cast<s_mercenary_data*>( &bl )->battle_status;
  7642. case BL_ELEM:
  7643. return &reinterpret_cast<s_elemental_data*>( &bl )->battle_status;
  7644. case BL_NPC: {
  7645. npc_data* nd = reinterpret_cast<npc_data*>( &bl );
  7646. if( mobdb_checkid( nd->class_ ) == 0 ){
  7647. return &nd->status;
  7648. }else{
  7649. return &dummy_status;
  7650. }
  7651. }
  7652. default:
  7653. return &dummy_status;
  7654. }
  7655. }
  7656. /**
  7657. * Gets the base status data of the given bl
  7658. * @param bl: Object whose status to get [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7659. * @return base_status or nullptr if any other bl->type than noted above
  7660. */
  7661. struct status_data *status_get_base_status(struct block_list *bl)
  7662. {
  7663. nullpo_retr(nullptr, bl);
  7664. switch (bl->type) {
  7665. case BL_PC: return &((TBL_PC*)bl)->base_status;
  7666. case BL_MOB: return ((TBL_MOB*)bl)->base_status ? ((TBL_MOB*)bl)->base_status : &((TBL_MOB*)bl)->db->status;
  7667. case BL_PET: return &((TBL_PET*)bl)->db->status;
  7668. case BL_HOM: return &((TBL_HOM*)bl)->base_status;
  7669. case BL_MER: return &((TBL_MER*)bl)->base_status;
  7670. case BL_ELEM: return &((TBL_ELEM*)bl)->base_status;
  7671. case BL_NPC: return ((mobdb_checkid(((TBL_NPC*)bl)->class_) == 0) ? &((TBL_NPC*)bl)->status : nullptr);
  7672. default:
  7673. return nullptr;
  7674. }
  7675. }
  7676. /**
  7677. * Gets the defense of the given bl
  7678. * @param bl: Object whose defense to get [PC|MOB|HOM|MER|ELEM]
  7679. * @return defense with cap_value(def, DEFTYPE_MIN, DEFTYPE_MAX)
  7680. */
  7681. defType status_get_def(struct block_list *bl)
  7682. {
  7683. struct unit_data *ud;
  7684. status_data* status = status_get_status_data(*bl);
  7685. // TODO: check if dummy_status? Can never be nullptr [Lemongrass]
  7686. int32 def = status?status->def:0;
  7687. ud = unit_bl2ud(bl);
  7688. if (ud && ud->skilltimer != INVALID_TIMER)
  7689. def -= def * skill_get_castdef(ud->skill_id)/100;
  7690. return cap_value(def, DEFTYPE_MIN, DEFTYPE_MAX);
  7691. }
  7692. /**
  7693. * Gets the walking speed of the given bl
  7694. * @param bl: Object whose speed to get [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7695. * @return speed
  7696. */
  7697. uint16 status_get_speed(struct block_list *bl)
  7698. {
  7699. // TODO: is the statement of Skotlex still true? And would it not be better to check for dummy_status instead? [Lemongrass]
  7700. if(bl->type==BL_NPC)// Only BL with speed data but no status_data [Skotlex]
  7701. return ((struct npc_data *)bl)->speed;
  7702. return status_get_status_data(*bl)->speed;
  7703. }
  7704. /**
  7705. * Gets the party ID of the given bl
  7706. * @param bl: Object whose party ID to get [PC|MOB|PET|HOM|MER|SKILL|ELEM]
  7707. * @return party ID
  7708. */
  7709. int32 status_get_party_id(struct block_list *bl)
  7710. {
  7711. nullpo_ret(bl);
  7712. switch (bl->type) {
  7713. case BL_PC:
  7714. return ((TBL_PC*)bl)->status.party_id;
  7715. case BL_PET:
  7716. if (((TBL_PET*)bl)->master)
  7717. return ((TBL_PET*)bl)->master->status.party_id;
  7718. break;
  7719. case BL_MOB: {
  7720. struct mob_data *md=(TBL_MOB*)bl;
  7721. if( md->master_id > 0 ) {
  7722. map_session_data *msd;
  7723. if (md->special_state.ai && (msd = map_id2sd(md->master_id)) != nullptr)
  7724. return msd->status.party_id;
  7725. return -md->master_id;
  7726. }
  7727. }
  7728. break;
  7729. case BL_HOM:
  7730. if (((TBL_HOM*)bl)->master)
  7731. return ((TBL_HOM*)bl)->master->status.party_id;
  7732. break;
  7733. case BL_MER:
  7734. if (((TBL_MER*)bl)->master)
  7735. return ((TBL_MER*)bl)->master->status.party_id;
  7736. break;
  7737. case BL_SKILL:
  7738. if (((TBL_SKILL*)bl)->group)
  7739. return ((TBL_SKILL*)bl)->group->party_id;
  7740. break;
  7741. case BL_ELEM:
  7742. if (((TBL_ELEM*)bl)->master)
  7743. return ((TBL_ELEM*)bl)->master->status.party_id;
  7744. break;
  7745. }
  7746. return 0;
  7747. }
  7748. /**
  7749. * Gets the guild ID of the given bl
  7750. * @param bl: Object whose guild ID to get [PC|MOB|PET|HOM|MER|SKILL|ELEM|NPC]
  7751. * @return guild ID
  7752. */
  7753. int32 status_get_guild_id(struct block_list *bl)
  7754. {
  7755. nullpo_ret(bl);
  7756. switch (bl->type) {
  7757. case BL_PC:
  7758. return ((TBL_PC*)bl)->status.guild_id;
  7759. case BL_PET:
  7760. if (((TBL_PET*)bl)->master)
  7761. return ((TBL_PET*)bl)->master->status.guild_id;
  7762. break;
  7763. case BL_MOB:
  7764. {
  7765. map_session_data *msd;
  7766. struct mob_data *md = (struct mob_data *)bl;
  7767. if (md->guardian_data) // Guardian's guild [Skotlex]
  7768. return md->guardian_data->guild_id;
  7769. if (md->special_state.ai && (msd = map_id2sd(md->master_id)) != nullptr)
  7770. return msd->status.guild_id; // Alchemist's mobs [Skotlex]
  7771. }
  7772. break;
  7773. case BL_HOM:
  7774. if (((TBL_HOM*)bl)->master)
  7775. return ((TBL_HOM*)bl)->master->status.guild_id;
  7776. break;
  7777. case BL_MER:
  7778. if (((TBL_MER*)bl)->master)
  7779. return ((TBL_MER*)bl)->master->status.guild_id;
  7780. break;
  7781. case BL_NPC:
  7782. if (((TBL_NPC*)bl)->subtype == NPCTYPE_SCRIPT)
  7783. return ((TBL_NPC*)bl)->u.scr.guild_id;
  7784. break;
  7785. case BL_SKILL:
  7786. if (((TBL_SKILL*)bl)->group)
  7787. return ((TBL_SKILL*)bl)->group->guild_id;
  7788. break;
  7789. case BL_ELEM:
  7790. if (((TBL_ELEM*)bl)->master)
  7791. return ((TBL_ELEM*)bl)->master->status.guild_id;
  7792. break;
  7793. }
  7794. return 0;
  7795. }
  7796. /**
  7797. * Gets the guild emblem ID of the given bl
  7798. * @param bl: Object whose emblem ID to get [PC|MOB|PET|HOM|MER|SKILL|ELEM|NPC]
  7799. * @return guild emblem ID
  7800. */
  7801. int32 status_get_emblem_id(struct block_list *bl)
  7802. {
  7803. nullpo_ret(bl);
  7804. switch (bl->type) {
  7805. case BL_PC:
  7806. return ((TBL_PC*)bl)->guild_emblem_id;
  7807. case BL_PET:
  7808. if (((TBL_PET*)bl)->master)
  7809. return ((TBL_PET*)bl)->master->guild_emblem_id;
  7810. break;
  7811. case BL_MOB:
  7812. {
  7813. map_session_data *msd;
  7814. struct mob_data *md = (struct mob_data *)bl;
  7815. if (md->guardian_data) // Guardian's guild [Skotlex]
  7816. return md->guardian_data->emblem_id;
  7817. if (md->special_state.ai && (msd = map_id2sd(md->master_id)) != nullptr)
  7818. return msd->guild_emblem_id; // Alchemist's mobs [Skotlex]
  7819. }
  7820. break;
  7821. case BL_HOM:
  7822. if (((TBL_HOM*)bl)->master)
  7823. return ((TBL_HOM*)bl)->master->guild_emblem_id;
  7824. break;
  7825. case BL_MER:
  7826. if (((TBL_MER*)bl)->master)
  7827. return ((TBL_MER*)bl)->master->guild_emblem_id;
  7828. break;
  7829. case BL_NPC:
  7830. if (((TBL_NPC*)bl)->subtype == NPCTYPE_SCRIPT && ((TBL_NPC*)bl)->u.scr.guild_id > 0) {
  7831. auto g = guild_search(((TBL_NPC*)bl)->u.scr.guild_id);
  7832. if (g)
  7833. return g->guild.emblem_id;
  7834. }
  7835. break;
  7836. case BL_ELEM:
  7837. if (((TBL_ELEM*)bl)->master)
  7838. return ((TBL_ELEM*)bl)->master->guild_emblem_id;
  7839. break;
  7840. }
  7841. return 0;
  7842. }
  7843. /**
  7844. * Gets the race2 of a mob or pet
  7845. * @param bl: Object whose race2 to get [MOB|PET]
  7846. * @return race2
  7847. */
  7848. std::vector<e_race2> status_get_race2(struct block_list *bl)
  7849. {
  7850. nullpo_retr(std::vector<e_race2>(),bl);
  7851. if (bl->type == BL_MOB)
  7852. return ((struct mob_data *)bl)->db->race2;
  7853. if (bl->type == BL_PET)
  7854. return ((struct pet_data *)bl)->db->race2;
  7855. return std::vector<e_race2>();
  7856. }
  7857. /**
  7858. * Checks if an object is dead
  7859. * @param bl: Object to check [PC|MOB|HOM|MER|ELEM]
  7860. * @return 1: Is dead or 0: Is alive
  7861. */
  7862. bool status_isdead(block_list &bl){
  7863. return status_get_status_data(bl)->hp == 0;
  7864. }
  7865. /**
  7866. * Checks if an object is immune to magic
  7867. * @param bl: Object to check [PC|MOB|HOM|MER|ELEM]
  7868. * @return value of magic damage to be blocked
  7869. */
  7870. int32 status_isimmune(struct block_list *bl)
  7871. {
  7872. status_change *sc =status_get_sc(bl);
  7873. if (sc) {
  7874. if (sc->getSCE(SC_HERMODE))
  7875. return 100;
  7876. if (sc->getSCE(SC_DEADLY_DEFEASANCE))
  7877. return 0;
  7878. }
  7879. if (bl->type == BL_PC &&
  7880. ((TBL_PC*)bl)->special_state.no_magic_damage >= battle_config.gtb_sc_immunity)
  7881. return ((TBL_PC*)bl)->special_state.no_magic_damage;
  7882. return 0;
  7883. }
  7884. /**
  7885. * Get view data of an object
  7886. * @param bl: Object whose view data to get [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7887. * @return view data structure bl->vd
  7888. */
  7889. struct view_data* status_get_viewdata(struct block_list *bl)
  7890. {
  7891. nullpo_retr(nullptr, bl);
  7892. switch (bl->type) {
  7893. case BL_PC: return &((TBL_PC*)bl)->vd;
  7894. case BL_MOB: return ((TBL_MOB*)bl)->vd;
  7895. case BL_PET: return &((TBL_PET*)bl)->vd;
  7896. case BL_NPC: return &((TBL_NPC*)bl)->vd;
  7897. case BL_HOM: return ((TBL_HOM*)bl)->vd;
  7898. case BL_MER: return ((TBL_MER*)bl)->vd;
  7899. case BL_ELEM: return ((TBL_ELEM*)bl)->vd;
  7900. }
  7901. return nullptr;
  7902. }
  7903. /**
  7904. * Set view data of an object
  7905. * This function deals with class, mount, and item views
  7906. * SC views are set in clif_getareachar_unit()
  7907. * @param bl: Object whose view data to set [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7908. * @param class_: class of the object
  7909. */
  7910. void status_set_viewdata(struct block_list *bl, int32 class_)
  7911. {
  7912. struct view_data* vd;
  7913. nullpo_retv(bl);
  7914. if (mobdb_checkid(class_) || mob_is_clone(class_))
  7915. vd = mob_get_viewdata(class_);
  7916. else if (npcdb_checkid(class_))
  7917. vd = npc_get_viewdata(class_);
  7918. else if (homdb_checkid(class_))
  7919. vd = hom_get_viewdata(class_);
  7920. else if (mercenary_db.exists(class_))
  7921. vd = mercenary_get_viewdata(class_);
  7922. else if (elemental_db.exists(class_))
  7923. vd = elemental_get_viewdata(class_);
  7924. else
  7925. vd = nullptr;
  7926. switch (bl->type) {
  7927. case BL_PC:
  7928. {
  7929. TBL_PC* sd = (TBL_PC*)bl;
  7930. if (pcdb_checkid(class_)) {
  7931. if (sd->sc.option&OPTION_RIDING) {
  7932. switch (class_) { // Adapt class to a Mounted one.
  7933. case JOB_KNIGHT:
  7934. class_ = JOB_KNIGHT2;
  7935. break;
  7936. case JOB_CRUSADER:
  7937. class_ = JOB_CRUSADER2;
  7938. break;
  7939. case JOB_LORD_KNIGHT:
  7940. class_ = JOB_LORD_KNIGHT2;
  7941. break;
  7942. case JOB_PALADIN:
  7943. class_ = JOB_PALADIN2;
  7944. break;
  7945. case JOB_BABY_KNIGHT:
  7946. class_ = JOB_BABY_KNIGHT2;
  7947. break;
  7948. case JOB_BABY_CRUSADER:
  7949. class_ = JOB_BABY_CRUSADER2;
  7950. break;
  7951. }
  7952. }
  7953. sd->vd.class_ = class_;
  7954. clif_get_weapon_view(sd, &sd->vd.weapon, &sd->vd.shield);
  7955. sd->vd.head_top = sd->status.head_top;
  7956. sd->vd.head_mid = sd->status.head_mid;
  7957. sd->vd.head_bottom = sd->status.head_bottom;
  7958. sd->vd.hair_style = cap_value(sd->status.hair, MIN_HAIR_STYLE, MAX_HAIR_STYLE);
  7959. sd->vd.hair_color = cap_value(sd->status.hair_color, MIN_HAIR_COLOR, MAX_HAIR_COLOR);
  7960. sd->vd.cloth_color = cap_value(sd->status.clothes_color, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
  7961. sd->vd.body_style = cap_value(sd->status.body, MIN_BODY_STYLE, MAX_BODY_STYLE);
  7962. sd->vd.sex = sd->status.sex;
  7963. if (sd->vd.cloth_color) {
  7964. if(sd->sc.option&OPTION_WEDDING && battle_config.wedding_ignorepalette)
  7965. sd->vd.cloth_color = 0;
  7966. if(sd->sc.option&OPTION_XMAS && battle_config.xmas_ignorepalette)
  7967. sd->vd.cloth_color = 0;
  7968. if(sd->sc.option&(OPTION_SUMMER|OPTION_SUMMER2) && battle_config.summer_ignorepalette)
  7969. sd->vd.cloth_color = 0;
  7970. if(sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette)
  7971. sd->vd.cloth_color = 0;
  7972. if(sd->sc.option&OPTION_OKTOBERFEST && battle_config.oktoberfest_ignorepalette)
  7973. sd->vd.cloth_color = 0;
  7974. }
  7975. if ( sd->vd.body_style && sd->sc.option&OPTION_COSTUME)
  7976. sd->vd.body_style = 0;
  7977. } else if (vd)
  7978. memcpy(&sd->vd, vd, sizeof(struct view_data));
  7979. else
  7980. ShowError("status_set_viewdata (PC): No view data for class %d\n", class_);
  7981. }
  7982. break;
  7983. case BL_MOB:
  7984. {
  7985. TBL_MOB* md = (TBL_MOB*)bl;
  7986. if (vd){
  7987. mob_free_dynamic_viewdata( md );
  7988. md->vd = vd;
  7989. }else if( pcdb_checkid( class_ ) ){
  7990. mob_set_dynamic_viewdata( md );
  7991. md->vd->class_ = class_;
  7992. md->vd->hair_style = cap_value(md->vd->hair_style, MIN_HAIR_STYLE, MAX_HAIR_STYLE);
  7993. md->vd->hair_color = cap_value(md->vd->hair_color, MIN_HAIR_COLOR, MAX_HAIR_COLOR);
  7994. }else
  7995. ShowError("status_set_viewdata (MOB): No view data for class %d\n", class_);
  7996. }
  7997. break;
  7998. case BL_PET:
  7999. {
  8000. TBL_PET* pd = (TBL_PET*)bl;
  8001. if (vd) {
  8002. memcpy(&pd->vd, vd, sizeof(struct view_data));
  8003. if (!pcdb_checkid(vd->class_)) {
  8004. pd->vd.hair_style = battle_config.pet_hair_style;
  8005. if(pd->pet.equip) {
  8006. pd->vd.head_bottom = itemdb_viewid(pd->pet.equip);
  8007. if (!pd->vd.head_bottom)
  8008. pd->vd.head_bottom = pd->pet.equip;
  8009. }
  8010. }
  8011. } else
  8012. ShowError("status_set_viewdata (PET): No view data for class %d\n", class_);
  8013. }
  8014. break;
  8015. case BL_NPC:
  8016. {
  8017. TBL_NPC* nd = (TBL_NPC*)bl;
  8018. if (vd)
  8019. memcpy(&nd->vd, vd, sizeof(struct view_data));
  8020. else if (pcdb_checkid(class_)) {
  8021. memset(&nd->vd, 0, sizeof(struct view_data));
  8022. nd->vd.class_ = class_;
  8023. nd->vd.hair_style = cap_value(nd->vd.hair_style, MIN_HAIR_STYLE, MAX_HAIR_STYLE);
  8024. } else {
  8025. ShowError("status_set_viewdata (NPC): Invalid view data %d\n", class_);
  8026. if (bl->m >= 0)
  8027. ShowDebug("Source (NPC): %s at %s (%d,%d)\n", nd->name, map_mapid2mapname(bl->m), bl->x, bl->y);
  8028. else
  8029. ShowDebug("Source (NPC): %s (invisible/not on a map)\n", nd->name);
  8030. ShowDebug( "Source (NPC): %s is located in: %s\n", nd->name, nd->path );
  8031. }
  8032. break;
  8033. }
  8034. break;
  8035. case BL_HOM:
  8036. {
  8037. struct homun_data *hd = (struct homun_data*)bl;
  8038. if (vd)
  8039. hd->vd = vd;
  8040. else
  8041. ShowError("status_set_viewdata (HOMUNCULUS): No view data for class %d\n", class_);
  8042. }
  8043. break;
  8044. case BL_MER:
  8045. {
  8046. s_mercenary_data *md = (s_mercenary_data*)bl;
  8047. if (vd)
  8048. md->vd = vd;
  8049. else
  8050. ShowError("status_set_viewdata (MERCENARY): No view data for class %d\n", class_);
  8051. }
  8052. break;
  8053. case BL_ELEM:
  8054. {
  8055. s_elemental_data *ed = (s_elemental_data*)bl;
  8056. if (vd)
  8057. ed->vd = vd;
  8058. else
  8059. ShowError("status_set_viewdata (ELEMENTAL): No view data for class %d\n", class_);
  8060. }
  8061. break;
  8062. }
  8063. }
  8064. /**
  8065. * Get status change data of an object
  8066. * @param bl: Object whose sc data to get [PC|MOB|HOM|MER|ELEM|NPC]
  8067. * @return status change data structure bl->sc
  8068. */
  8069. status_change *status_get_sc(struct block_list *bl)
  8070. {
  8071. if( bl )
  8072. switch (bl->type) {
  8073. case BL_PC: return &((TBL_PC*)bl)->sc;
  8074. case BL_MOB: return &((TBL_MOB*)bl)->sc;
  8075. case BL_NPC: return &((TBL_NPC*)bl)->sc;
  8076. case BL_HOM: return &((TBL_HOM*)bl)->sc;
  8077. case BL_MER: return &((TBL_MER*)bl)->sc;
  8078. case BL_ELEM: return &((TBL_ELEM*)bl)->sc;
  8079. }
  8080. return nullptr;
  8081. }
  8082. /**
  8083. * Initiate (memset) the status change data of an object
  8084. * @param bl: Object whose sc data to memset [PC|MOB|HOM|MER|ELEM|NPC]
  8085. */
  8086. void status_change_init(struct block_list *bl)
  8087. {
  8088. status_change *sc = status_get_sc(bl);
  8089. nullpo_retv(sc);
  8090. new (sc) status_change();
  8091. }
  8092. /*========================================== [Playtester]
  8093. * Returns the interval for status changes that iterate multiple times
  8094. * through the timer (e.g. those that deal damage in regular intervals)
  8095. * @param type: Status change (SC_*)
  8096. *------------------------------------------*/
  8097. static int32 status_get_sc_interval(enum sc_type type)
  8098. {
  8099. switch (type) {
  8100. case SC_POISON:
  8101. case SC_LEECHESEND:
  8102. case SC_DPOISON:
  8103. case SC_DEATHHURT:
  8104. case SC_GRADUAL_GRAVITY:
  8105. case SC_KILLING_AURA:
  8106. case SC_BOSSMAPINFO:
  8107. return 1000;
  8108. case SC_BURNING:
  8109. case SC_PYREXIA:
  8110. return 3000;
  8111. case SC_MAGICMUSHROOM:
  8112. return 4000;
  8113. case SC_STONE:
  8114. return 5000;
  8115. case SC_BLEEDING:
  8116. case SC_TOXIN:
  8117. return 10000;
  8118. case SC_HELLS_PLANT:
  8119. return 333;
  8120. case SC_SHIELDSPELL_HP:
  8121. return 3000;
  8122. case SC_SHIELDSPELL_SP:
  8123. return 5000;
  8124. case SC_STAR_BURST:
  8125. return 300;
  8126. default:
  8127. break;
  8128. }
  8129. return 0;
  8130. }
  8131. /**
  8132. * Applies SC defense to a given status change
  8133. * This function also determines whether or not the status change will be applied
  8134. * @param src: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
  8135. * @param bl: Target of the status change
  8136. * @param type: Status change (SC_*)
  8137. * @param rate: Initial percentage rate of affecting bl (0~10000)
  8138. * @param tick: Initial duration that the status change affects bl
  8139. * @param flag: Value which determines what parts to calculate. See e_status_change_start_flags
  8140. * @return adjusted duration based on flag values
  8141. */
  8142. t_tick status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_type type, int32 rate, t_tick tick, unsigned char flag)
  8143. {
  8144. /// Resistance rate: 10000 = 100%
  8145. /// Example: 50% (5000) -> sc_def = 5000 -> 25%;
  8146. /// 5000ms -> tick_def = 5000 -> 2500ms
  8147. int32 sc_def = 0, tick_def = -1; // -1 = use sc_def
  8148. /// Fixed resistance value (after rate calculation)
  8149. /// Example: 25% (2500) -> sc_def2 = 2000 -> 5%;
  8150. /// 2500ms -> tick_def2=2000 -> 500ms
  8151. int32 sc_def2 = 0, tick_def2 = 0;
  8152. status_change *sc;
  8153. map_session_data *sd;
  8154. nullpo_ret(bl);
  8155. if (src == nullptr)
  8156. return tick?tick:1; // This should not happen in current implementation, but leave it anyway
  8157. // Skills (magic type) that are blocked by Golden Thief Bug card or Wand of Hermod
  8158. if (status_isimmune(bl)) {
  8159. std::shared_ptr<s_skill_db> skill = skill_db.find(battle_getcurrentskill(src));
  8160. if (skill == nullptr) // Check for ground-type skills using the status when a player moves through units
  8161. skill = skill_db.find(status_db.getSkill(type));
  8162. if (skill != nullptr && skill->skill_type == BF_MAGIC && // Basic magic skill
  8163. !skill->inf2[INF2_IGNOREGTB] && // Specific skill to bypass
  8164. ((skill->inf == INF_ATTACK_SKILL || skill->inf == INF_GROUND_SKILL || skill->inf == INF_SUPPORT_SKILL) || // Target skills should get blocked even when cast on self
  8165. (skill->inf == INF_SELF_SKILL && src != bl))) // Self skills should get blocked on all targets except self
  8166. return 0;
  8167. }
  8168. sd = BL_CAST(BL_PC,bl);
  8169. status_data* status = status_get_status_data(*bl);
  8170. status_data* status_src = status_get_status_data(*src);
  8171. sc = status_get_sc(bl);
  8172. if( sc != nullptr && sc->empty() )
  8173. sc = nullptr;
  8174. #ifdef RENEWAL
  8175. uint16 levelAdv = (static_cast<uint16>(pow(max(0, status_get_lv(src) - status_get_lv(bl)), 2)) / 5) * 100;
  8176. #endif
  8177. switch (type) {
  8178. case SC_POISON:
  8179. case SC_DPOISON:
  8180. #ifndef RENEWAL
  8181. sc_def = status->vit*100;
  8182. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  8183. if (sd) {
  8184. // For players: 60000 - 450*vit - 100*luk
  8185. tick_def = status->vit*75;
  8186. tick_def2 = status->luk*100;
  8187. } else {
  8188. // For monsters: 30000 - 200*vit
  8189. tick /= 2;
  8190. tick_def = (status->vit*200)/3;
  8191. }
  8192. #else
  8193. sc_def = status->vit * 100 - levelAdv;
  8194. tick_def2 = -2000;
  8195. #endif
  8196. break;
  8197. case SC_STUN:
  8198. #ifndef RENEWAL
  8199. sc_def = status->vit*100;
  8200. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  8201. tick_def2 = status->luk*10;
  8202. #else
  8203. sc_def = status->vit * 100 - levelAdv;
  8204. tick_def2 = -500;
  8205. #endif
  8206. break;
  8207. case SC_SILENCE:
  8208. #ifndef RENEWAL
  8209. sc_def = status->vit*100;
  8210. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  8211. tick_def2 = status->luk*10;
  8212. #else
  8213. sc_def = status->int_ * 100 - levelAdv;
  8214. tick_def2 = -2000;
  8215. #endif
  8216. break;
  8217. case SC_BLEEDING:
  8218. #ifndef RENEWAL
  8219. sc_def = status->vit*100;
  8220. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  8221. tick_def2 = status->luk*10;
  8222. #else
  8223. sc_def = status->agi * 100 - levelAdv;
  8224. tick_def2 = -12000;
  8225. #endif
  8226. break;
  8227. case SC_SLEEP:
  8228. #ifndef RENEWAL
  8229. sc_def = status->int_*100;
  8230. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  8231. tick_def2 = status->luk*10;
  8232. #else
  8233. sc_def = status->agi * 100 - levelAdv;
  8234. tick_def2 = -2000;
  8235. #endif
  8236. break;
  8237. case SC_STONEWAIT:
  8238. #ifndef RENEWAL
  8239. sc_def = status->mdef*100;
  8240. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  8241. tick_def = 0; // No duration reduction
  8242. #else
  8243. sc_def = status->mdef * 100 - levelAdv;
  8244. tick_def2 = -3000;
  8245. #endif
  8246. break;
  8247. case SC_FREEZE:
  8248. #ifndef RENEWAL
  8249. sc_def = status->mdef*100;
  8250. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  8251. tick_def2 = status_src->luk*-10; // Caster can increase final duration with luk
  8252. #else
  8253. sc_def = status->mdef * 100 - levelAdv;
  8254. tick_def2 = -3000;
  8255. #endif
  8256. break;
  8257. case SC_CURSE:
  8258. // Special property: immunity when luk is zero
  8259. if (status->luk == 0)
  8260. return 0;
  8261. #ifndef RENEWAL
  8262. sc_def = status->luk*100;
  8263. sc_def2 = status->luk*10 - status_get_lv(src)*10; // Curse only has a level penalty and no resistance
  8264. tick_def = status->vit*100;
  8265. tick_def2 = status->luk*10;
  8266. #else
  8267. sc_def = status->luk * 100 - levelAdv;
  8268. tick_def2 = -2000;
  8269. #endif
  8270. break;
  8271. case SC_BLIND:
  8272. #ifndef RENEWAL
  8273. sc_def = (status->vit + status->int_)*50;
  8274. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  8275. tick_def2 = status->luk*10;
  8276. #else
  8277. sc_def = status->int_ * 100 - levelAdv;
  8278. tick_def2 = -2000;
  8279. #endif
  8280. break;
  8281. case SC_CONFUSION:
  8282. #ifndef RENEWAL
  8283. sc_def = (status->str + status->int_)*50;
  8284. sc_def2 = status_get_lv(src)*10 - status_get_lv(bl)*10 - status->luk*10; // Reversed sc_def2
  8285. tick_def2 = status->luk*10;
  8286. #else
  8287. sc_def = status->luk * 100 - levelAdv;
  8288. tick_def2 = -2000;
  8289. #endif
  8290. break;
  8291. case SC_DECREASEAGI:
  8292. if (sd)
  8293. tick /= 2; // Half duration for players.
  8294. sc_def2 = status->mdef*100;
  8295. break;
  8296. case SC_JOINTBEAT:
  8297. tick_def2 = 1000 * ((status->luk / 2 + status->agi / 5) / 2); // (50 * LUK / 100 + 20 * AGI / 100) / 2
  8298. break;
  8299. case SC_DEEPSLEEP:
  8300. tick_def2 = status_get_base_status(bl)->int_ * 25 + status_get_lv(bl) * 50;
  8301. break;
  8302. case SC_NETHERWORLD:
  8303. // Resistance: {(Target's Base Level / 50) + (Target's Job Level / 10)} seconds
  8304. tick_def2 = status_get_lv(bl) * 20 + (sd ? sd->status.job_level : 1) * 100;
  8305. break;
  8306. case SC_MARSHOFABYSS:
  8307. // 5 second (Fixed) + 25 second - {( INT + LUK ) / 20 second }
  8308. tick_def2 = (status->int_ + status->luk)*50;
  8309. break;
  8310. case SC_STASIS:
  8311. // 10 second (fixed) + { Stasis Skill level * 10 - (Target's VIT + DEX) / 20 }
  8312. tick_def2 = (status->vit + status->dex) * 50;
  8313. break;
  8314. case SC_WHITEIMPRISON:
  8315. if( src == bl ) // 100% on caster
  8316. break;
  8317. sc_def = status->str * 20 + status_get_lv(bl) * 20 + status->luk * 10;
  8318. tick_def2 = -2000;
  8319. break;
  8320. case SC_FEAR:
  8321. sc_def = status->int_ * 20 + status_get_lv(bl) * 20 + status->luk * 10;
  8322. tick_def2 = -4000; // 2 seconds is applied twice on Aegis
  8323. break;
  8324. case SC_BURNING:
  8325. sc_def = status->agi * 20 + status_get_lv(bl) * 20 + status->luk * 10;
  8326. tick_def2 = -2000;
  8327. break;
  8328. case SC_FREEZING:
  8329. tick_def2 = (status->vit + status->dex) * 50;
  8330. break;
  8331. case SC_OBLIVIONCURSE: // 100% - (100 - 0.8 x INT)
  8332. sc_def = status->int_ * 80;
  8333. sc_def = max(sc_def, 500); // minimum of 5% resist
  8334. tick_def = 0;
  8335. tick_def2 = (status->vit + status->luk) * 500;
  8336. break;
  8337. case SC_TOXIN:
  8338. case SC_PARALYSE:
  8339. case SC_VENOMBLEED:
  8340. case SC_MAGICMUSHROOM:
  8341. case SC_DEATHHURT:
  8342. case SC_PYREXIA:
  8343. case SC_LEECHESEND:
  8344. tick_def2 = (status->vit + status->luk) * 500;
  8345. break;
  8346. case SC_BITE: // {(Base Success chance) - (Target's AGI / 4)}
  8347. sc_def2 = status->agi*25;
  8348. break;
  8349. case SC_ELECTRICSHOCKER:
  8350. tick_def2 = (status->vit + status->agi) * 70;
  8351. break;
  8352. case SC_CRYSTALIZE:
  8353. tick_def2 = status_get_base_status(bl)->vit * 100;
  8354. break;
  8355. case SC_VACUUM_EXTREME:
  8356. tick_def2 = (sd ? sd->status.str : status_get_base_status(bl)->str) * 50;
  8357. break;
  8358. case SC_KYOUGAKU:
  8359. tick_def2 = 30*status->int_;
  8360. break;
  8361. case SC_PARALYSIS:
  8362. tick_def2 = (status->vit + status->luk)*50;
  8363. break;
  8364. case SC_VOICEOFSIREN:
  8365. // Resistance: {(Target's Base Level / 10) + (Target's Job Level / 5)} seconds
  8366. tick_def2 = status_get_lv(bl) * 100 + (sd ? sd->status.job_level : 1) * 200;
  8367. break;
  8368. case SC_B_TRAP:
  8369. tick_def = (sd ? sd->status.str : status_get_base_status(bl)->str) * 50; //! TODO: Figure out reduction formula
  8370. break;
  8371. case SC_NORECOVER_STATE:
  8372. tick_def2 = status->luk * 100;
  8373. break;
  8374. default:
  8375. // Effect that cannot be reduced? Likely a buff.
  8376. if (!(rnd()%10000 < rate))
  8377. return 0;
  8378. return tick ? tick : 1;
  8379. }
  8380. if (sd) {
  8381. if (battle_config.pc_sc_def_rate != 100) {
  8382. sc_def = sc_def*battle_config.pc_sc_def_rate/100;
  8383. sc_def2 = sc_def2*battle_config.pc_sc_def_rate/100;
  8384. }
  8385. #ifndef RENEWAL
  8386. sc_def = min(sc_def, battle_config.pc_max_sc_def*100);
  8387. sc_def2 = min(sc_def2, battle_config.pc_max_sc_def*100);
  8388. #else
  8389. sc_def = cap_value(sc_def, 0, battle_config.pc_max_sc_def*100);
  8390. sc_def2 = cap_value(sc_def2, 0, battle_config.pc_max_sc_def*100);
  8391. #endif
  8392. if (battle_config.pc_sc_def_rate != 100) {
  8393. tick_def = tick_def*battle_config.pc_sc_def_rate/100;
  8394. tick_def2 = tick_def2*battle_config.pc_sc_def_rate/100;
  8395. }
  8396. } else {
  8397. if (battle_config.mob_sc_def_rate != 100) {
  8398. sc_def = sc_def*battle_config.mob_sc_def_rate/100;
  8399. sc_def2 = sc_def2*battle_config.mob_sc_def_rate/100;
  8400. }
  8401. #ifndef RENEWAL
  8402. sc_def = min(sc_def, battle_config.mob_max_sc_def*100);
  8403. sc_def2 = min(sc_def2, battle_config.mob_max_sc_def*100);
  8404. #else
  8405. sc_def = cap_value(sc_def, 0, battle_config.mob_max_sc_def*100);
  8406. sc_def2 = cap_value(sc_def2, 0, battle_config.mob_max_sc_def*100);
  8407. #endif
  8408. if (battle_config.mob_sc_def_rate != 100) {
  8409. tick_def = tick_def*battle_config.mob_sc_def_rate/100;
  8410. tick_def2 = tick_def2*battle_config.mob_sc_def_rate/100;
  8411. }
  8412. }
  8413. if (sc) {
  8414. if (sc->getSCE(SC_SCRESIST))
  8415. sc_def += sc->getSCE(SC_SCRESIST)->val1*100; // Status resist
  8416. #ifdef RENEWAL
  8417. else if (sc->getSCE(SC_SIEGFRIED) && (type == SC_BLIND || type == SC_STONE || type == SC_FREEZE || type == SC_STUN || type == SC_CURSE || type == SC_SLEEP || type == SC_SILENCE))
  8418. sc_def += sc->getSCE(SC_SIEGFRIED)->val3 * 100; // Status resistance.
  8419. #else
  8420. else if (sc->getSCE(SC_SIEGFRIED))
  8421. sc_def += sc->getSCE(SC_SIEGFRIED)->val3*100; // Status resistance.
  8422. #endif
  8423. else if (sc->getSCE(SC_LEECHESEND) && sc->getSCE(SC_LEECHESEND)->val3 == 0) {
  8424. switch (type) {
  8425. case SC_BLIND:
  8426. case SC_STUN:
  8427. return 0; // Immune
  8428. }
  8429. } else if (sc->getSCE(SC_OBLIVIONCURSE) && sc->getSCE(SC_OBLIVIONCURSE)->val3 == 0) {
  8430. switch (type) {
  8431. case SC_SILENCE:
  8432. case SC_CURSE:
  8433. return 0; // Immune
  8434. }
  8435. }
  8436. }
  8437. // When tick def not set, reduction is the same for both.
  8438. if(tick_def == -1)
  8439. tick_def = sc_def;
  8440. // Natural resistance
  8441. if (!(flag&SCSTART_NORATEDEF)) {
  8442. rate -= rate*sc_def/10000;
  8443. rate -= sc_def2;
  8444. // Item resistance (only applies to rate%)
  8445. if (sd) {
  8446. for (const auto &it : sd->reseff) {
  8447. if (it.id == type)
  8448. rate -= rate * it.val / 10000;
  8449. }
  8450. }
  8451. // Aegis accuracy
  8452. if(rate > 0 && rate%10 != 0) rate += (10 - rate%10);
  8453. }
  8454. std::shared_ptr<s_status_change_db> scdb = status_db.find(type);
  8455. // Cap minimum rate
  8456. rate = max(rate, scdb->min_rate);
  8457. if (rate < 10000 && (rate <= 0 || !(rnd()%10000 < rate)))
  8458. return 0;
  8459. // Duration cannot be reduced
  8460. if (flag&SCSTART_NOTICKDEF)
  8461. return i64max(tick, scdb->min_duration);
  8462. tick -= tick*tick_def/10000;
  8463. #ifdef RENEWAL
  8464. // Renewal applies item resistance also to duration
  8465. if (sd) {
  8466. for (const auto &it : sd->reseff) {
  8467. if (it.id == type)
  8468. tick -= tick * it.val / 10000;
  8469. }
  8470. }
  8471. #endif
  8472. tick -= tick_def2;
  8473. return i64max(tick, scdb->min_duration);
  8474. }
  8475. /**
  8476. * Applies SC effect
  8477. * @param bl: Source to apply effect
  8478. * @param type: Status change (SC_*)
  8479. * @param dval1~3: Depends on type of status change
  8480. * Author: Ind
  8481. */
  8482. void status_display_add(struct block_list *bl, enum sc_type type, int32 dval1, int32 dval2, int32 dval3) {
  8483. struct eri *eri;
  8484. struct sc_display_entry **sc_display;
  8485. struct sc_display_entry ***sc_display_ptr;
  8486. struct sc_display_entry *entry;
  8487. int32 i;
  8488. unsigned char sc_display_count;
  8489. unsigned char *sc_display_count_ptr;
  8490. nullpo_retv(bl);
  8491. switch( bl->type ){
  8492. case BL_PC: {
  8493. map_session_data* sd = (map_session_data*)bl;
  8494. sc_display_ptr = &sd->sc_display;
  8495. sc_display_count_ptr = &sd->sc_display_count;
  8496. eri = pc_sc_display_ers;
  8497. }
  8498. break;
  8499. case BL_NPC: {
  8500. struct npc_data* nd = (struct npc_data*)bl;
  8501. sc_display_ptr = &nd->sc_display;
  8502. sc_display_count_ptr = &nd->sc_display_count;
  8503. eri = npc_sc_display_ers;
  8504. }
  8505. break;
  8506. default:
  8507. return;
  8508. }
  8509. sc_display = *sc_display_ptr;
  8510. sc_display_count = *sc_display_count_ptr;
  8511. ARR_FIND(0, sc_display_count, i, sc_display[i]->type == type);
  8512. if( i != sc_display_count ) {
  8513. sc_display[i]->val1 = dval1;
  8514. sc_display[i]->val2 = dval2;
  8515. sc_display[i]->val3 = dval3;
  8516. return;
  8517. }
  8518. entry = ers_alloc(eri, struct sc_display_entry);
  8519. entry->type = type;
  8520. entry->val1 = dval1;
  8521. entry->val2 = dval2;
  8522. entry->val3 = dval3;
  8523. RECREATE(sc_display, struct sc_display_entry *, ++sc_display_count);
  8524. sc_display[sc_display_count - 1] = entry;
  8525. *sc_display_ptr = sc_display;
  8526. *sc_display_count_ptr = sc_display_count;
  8527. }
  8528. /**
  8529. * Removes SC effect
  8530. * @param bl: Source to remove effect
  8531. * @param type: Status change (SC_*)
  8532. * Author: Ind
  8533. */
  8534. void status_display_remove(struct block_list *bl, enum sc_type type) {
  8535. struct eri *eri;
  8536. struct sc_display_entry **sc_display;
  8537. struct sc_display_entry ***sc_display_ptr;
  8538. int32 i;
  8539. unsigned char sc_display_count;
  8540. unsigned char *sc_display_count_ptr;
  8541. nullpo_retv(bl);
  8542. switch( bl->type ){
  8543. case BL_PC: {
  8544. map_session_data* sd = (map_session_data*)bl;
  8545. sc_display_ptr = &sd->sc_display;
  8546. sc_display_count_ptr = &sd->sc_display_count;
  8547. eri = pc_sc_display_ers;
  8548. }
  8549. break;
  8550. case BL_NPC: {
  8551. struct npc_data* nd = (struct npc_data*)bl;
  8552. sc_display_ptr = &nd->sc_display;
  8553. sc_display_count_ptr = &nd->sc_display_count;
  8554. eri = npc_sc_display_ers;
  8555. }
  8556. break;
  8557. default:
  8558. return;
  8559. }
  8560. sc_display = *sc_display_ptr;
  8561. sc_display_count = *sc_display_count_ptr;
  8562. ARR_FIND(0, sc_display_count, i, sc_display[i]->type == type);
  8563. if( i != sc_display_count ) {
  8564. int32 cursor;
  8565. ers_free(eri, sc_display[i]);
  8566. sc_display[i] = nullptr;
  8567. /* The all-mighty compact-o-matic */
  8568. for( i = 0, cursor = 0; i < sc_display_count; i++ ) {
  8569. if( sc_display[i] == nullptr )
  8570. continue;
  8571. if( i != cursor )
  8572. sc_display[cursor] = sc_display[i];
  8573. cursor++;
  8574. }
  8575. if( !(sc_display_count = cursor) ) {
  8576. aFree(sc_display);
  8577. sc_display = nullptr;
  8578. }
  8579. *sc_display_ptr = sc_display;
  8580. *sc_display_count_ptr = sc_display_count;
  8581. }
  8582. }
  8583. /**
  8584. * Applies SC defense to a given status change
  8585. * This function also determines whether or not the status change will be applied
  8586. * @param src: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
  8587. * @param bl: Target of the status change (See: enum sc_type)
  8588. * @param type: Status change (SC_*)
  8589. * @param rate: Initial percentage rate of affecting bl (0~10000)
  8590. * @param val1~4: Depends on type of status change
  8591. * @param duration: Initial duration that the status change affects bl
  8592. * @param flag: Value which determines what parts to calculate. See e_status_change_start_flags
  8593. * @param delay: Delay in milliseconds before the SC is applied
  8594. * @return adjusted duration based on flag values
  8595. */
  8596. int32 status_change_start(struct block_list* src, struct block_list* bl,enum sc_type type,int32 rate,int32 val1,int32 val2,int32 val3,int32 val4,t_tick duration,unsigned char flag, int32 delay) {
  8597. map_session_data *sd = nullptr;
  8598. status_change* sc;
  8599. struct status_change_entry* sce;
  8600. struct view_data *vd;
  8601. int32 undead_flag, tick_time = 0;
  8602. bool sc_isnew = true;
  8603. std::shared_ptr<s_status_change_db> scdb = status_db.find(type);
  8604. nullpo_ret(bl);
  8605. sc = status_get_sc(bl);
  8606. if( !scdb ) {
  8607. ShowError("status_change_start: Invalid status change (%d)!\n", type);
  8608. return 0;
  8609. }
  8610. if( !sc )
  8611. return 0; // Unable to receive status changes
  8612. // Scripted status changes only work for players for the time being
  8613. if( scdb->script != nullptr && bl->type != BL_PC ){
  8614. ShowError( "status_change_start: Failed to start the scripted status change %d on a non player.\n", type );
  8615. return 0;
  8616. }
  8617. if( bl->type != BL_NPC && status_isdead(*bl) && ( type != SC_NOCHAT && type != SC_JAILED ) ) // SC_NOCHAT and SC_JAILED should work even on dead characters
  8618. return 0;
  8619. if (status_change_isDisabledOnMap(type, map_getmapdata(bl->m)))
  8620. return 0;
  8621. if (sc->getSCE(SC_GRAVITYCONTROL))
  8622. return 0; // !TODO: Confirm what statuses/conditions (if not all) are blocked.
  8623. // Uncomment to prevent status adding hp to gvg mob (like bloodylust=hp*3 etc...
  8624. // if (bl->type == BL_MOB)
  8625. // if (util::vector_exists(status_get_race2(bl), RC2_GVG) && status_sc2scb_flag(type)&SCB_MAXHP) return 0;
  8626. // Fail if Madogear is active
  8627. if (sc->option&OPTION_MADOGEAR && flag&SCSTART_NOAVOID && scdb->flag[SCF_FAILEDMADO])
  8628. return 0;
  8629. status_data* status = status_get_status_data(*bl);
  8630. // Check for Boss resistances
  8631. if(status->mode&MD_STATUSIMMUNE && !(flag&SCSTART_NOAVOID) && scdb->flag[SCF_BOSSRESIST])
  8632. return 0;
  8633. // Check for MVP resistance
  8634. if(status->mode&MD_MVP && !(flag&SCSTART_NOAVOID) && scdb->flag[SCF_MVPRESIST])
  8635. return 0;
  8636. // End the SCs from the list and immediately return
  8637. // If anything in this list is removed, the rest is ignored.
  8638. if (!scdb->endreturn.empty()) {
  8639. bool isRemoved = false;
  8640. for (const auto &it : scdb->endreturn) {
  8641. sc_type rem_sc = it;
  8642. if (sc->getSCE(rem_sc)) {
  8643. status_change_end(bl, rem_sc);
  8644. isRemoved = true;
  8645. }
  8646. }
  8647. if (isRemoved) // Something was removed, don't give the status
  8648. return 1; // Return 1 so that sc_start can be checked as success
  8649. }
  8650. // Check failing SCs from list
  8651. if (!scdb->fail.empty()) {
  8652. for (const auto &it : scdb->fail) {
  8653. // Don't let OPT1 that have RemoveOnDamaged start a new effect in the same attack.
  8654. if (sc->getSCE(it) || sc->lastEffect == it)
  8655. return 0;
  8656. }
  8657. }
  8658. // Adjust tick according to status resistances
  8659. if( !(flag&(SCSTART_NOAVOID|SCSTART_LOADED)) ) {
  8660. duration = status_get_sc_def(src, bl, type, rate, duration, flag);
  8661. if( !duration )
  8662. return 0;
  8663. }
  8664. int32 tick = (int32)duration;
  8665. sd = BL_CAST(BL_PC, bl);
  8666. vd = status_get_viewdata(bl);
  8667. undead_flag = battle_check_undead(status->race,status->def_ele);
  8668. // Check for immunities / sc fails
  8669. switch (type) {
  8670. case SC_VACUUM_EXTREME:
  8671. if (sc && sc->getSCE(SC_VACUUM_EXTREME_POSTDELAY) && sc->getSCE(SC_VACUUM_EXTREME_POSTDELAY)->val2 == val2) // Ignore post delay from other vacuum (this will make stack effect enabled)
  8672. return 0;
  8673. break;
  8674. case SC_STONE:
  8675. case SC_STONEWAIT:
  8676. case SC_FREEZE:
  8677. // Undead are immune to Freeze/Stone
  8678. if (undead_flag && !(flag&SCSTART_NOAVOID))
  8679. return 0;
  8680. break;
  8681. case SC_BURNING:
  8682. // Level 2 Fire Element is immune
  8683. if (status->def_ele == ELE_FIRE && status->ele_lv == 2)
  8684. return 0;
  8685. break;
  8686. case SC_ALL_RIDING:
  8687. if( !sd || sc->option&(OPTION_RIDING|OPTION_DRAGON|OPTION_WUG|OPTION_MADOGEAR) )
  8688. return 0;
  8689. break;
  8690. case SC_SIGNUMCRUCIS:
  8691. // Only affects demons and undead element (but not players)
  8692. if((!undead_flag && status->race!=RC_DEMON) || bl->type == BL_PC)
  8693. return 0;
  8694. break;
  8695. case SC_KYRIE:
  8696. case SC_TUNAPARTY:
  8697. if (bl->type == BL_MOB)
  8698. return 0;
  8699. break;
  8700. case SC_ADRENALINE:
  8701. if(sd && !pc_check_weapontype(sd,skill_get_weapontype(BS_ADRENALINE)))
  8702. return 0;
  8703. break;
  8704. case SC_ADRENALINE2:
  8705. if(sd && !pc_check_weapontype(sd,skill_get_weapontype(BS_ADRENALINE2)))
  8706. return 0;
  8707. break;
  8708. case SC_CLOAKING:
  8709. // Avoid cloaking with no wall and low skill level. [Skotlex]
  8710. // Due to the cloaking card, we have to check the wall versus to known
  8711. // skill level rather than the used one. [Skotlex]
  8712. // if (sd && val1 < 3 && skill_check_cloaking(bl,nullptr))
  8713. if( sd && pc_checkskill(sd, AS_CLOAKING) < 3 && !skill_check_cloaking(bl,nullptr) )
  8714. return 0;
  8715. break;
  8716. case SC_MODECHANGE: {
  8717. int32 mode;
  8718. struct status_data *bstatus = status_get_base_status(bl);
  8719. if (!bstatus) return 0;
  8720. if (sc->getSCE(type)) { // Pile up with previous values.
  8721. if (!val2) val2 = sc->getSCE(type)->val2;
  8722. val3 |= sc->getSCE(type)->val3;
  8723. val4 |= sc->getSCE(type)->val4;
  8724. }
  8725. mode = val2 ? ((val2&~MD_MASK) | val2) : bstatus->mode; // Base mode
  8726. if (val4) mode = static_cast<e_mode>(mode&~val4); // Del mode
  8727. if (val3) mode = static_cast<e_mode>(mode | val3); // Add mode
  8728. if (mode == bstatus->mode) { // No change.
  8729. if (sc->getSCE(type)) // Abort previous status
  8730. return status_change_end(bl, type);
  8731. return 0;
  8732. }
  8733. }
  8734. break;
  8735. // Strip skills, need to divest something or it fails.
  8736. case SC_STRIPWEAPON:
  8737. if (val2 == 1)
  8738. val2 = 0; // Brandish Spear/Bowling Bash effet. Do not take weapon off.
  8739. else if (sd && !(flag&SCSTART_LOADED)) { // Apply sc anyway if loading saved sc_data
  8740. int16 i;
  8741. uint8 successFlag = 0;
  8742. if(sd->bonus.unstripable_equip&EQP_WEAPON)
  8743. return 0;
  8744. i = sd->equip_index[EQI_HAND_L];
  8745. if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) {
  8746. successFlag|=1;
  8747. pc_unequipitem(sd,i,3); // Left-hand weapon
  8748. }
  8749. i = sd->equip_index[EQI_HAND_R];
  8750. if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) {
  8751. successFlag|=2;
  8752. pc_unequipitem(sd,i,3);
  8753. }
  8754. if (!successFlag) return 0;
  8755. }
  8756. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8757. break;
  8758. case SC_STRIPSHIELD:
  8759. if( val2 == 1 ) val2 = 0; // GX effect. Do not take shield off..
  8760. else
  8761. if (sd && !(flag&SCSTART_LOADED)) {
  8762. int16 i;
  8763. if(sd->bonus.unstripable_equip&EQP_SHIELD)
  8764. return 0;
  8765. i = sd->equip_index[EQI_HAND_L];
  8766. if ( i < 0 || !sd->inventory_data[i] || sd->inventory_data[i]->type != IT_ARMOR )
  8767. return 0;
  8768. pc_unequipitem(sd,i,3);
  8769. }
  8770. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8771. break;
  8772. case SC_STRIPARMOR:
  8773. if (sd && !(flag&SCSTART_LOADED)) {
  8774. int16 i;
  8775. if(sd->bonus.unstripable_equip&EQP_ARMOR)
  8776. return 0;
  8777. i = sd->equip_index[EQI_ARMOR];
  8778. if ( i < 0 || !sd->inventory_data[i] )
  8779. return 0;
  8780. pc_unequipitem(sd,i,3);
  8781. }
  8782. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8783. break;
  8784. case SC_STRIPHELM:
  8785. if (sd && !(flag&SCSTART_LOADED)) {
  8786. int16 i;
  8787. if(sd->bonus.unstripable_equip&EQP_HELM)
  8788. return 0;
  8789. i = sd->equip_index[EQI_HEAD_TOP];
  8790. if ( i < 0 || !sd->inventory_data[i] )
  8791. return 0;
  8792. pc_unequipitem(sd,i,3);
  8793. }
  8794. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8795. break;
  8796. case SC_SHADOW_STRIP:
  8797. if (sd && !(flag&SCSTART_LOADED)) {
  8798. if (sd->bonus.unstripable_equip&EQP_SHADOW_GEAR)
  8799. return 0;
  8800. bool successFlag = false;
  8801. for( int32 i = EQI_SHADOW_ARMOR; i <= EQI_SHADOW_ACC_L; i++ ){
  8802. int32 index = sd->equip_index[i];
  8803. if( index >= 0 && sd->inventory_data[index] != nullptr ){
  8804. pc_unequipitem( sd, index, 3 );
  8805. successFlag = true;
  8806. }
  8807. }
  8808. if (!successFlag)
  8809. return 0;
  8810. }
  8811. if (tick == 1)
  8812. return 1;
  8813. break;
  8814. case SC_MERC_FLEEUP:
  8815. case SC_MERC_ATKUP:
  8816. case SC_MERC_HPUP:
  8817. case SC_MERC_SPUP:
  8818. case SC_MERC_HITUP:
  8819. if( bl->type != BL_MER )
  8820. return 0; // Stats only for Mercenaries
  8821. break;
  8822. case SC_STRFOOD:
  8823. if (sc->getSCE(SC_FOOD_STR_CASH) && sc->getSCE(SC_FOOD_STR_CASH)->val1 > val1)
  8824. return 0;
  8825. break;
  8826. case SC_AGIFOOD:
  8827. if (sc->getSCE(SC_FOOD_AGI_CASH) && sc->getSCE(SC_FOOD_AGI_CASH)->val1 > val1)
  8828. return 0;
  8829. break;
  8830. case SC_VITFOOD:
  8831. if (sc->getSCE(SC_FOOD_VIT_CASH) && sc->getSCE(SC_FOOD_VIT_CASH)->val1 > val1)
  8832. return 0;
  8833. break;
  8834. case SC_INTFOOD:
  8835. if (sc->getSCE(SC_FOOD_INT_CASH) && sc->getSCE(SC_FOOD_INT_CASH)->val1 > val1)
  8836. return 0;
  8837. break;
  8838. case SC_DEXFOOD:
  8839. if (sc->getSCE(SC_FOOD_DEX_CASH) && sc->getSCE(SC_FOOD_DEX_CASH)->val1 > val1)
  8840. return 0;
  8841. break;
  8842. case SC_LUKFOOD:
  8843. if (sc->getSCE(SC_FOOD_LUK_CASH) && sc->getSCE(SC_FOOD_LUK_CASH)->val1 > val1)
  8844. return 0;
  8845. break;
  8846. case SC_FOOD_STR_CASH:
  8847. if (sc->getSCE(SC_STRFOOD) && sc->getSCE(SC_STRFOOD)->val1 > val1)
  8848. return 0;
  8849. break;
  8850. case SC_FOOD_AGI_CASH:
  8851. if (sc->getSCE(SC_AGIFOOD) && sc->getSCE(SC_AGIFOOD)->val1 > val1)
  8852. return 0;
  8853. break;
  8854. case SC_FOOD_VIT_CASH:
  8855. if (sc->getSCE(SC_VITFOOD) && sc->getSCE(SC_VITFOOD)->val1 > val1)
  8856. return 0;
  8857. break;
  8858. case SC_FOOD_INT_CASH:
  8859. if (sc->getSCE(SC_INTFOOD) && sc->getSCE(SC_INTFOOD)->val1 > val1)
  8860. return 0;
  8861. break;
  8862. case SC_FOOD_DEX_CASH:
  8863. if (sc->getSCE(SC_DEXFOOD) && sc->getSCE(SC_DEXFOOD)->val1 > val1)
  8864. return 0;
  8865. break;
  8866. case SC_FOOD_LUK_CASH:
  8867. if (sc->getSCE(SC_LUKFOOD) && sc->getSCE(SC_LUKFOOD)->val1 > val1)
  8868. return 0;
  8869. break;
  8870. case SC_CAMOUFLAGE:
  8871. if( sd && pc_checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill_check_camouflage(bl,nullptr) )
  8872. return 0;
  8873. break;
  8874. case SC__STRIPACCESSORY:
  8875. if( sd ) {
  8876. int16 i = -1;
  8877. if( !(sd->bonus.unstripable_equip&EQP_ACC_L) ) {
  8878. i = sd->equip_index[EQI_ACC_L];
  8879. if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR )
  8880. pc_unequipitem(sd,i,3); // Left-Accessory
  8881. }
  8882. if( !(sd->bonus.unstripable_equip&EQP_ACC_R) ) {
  8883. i = sd->equip_index[EQI_ACC_R];
  8884. if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR )
  8885. pc_unequipitem(sd,i,3); // Right-Accessory
  8886. }
  8887. if( i < 0 )
  8888. return 0;
  8889. }
  8890. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8891. break;
  8892. case SC_C_MARKER:
  8893. if (src == bl)
  8894. return 0;
  8895. else {
  8896. status_change *tsc = status_get_sc(bl);
  8897. // Failed if the target is already marked and the new marker that isn't same marker
  8898. if (tsc && tsc->getSCE(type) && tsc->getSCE(type)->val2 != src->id)
  8899. return 0;
  8900. }
  8901. break;
  8902. case SC_MADNESSCANCEL:
  8903. if (sc->getSCE(type)) { // Toggle the status but still consume requirements.
  8904. status_change_end(bl, type);
  8905. return 0;
  8906. }
  8907. break;
  8908. case SC_TOXIN:
  8909. case SC_PARALYSE:
  8910. case SC_VENOMBLEED:
  8911. case SC_MAGICMUSHROOM:
  8912. case SC_DEATHHURT:
  8913. case SC_PYREXIA:
  8914. case SC_OBLIVIONCURSE:
  8915. case SC_LEECHESEND:
  8916. if (val3 == 0) // Don't display icon on self
  8917. flag |= SCSTART_NOICON;
  8918. for (int32 i = SC_TOXIN; i <= SC_LEECHESEND; i++) {
  8919. if (sc->getSCE(i) && sc->getSCE(i)->val3 == 1) // It doesn't stack or even renew on the target
  8920. return 0;
  8921. else if (sc->getSCE(i) && sc->getSCE(i)->val3 == 0)
  8922. status_change_end(bl, static_cast<sc_type>(i)); // End the bonus part on the caster
  8923. }
  8924. break;
  8925. case SC_SPIRIT:
  8926. if( sd ){
  8927. uint64 target_class = 0;
  8928. uint64 mask = MAPID_UPPERMASK;
  8929. switch( val2 ){
  8930. case SL_ALCHEMIST:
  8931. target_class = MAPID_ALCHEMIST;
  8932. break;
  8933. case SL_ASSASIN:
  8934. target_class = MAPID_ASSASSIN;
  8935. break;
  8936. case SL_BARDDANCER:
  8937. target_class = MAPID_BARDDANCER;
  8938. break;
  8939. case SL_BLACKSMITH:
  8940. target_class = MAPID_BLACKSMITH;
  8941. break;
  8942. case SL_CRUSADER:
  8943. target_class = MAPID_CRUSADER;
  8944. break;
  8945. case SL_HUNTER:
  8946. target_class = MAPID_HUNTER;
  8947. break;
  8948. case SL_KNIGHT:
  8949. target_class = MAPID_KNIGHT;
  8950. break;
  8951. case SL_MONK:
  8952. target_class = MAPID_MONK;
  8953. break;
  8954. case SL_PRIEST:
  8955. target_class = MAPID_PRIEST;
  8956. break;
  8957. case SL_ROGUE:
  8958. target_class = MAPID_ROGUE;
  8959. break;
  8960. case SL_SAGE:
  8961. target_class = MAPID_SAGE;
  8962. break;
  8963. case SL_SOULLINKER:
  8964. target_class = MAPID_SOUL_LINKER;
  8965. break;
  8966. case SL_STAR:
  8967. target_class = MAPID_STAR_GLADIATOR;
  8968. break;
  8969. case SL_SUPERNOVICE:
  8970. target_class = MAPID_SUPER_NOVICE;
  8971. break;
  8972. case SL_WIZARD:
  8973. target_class = MAPID_WIZARD;
  8974. break;
  8975. case SL_HIGH:
  8976. if( sd->status.base_level >= 70 ){
  8977. return 0;
  8978. }
  8979. switch (sd->class_) {
  8980. case MAPID_SWORDMAN_HIGH:
  8981. case MAPID_MAGE_HIGH:
  8982. case MAPID_ARCHER_HIGH:
  8983. case MAPID_ACOLYTE_HIGH:
  8984. case MAPID_MERCHANT_HIGH:
  8985. case MAPID_THIEF_HIGH:
  8986. // Only these classes are allowed.
  8987. break;
  8988. default:
  8989. return 0;
  8990. }
  8991. // Set these to pass the check below.
  8992. mask = sd->class_;
  8993. target_class = sd->class_;
  8994. break;
  8995. default:
  8996. ShowError( "Unknown skill id %d for SC_SPIRIT.\n", val2 );
  8997. return 0;
  8998. }
  8999. if( ( sd->class_ & mask ) != target_class ){
  9000. return 0;
  9001. }
  9002. }else{
  9003. // Status change is only applicable for players
  9004. return 0;
  9005. }
  9006. break;
  9007. case SC_SOULGOLEM:
  9008. case SC_SOULSHADOW:
  9009. case SC_SOULFALCON:
  9010. case SC_SOULFAIRY:
  9011. if( sd == nullptr ){
  9012. // Status change is only applicable for players
  9013. return 0;
  9014. }
  9015. break;
  9016. }
  9017. // Check for OPT1 stacking
  9018. if (sc->opt1 > OPT1_NONE && scdb->opt1 > OPT1_NONE) {
  9019. for (const auto &status_it : status_db) {
  9020. sc_type opt1_type = status_it.second->type;
  9021. if (sc->getSCE(opt1_type) && status_it.second->opt1 > OPT1_NONE)
  9022. status_change_end(bl, opt1_type);
  9023. }
  9024. }
  9025. // Before overlapping fail, one must check for status cured.
  9026. std::vector<sc_type> endlist;
  9027. if (type == SC_BERSERK && val3 == SC__BLOODYLUST) //There is some reasons that using SC_BERSERK first before SC__BLOODYLUST itself on Akinari's fix
  9028. endlist = status_db.getEndOnStart(SC__BLOODYLUST);
  9029. else
  9030. endlist = scdb->endonstart;
  9031. // End the SCs from the list
  9032. if (!endlist.empty()) {
  9033. for (const auto &it : endlist) {
  9034. sc_type rem_sc = it;
  9035. if (sc->getSCE(rem_sc)) {
  9036. switch (rem_sc) {
  9037. case SC_BERSERK:
  9038. case SC_SATURDAYNIGHTFEVER:
  9039. sc->getSCE(rem_sc)->val2 = 0; // Mark to not lose hp
  9040. [[fallthrough]];
  9041. default:
  9042. status_change_end(bl, rem_sc);
  9043. break;
  9044. }
  9045. }
  9046. }
  9047. }
  9048. // List of hardcoded status cured.
  9049. switch (type) {
  9050. case SC_BLESSING:
  9051. if (bl->type == BL_PC) {
  9052. // Remove Curse first, Stone is only removed if the target is not cursed
  9053. if (sc->getSCE(SC_CURSE)) {
  9054. status_change_end(bl, SC_CURSE);
  9055. return 1; // End Curse and do not give stat boost
  9056. } else if (sc->getSCE(SC_STONE)) {
  9057. status_change_end(bl, SC_STONE);
  9058. return 1; // End Stone and do not give stat boost
  9059. }
  9060. }
  9061. if(sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_HIGH)
  9062. status_change_end(bl, SC_SPIRIT);
  9063. break;
  9064. case SC_INCREASEAGI:
  9065. if(sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_HIGH)
  9066. status_change_end(bl, SC_SPIRIT);
  9067. break;
  9068. case SC_DELUGE:
  9069. if (sc->getSCE(SC_FOGWALL) && sc->getSCE(SC_BLIND))
  9070. status_change_end(bl, SC_BLIND);
  9071. break;
  9072. case SC_SILENCE:
  9073. if (sc->getSCE(SC_GOSPEL) && sc->getSCE(SC_GOSPEL)->val4 == BCT_SELF)
  9074. status_change_end(bl, SC_GOSPEL);
  9075. break;
  9076. case SC_IMPOSITIO:
  9077. if (sc->getSCE(SC_IMPOSITIO) && sc->getSCE(SC_IMPOSITIO)->val1 > val1) //Replace higher level effect for lower.
  9078. status_change_end(bl,SC_IMPOSITIO);
  9079. break;
  9080. case SC_ENDURE:
  9081. if (sd && sd->special_state.no_walk_delay)
  9082. return 1;
  9083. break;
  9084. case SC_MADOGEAR:
  9085. status_db.removeByStatusFlag(bl, { SCF_MADOCANCEL });
  9086. if (sd)
  9087. pc_bonus_script_clear(sd, BSF_REM_ON_MADOGEAR);
  9088. break;
  9089. default:
  9090. break;
  9091. }
  9092. // Check for overlapping fails
  9093. if( (sce = sc->getSCE(type)) ) {
  9094. switch( type ) {
  9095. case SC_MERC_FLEEUP:
  9096. case SC_MERC_ATKUP:
  9097. case SC_MERC_HPUP:
  9098. case SC_MERC_SPUP:
  9099. case SC_MERC_HITUP:
  9100. if( sce->val1 > val1 )
  9101. val1 = sce->val1;
  9102. break;
  9103. case SC_ADRENALINE:
  9104. case SC_ADRENALINE2:
  9105. case SC_WEAPONPERFECTION:
  9106. case SC_OVERTHRUST:
  9107. if (sce->val2 > val2)
  9108. return 0;
  9109. break;
  9110. case SC_GOSPEL:
  9111. // Must not override a casting gospel char.
  9112. if(sce->val4 == BCT_SELF)
  9113. return 0;
  9114. if(sce->val1 > val1)
  9115. return 1;
  9116. break;
  9117. case SC_ENDURE:
  9118. if(sce->val4 && !val4)
  9119. return 1; // Don't let you override infinite endure.
  9120. if(sce->val1 > val1)
  9121. return 1;
  9122. break;
  9123. case SC_JAILED:
  9124. // When a player is already jailed, do not edit the jail data.
  9125. val2 = sce->val2;
  9126. val3 = sce->val3;
  9127. val4 = sce->val4;
  9128. break;
  9129. case SC_SHAPESHIFT:
  9130. case SC_PROPERTYWALK:
  9131. break;
  9132. case SC_LEADERSHIP:
  9133. case SC_GLORYWOUNDS:
  9134. case SC_SOULCOLD:
  9135. case SC_HAWKEYES:
  9136. if( sce->val4 && !val4 ) // You cannot override master guild aura
  9137. return 0;
  9138. break;
  9139. case SC_JOINTBEAT:
  9140. if (sc && sc->getSCE(type)->val2 & BREAK_NECK)
  9141. return 0; // BREAK_NECK cannot be stacked with new breaks until the status is over.
  9142. val2 |= sce->val2; // Stackable ailments
  9143. [[fallthrough]];
  9144. default:
  9145. if (scdb->flag[SCF_OVERLAPIGNORELEVEL])
  9146. break;
  9147. if(sce->val1 > val1)
  9148. return 1; // Return true to not mess up skill animations. [Skotlex]
  9149. }
  9150. }
  9151. vd = status_get_viewdata(bl);
  9152. std::bitset<SCB_MAX> calc_flag = scdb->calc_flag;
  9153. if(!(flag&SCSTART_LOADED)) // &4 - Do not parse val settings when loading SCs
  9154. switch(type)
  9155. {
  9156. /* Permanent effects */
  9157. case SC_AETERNA:
  9158. case SC_MODECHANGE:
  9159. case SC_WEIGHT50:
  9160. case SC_WEIGHT90:
  9161. case SC_BROKENWEAPON:
  9162. case SC_BROKENARMOR:
  9163. case SC_READYSTORM:
  9164. case SC_READYDOWN:
  9165. case SC_READYCOUNTER:
  9166. case SC_READYTURN:
  9167. case SC_DODGE:
  9168. case SC_PUSH_CART:
  9169. case SC_SPRITEMABLE:
  9170. case SC_CLAN_INFO:
  9171. case SC_DAILYSENDMAILCNT:
  9172. case SC_SOULATTACK:
  9173. tick = INFINITE_TICK;
  9174. break;
  9175. case SC_KEEPING:
  9176. case SC_BARRIER: {
  9177. unit_data *ud = unit_bl2ud(bl);
  9178. if (ud)
  9179. ud->attackabletime = ud->canact_tick = ud->canmove_tick = gettick() + tick;
  9180. }
  9181. break;
  9182. case SC_DECREASEAGI:
  9183. case SC_INCREASEAGI:
  9184. case SC_ADORAMUS:
  9185. if (type == SC_ADORAMUS) {
  9186. // 1000% base chance to blind, but still can be resisted
  9187. sc_start(src, bl, SC_BLIND, 1000, val1, skill_get_time(scdb->skill_id, val1));
  9188. if (sc->getSCE(SC_ADORAMUS))
  9189. return 0; //Adoramus can't refresh itself, but it can cause blind again
  9190. }
  9191. val2 = 2 + val1; // Agi change
  9192. break;
  9193. case SC_ENDURE:
  9194. val2 = 7; // Hit-count [Celest]
  9195. if( !(flag&SCSTART_NOAVOID) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg2(bl->m) && !map_getmapflag(bl->m, MF_BATTLEGROUND) && !val4 ) {
  9196. map_session_data *tsd;
  9197. if( sd ) {
  9198. int32 i;
  9199. for( i = 0; i < MAX_DEVOTION; i++ ) {
  9200. if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
  9201. status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  9202. }
  9203. }
  9204. else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
  9205. status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  9206. }
  9207. if( val4 )
  9208. tick = INFINITE_TICK;
  9209. break;
  9210. case SC_AUTOBERSERK:
  9211. if (status->hp < status->max_hp / 4 &&
  9212. (!sc->getSCE(SC_PROVOKE) || sc->getSCE(SC_PROVOKE)->val4==0))
  9213. sc_start4(src,bl,SC_PROVOKE,100,10,0,0,1,60000);
  9214. tick = INFINITE_TICK;
  9215. break;
  9216. case SC_SIGNUMCRUCIS:
  9217. val2 = 10 + 4*val1; // Def reduction
  9218. tick = INFINITE_TICK;
  9219. clif_emotion(bl, ET_SWEAT);
  9220. break;
  9221. case SC_MAXIMIZEPOWER:
  9222. tick_time = val2 = tick>0?tick:60000;
  9223. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  9224. break;
  9225. case SC_EDP:
  9226. val2 = (val1 + 1) / 2 + 2; // Chance to Poison enemies.
  9227. #ifndef RENEWAL
  9228. val3 = 50*(val1+1); // Damage increase (+50 +50*lv%)
  9229. #endif
  9230. if (sd) {
  9231. uint16 poison_level = pc_checkskill(sd, GC_RESEARCHNEWPOISON);
  9232. if (poison_level > 0) {
  9233. tick += 30000; // Base of 30 seconds
  9234. tick += poison_level * 15 * 1000; // Additional 15 seconds per level
  9235. }
  9236. }
  9237. break;
  9238. case SC_POISONREACT:
  9239. #ifdef RENEWAL
  9240. val2= (val1 + 1) / 2;
  9241. #else
  9242. val2=(val1+1)/2 + val1/10; // Number of counters [Skotlex]
  9243. #endif
  9244. val3=50; // + 5*val1; // Chance to counter. [Skotlex]
  9245. break;
  9246. case SC_MAGICROD:
  9247. val2 = val1*20; // SP gained
  9248. break;
  9249. case SC_KYRIE:
  9250. if( val4 ) { // Formulas for Praefatio
  9251. val2 = (status->max_hp * (val1 * 2 + 10) / 100) + val4 * 2; //%Max HP to absorb
  9252. val3 = 6 + val1; //Hits
  9253. } else { // Formulas for Kyrie Eleison
  9254. val2 = status->max_hp * (val1 * 2 + 10) / 100;
  9255. val3 = (val1 / 2 + 5);
  9256. }
  9257. break;
  9258. case SC_MAGICPOWER:
  9259. #ifdef RENEWAL
  9260. val3 = 5 * val1; // Matk% increase
  9261. #else
  9262. val2 = 1; // Lasts 1 invocation
  9263. val3 = 10 * val1; // Matk% increase
  9264. val4 = 0; // 0 = ready to be used, 1 = activated and running
  9265. #endif
  9266. break;
  9267. case SC_SACRIFICE:
  9268. val2 = 5; // Lasts 5 hits
  9269. tick = INFINITE_TICK;
  9270. break;
  9271. case SC_ENCPOISON:
  9272. val2= 250+50*val1; // Poisoning Chance (2.5+0.5%) in 1/10000 rate
  9273. break;
  9274. case SC_ELEMENTALCHANGE:
  9275. // val1 : Element Lvl (if called by skill lvl 1, takes random value between 1 and 4)
  9276. // val2 : Element (When no element, random one is picked)
  9277. // val3 : 0 = called by skill 1 = called by script (fixed level)
  9278. if( !val2 ) val2 = rnd()%ELE_ALL;
  9279. if( val1 == 1 && val3 == 0 )
  9280. val1 = 1 + rnd()%4;
  9281. else if( val1 > 4 )
  9282. val1 = 4; // Max Level
  9283. val3 = 0; // Not need to keep this info.
  9284. break;
  9285. case SC_PROVIDENCE:
  9286. val2 = val1*5; // Race/Ele resist
  9287. break;
  9288. case SC_REFLECTSHIELD:
  9289. val2 = 10+val1*3; // %Dmg reflected
  9290. // val4 used to mark if reflect shield is an inheritance bonus from Devotion
  9291. if( !(flag&SCSTART_NOAVOID) && (bl->type&(BL_PC|BL_MER)) ) {
  9292. map_session_data *tsd;
  9293. if( sd ) {
  9294. int32 i;
  9295. for( i = 0; i < MAX_DEVOTION; i++ ) {
  9296. if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
  9297. status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  9298. }
  9299. }
  9300. else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
  9301. status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  9302. }
  9303. break;
  9304. case SC_STRIPWEAPON:
  9305. if (!sd) // Watk reduction
  9306. val2 = 25;
  9307. break;
  9308. case SC_STRIPSHIELD:
  9309. if (!sd) // Def reduction
  9310. val2 = 15;
  9311. break;
  9312. case SC_STRIPARMOR:
  9313. if (!sd) // Vit reduction
  9314. val2 = 40;
  9315. break;
  9316. case SC_STRIPHELM:
  9317. if (!sd) // Int reduction
  9318. val2 = 40;
  9319. break;
  9320. case SC_AUTOSPELL:
  9321. // Val1 Skill LV of Autospell
  9322. // Val2 Skill ID to cast
  9323. // Val3 Max Lv to cast
  9324. #ifdef RENEWAL
  9325. val4 = val1 * 2; // Chance of casting
  9326. #else
  9327. val4 = 5 + val1*2; // Chance of casting
  9328. #endif
  9329. break;
  9330. case SC_VOLCANO:
  9331. {
  9332. int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition
  9333. uint8 i = max((val1-1)%5, 0);
  9334. #ifdef RENEWAL
  9335. val2 = 5 + val1 * 5; // ATK/MATK increase
  9336. #else
  9337. val2 = val1*10; // Watk increase
  9338. if (status->def_ele != ELE_FIRE)
  9339. val2 = 0;
  9340. #endif
  9341. val3 = enchant_eff[i];
  9342. }
  9343. break;
  9344. case SC_VIOLENTGALE:
  9345. {
  9346. int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition
  9347. uint8 i = max((val1-1)%5, 0);
  9348. val2 = val1*3; // Flee increase
  9349. #ifndef RENEWAL
  9350. if (status->def_ele != ELE_WIND)
  9351. val2 = 0;
  9352. #endif
  9353. val3 = enchant_eff[i];
  9354. }
  9355. break;
  9356. case SC_DELUGE:
  9357. {
  9358. int8 deluge_eff[] = { 5, 9, 12, 14, 15 }; // HP addition rate n/100
  9359. int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition
  9360. uint8 i = max((val1-1)%5, 0);
  9361. val2 = deluge_eff[i]; // HP increase
  9362. #ifndef RENEWAL
  9363. if (status->def_ele != ELE_WATER)
  9364. val2 = 0;
  9365. #endif
  9366. val3 = enchant_eff[i];
  9367. }
  9368. break;
  9369. case SC_SUITON:
  9370. if (!val2 || (sd && (sd->class_&MAPID_BASEMASK) == MAPID_NINJA)) {
  9371. // No penalties.
  9372. val2 = 0; // Agi penalty
  9373. val3 = 0; // Walk speed penalty
  9374. break;
  9375. }
  9376. val3 = 50;
  9377. val2 = 3*((val1+1)/3);
  9378. if (val1 > 4) val2--;
  9379. //Suiton is a special case, stop effect is forced and only happens when target enters it
  9380. if (!unit_blown_immune(bl, 0x1))
  9381. unit_stop_walking( bl, USW_FIXPOS|USW_FORCE_STOP );
  9382. break;
  9383. case SC_ONEHAND:
  9384. case SC_TWOHANDQUICKEN:
  9385. val2 = 300;
  9386. if (val1 > 10) // For boss casted skills [Skotlex]
  9387. val2 += 20*(val1-10);
  9388. break;
  9389. case SC_MERC_QUICKEN:
  9390. val2 = 300;
  9391. break;
  9392. #ifndef RENEWAL_ASPD
  9393. case SC_SPEARQUICKEN:
  9394. val2 = 200+10*val1;
  9395. break;
  9396. #endif
  9397. case SC_DANCING:
  9398. // val1 : Skill ID + LV
  9399. // val2 : Skill Group of the Dance.
  9400. // val3 : Brings the skill_lv (merged into val1 here)
  9401. // val4 : Partner
  9402. if (val1 == CG_MOONLIT)
  9403. clif_status_change(bl,EFST_MOON,1,tick,0, 0, 0);
  9404. val1|= (val3<<16);
  9405. val3 = tick/1000; // Tick duration
  9406. tick_time = 1000; // [GodLesZ] tick time
  9407. break;
  9408. #ifndef RENEWAL
  9409. case SC_LONGING:
  9410. val2 = 500-100*val1; // Aspd penalty.
  9411. break;
  9412. #else
  9413. case SC_ENSEMBLEFATIGUE:
  9414. val2 = 30; // Speed and ASPD penalty
  9415. break;
  9416. case SC_RICHMANKIM:
  9417. val2 = 10 + 10 * val1; // Exp increase bonus
  9418. break;
  9419. case SC_DRUMBATTLE:
  9420. val2 = 15 + val1 * 5; // Atk increase
  9421. val3 = val1 * 15; // Def increase
  9422. break;
  9423. case SC_NIBELUNGEN:
  9424. val2 = rnd() % RINGNBL_MAX; // See e_nibelungen_status
  9425. break;
  9426. case SC_SIEGFRIED:
  9427. val2 = val1 * 3; // Elemental Resistance
  9428. val3 = val1 * 5; // Status ailment resistance
  9429. break;
  9430. case SC_WHISTLE:
  9431. val2 = 18 + 2 * val1; // Flee increase
  9432. val3 = (val1 + 1) / 2; // Perfect dodge increase
  9433. break;
  9434. case SC_ASSNCROS:
  9435. val2 = val1 < 10 ? val1 * 2 - 1 : 20; // ASPD increase
  9436. break;
  9437. case SC_POEMBRAGI:
  9438. val2 = 2 * val1; // Cast time reduction
  9439. val3 = 3 * val1; // After-cast delay reduction
  9440. break;
  9441. case SC_APPLEIDUN:
  9442. val2 = val1 < 10 ? 9 + val1 : 20; // HP rate increase
  9443. val3 = 2 * val1; // Potion recovery rate
  9444. break;
  9445. case SC_HUMMING:
  9446. val2 = 4 * val1; // Hit increase
  9447. break;
  9448. case SC_DONTFORGETME:
  9449. val2 = 1 + 30 * val1; // ASPD decrease
  9450. val3 = 5 + 2 * val1; // Movement speed adjustment.
  9451. break;
  9452. case SC_FORTUNE:
  9453. val2 = val1 * 10; // Critical increase
  9454. break;
  9455. case SC_SERVICE4U:
  9456. val2 = val1 < 10 ? 9 + val1 : 20; // MaxSP percent increase
  9457. val3 = 5 + val1; // SP cost reduction
  9458. break;
  9459. #endif
  9460. case SC_EXPLOSIONSPIRITS:
  9461. val2 = 75 + 25*val1; // Cri bonus
  9462. break;
  9463. case SC_ASPDPOTION0:
  9464. case SC_ASPDPOTION1:
  9465. case SC_ASPDPOTION2:
  9466. case SC_ASPDPOTION3:
  9467. val2 = 50*(2+type-SC_ASPDPOTION0);
  9468. break;
  9469. case SC_NOCHAT:
  9470. // A hardcoded interval of 60 seconds is expected, as the time that SC_NOCHAT uses is defined by
  9471. // mmocharstatus.manner, each negative point results in 1 minute with this status activated.
  9472. // This is done this way because the message that the client displays is hardcoded, and only
  9473. // shows how many minutes are remaining. [Panikon]
  9474. tick = 60000;
  9475. val1 = battle_config.manner_system; // Mute filters.
  9476. if (sd) {
  9477. clif_changemanner( *sd );
  9478. clif_updatestatus(*sd,SP_MANNER);
  9479. }
  9480. break;
  9481. case SC_STONEWAIT:
  9482. val3 = max(1, tick - delay); // Petrify time
  9483. tick = delay;
  9484. break;
  9485. case SC_DPOISON:
  9486. // Lose 10/15% of your life as long as it doesn't brings life below 25%
  9487. if (status->hp > status->max_hp / 4) {
  9488. int32 diff = status->max_hp*(bl->type==BL_PC?10:15)/100;
  9489. if (status->hp - diff < status->max_hp / 4)
  9490. diff = status->hp - (status->max_hp / 4);
  9491. status_zap(bl, diff, 0);
  9492. }
  9493. [[fallthrough]];
  9494. case SC_STONE:
  9495. case SC_POISON:
  9496. case SC_BLEEDING:
  9497. case SC_BURNING:
  9498. case SC_KILLING_AURA:
  9499. tick_time = status_get_sc_interval(type);
  9500. val4 = tick - tick_time; // Remaining time
  9501. break;
  9502. case SC_TOXIN:
  9503. if (val3 == 1) // Target
  9504. tick_time = status_get_sc_interval(type);
  9505. else // Caster
  9506. tick_time = 1000;
  9507. val4 = tick - tick_time; // Remaining time
  9508. break;
  9509. case SC_DEATHHURT:
  9510. if (val3 == 1)
  9511. break;
  9512. tick_time = status_get_sc_interval(type);
  9513. val4 = tick - tick_time; // Remaining time
  9514. break;
  9515. case SC_LEECHESEND:
  9516. if (val3 == 0)
  9517. break;
  9518. tick_time = status_get_sc_interval(type);
  9519. val4 = tick - tick_time; // Remaining time
  9520. break;
  9521. case SC_PYREXIA:
  9522. if (val3 == 1) { // Target
  9523. // Causes blind for duration of pyrexia, unreducable and unavoidable, but can be healed with e.g. green potion
  9524. status_change_start(src, bl, SC_BLIND, 10000, val1, 0, 0, 0, tick, SCSTART_NOAVOID | SCSTART_NOTICKDEF | SCSTART_NORATEDEF);
  9525. tick_time = status_get_sc_interval(type);
  9526. val4 = tick - tick_time; // Remaining time
  9527. } else // Caster
  9528. val2 = 15; // CRIT % and ATK % increase
  9529. break;
  9530. case SC_VENOMBLEED:
  9531. if (val3 == 0) // Caster
  9532. val2 = 30; // Reflect damage % reduction
  9533. break;
  9534. case SC_MAGICMUSHROOM:
  9535. if (val3 == 1) { // Target
  9536. tick_time = status_get_sc_interval(type);
  9537. val4 = tick - tick_time; // Remaining time
  9538. } else // Caster
  9539. val2 = 10; // After-cast delay % reduction
  9540. break;
  9541. case SC_CONFUSION:
  9542. if (!val4)
  9543. clif_emotion(bl,ET_QUESTION);
  9544. break;
  9545. case SC_GRADUAL_GRAVITY:
  9546. val2 = 10 * val1;
  9547. tick_time = status_get_sc_interval(type);
  9548. val4 = tick - tick_time; // Remaining time
  9549. break;
  9550. case SC_ALL_STAT_DOWN:
  9551. val2 = 20 * val1;
  9552. if( val1 < skill_get_max( NPC_ALL_STAT_DOWN ) ){
  9553. val2 -= 10;
  9554. }
  9555. break;
  9556. case SC_DAMAGE_HEAL:
  9557. switch( val1 ){
  9558. case 1:
  9559. val2 = BF_WEAPON;
  9560. break;
  9561. case 2:
  9562. val2 = BF_MAGIC;
  9563. break;
  9564. case 3:
  9565. //TODO: Absorb MISC damage? Both WEAPON & MAGIC damage? Which is correct on level 3?
  9566. val2 = BF_MISC;
  9567. break;
  9568. }
  9569. break;
  9570. case SC_BOSSMAPINFO:
  9571. if( sd == nullptr ){
  9572. return 0;
  9573. }else{
  9574. // Search for Boss on this Map
  9575. mob_data* boss_md = map_getmob_boss( bl->m );
  9576. // No MVP on this map
  9577. if( boss_md == nullptr ){
  9578. clif_bossmapinfo( *sd, nullptr, BOSS_INFO_NOT );
  9579. return 0;
  9580. }
  9581. val1 = boss_md->bl.id;
  9582. tick_time = status_get_sc_interval( type );
  9583. val4 = tick - tick_time; // Remaining time
  9584. }
  9585. break;
  9586. case SC_HIDING:
  9587. val2 = tick/1000;
  9588. tick_time = 1000; // [GodLesZ] tick time
  9589. val3 = 0; // Unused, previously speed adjustment
  9590. val4 = val1+3; // Seconds before SP substraction happen.
  9591. break;
  9592. case SC_CHASEWALK:
  9593. val2 = tick>0?tick:10000; // Interval at which SP is drained.
  9594. val3 = 35 - 5 * val1; // Speed adjustment.
  9595. if (sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_ROGUE)
  9596. val3 -= 40;
  9597. val4 = 10+val1*2; // SP cost.
  9598. if (map_flag_gvg2(bl->m) || map_getmapflag(bl->m, MF_BATTLEGROUND)) val4 *= 5;
  9599. break;
  9600. case SC_CLOAKING:
  9601. if (!sd) // Monsters should be able to walk with no penalties. [Skotlex]
  9602. val1 = 10;
  9603. tick_time = val2 = tick>0?tick:60000; // SP consumption rate.
  9604. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  9605. val3 = 0; // Unused, previously walk speed adjustment
  9606. // val4&1 signals the presence of a wall.
  9607. // val4&2 makes cloak not end on normal attacks [Skotlex]
  9608. // val4&4 makes cloak not end on using skills
  9609. if (bl->type == BL_PC || (bl->type == BL_MOB && ((TBL_MOB*)bl)->special_state.clone) ) // Standard cloaking.
  9610. val4 |= battle_config.pc_cloak_check_type&7;
  9611. else
  9612. val4 |= battle_config.monster_cloak_check_type&7;
  9613. break;
  9614. case SC_SIGHT: /* splash status */
  9615. case SC_RUWACH:
  9616. case SC_SIGHTBLASTER:
  9617. val3 = skill_get_splash(val2, val1); // Val2 should bring the skill-id.
  9618. val2 = tick/20;
  9619. tick_time = 20; // [GodLesZ] tick time
  9620. break;
  9621. case SC_AUTOGUARD:
  9622. if( !(flag&SCSTART_NOAVOID) ) {
  9623. map_session_data *tsd;
  9624. int32 i;
  9625. for( i = val2 = 0; i < val1; i++) {
  9626. int32 t = 5-(i / 2);
  9627. val2 += (t < 0)? 1:t;
  9628. }
  9629. if( bl->type&(BL_PC|BL_MER) ) {
  9630. if( sd ) {
  9631. for( i = 0; i < MAX_DEVOTION; i++ ) {
  9632. if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
  9633. status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  9634. }
  9635. }
  9636. else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
  9637. status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  9638. }
  9639. }
  9640. break;
  9641. case SC_DEFENDER:
  9642. if (!(flag&SCSTART_NOAVOID)) {
  9643. val2 = 5 + 15*val1; // Damage reduction
  9644. val3 = 0; // Unused, previously speed adjustment
  9645. val4 = 250 - 50*val1; // Aspd adjustment
  9646. if (sd) {
  9647. map_session_data *tsd;
  9648. int32 i;
  9649. for (i = 0; i < MAX_DEVOTION; i++) { // See if there are devoted characters, and pass the status to them. [Skotlex]
  9650. if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])))
  9651. status_change_start(src,&tsd->bl,type,10000,val1,val2,val3,val4,tick,SCSTART_NOAVOID);
  9652. }
  9653. }
  9654. }
  9655. break;
  9656. case SC_TENSIONRELAX:
  9657. if (sd) {
  9658. pc_setsit(sd);
  9659. skill_sit(sd, true);
  9660. clif_sitting(sd->bl);
  9661. }
  9662. val2 = 12; // SP cost
  9663. tick_time = 10000; // Decrease at 10secs intervals.
  9664. val3 = tick / tick_time;
  9665. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  9666. break;
  9667. case SC_PARRYING:
  9668. val2 = 20 + val1*3; // Block Chance
  9669. break;
  9670. case SC_WINDWALK:
  9671. val2 = (val1+1)/2; // Flee bonus is 1/1/2/2/3/3/4/4/5/5
  9672. break;
  9673. case SC_JOINTBEAT:
  9674. if( val2&BREAK_NECK )
  9675. sc_start2(src,bl,SC_BLEEDING,100,val1,val3,skill_get_time2(scdb->skill_id,val1));
  9676. break;
  9677. case SC_BERSERK:
  9678. if( val3 == SC__BLOODYLUST )
  9679. sc_start(src,bl,(sc_type)val3,100,val1,tick);
  9680. else
  9681. sc_start4(src,bl, SC_ENDURE, 100,10,0,0,1, tick);
  9682. // HP healing is performing after the calc_status call.
  9683. // Val2 holds HP penalty
  9684. if (!val4) val4 = skill_get_time2(scdb->skill_id,val1);
  9685. if (!val4) val4 = 10000; // Val4 holds damage interval
  9686. val3 = tick/val4; // val3 holds skill duration
  9687. tick_time = val4; // [GodLesZ] tick time
  9688. break;
  9689. case SC_GOSPEL:
  9690. if(val4 == BCT_SELF) { // Self effect
  9691. val2 = tick/10000;
  9692. tick_time = 10000; // [GodLesZ] tick time
  9693. status_change_clear_buffs(bl, SCCB_BUFFS|SCCB_DEBUFFS|SCCB_CHEM_PROTECT); // Remove buffs/debuffs
  9694. }
  9695. break;
  9696. case SC_MARIONETTE:
  9697. {
  9698. int32 stat;
  9699. val3 = 0;
  9700. val4 = 0;
  9701. stat = ( sd ? sd->status.str : status_get_base_status(bl)->str ) / 2; val3 |= cap_value(stat,0,0xFF)<<16;
  9702. stat = ( sd ? sd->status.agi : status_get_base_status(bl)->agi ) / 2; val3 |= cap_value(stat,0,0xFF)<<8;
  9703. stat = ( sd ? sd->status.vit : status_get_base_status(bl)->vit ) / 2; val3 |= cap_value(stat,0,0xFF);
  9704. stat = ( sd ? sd->status.int_: status_get_base_status(bl)->int_) / 2; val4 |= cap_value(stat,0,0xFF)<<16;
  9705. stat = ( sd ? sd->status.dex : status_get_base_status(bl)->dex ) / 2; val4 |= cap_value(stat,0,0xFF)<<8;
  9706. stat = ( sd ? sd->status.luk : status_get_base_status(bl)->luk ) / 2; val4 |= cap_value(stat,0,0xFF);
  9707. break;
  9708. }
  9709. case SC_MARIONETTE2:
  9710. {
  9711. int32 stat,max_stat;
  9712. // Fetch caster information
  9713. struct block_list *pbl = map_id2bl(val1);
  9714. status_change *psc = pbl?status_get_sc(pbl):nullptr;
  9715. struct status_change_entry *psce = psc?psc->getSCE(SC_MARIONETTE):nullptr;
  9716. if (!psce)
  9717. return 0;
  9718. // Fetch target's stats
  9719. status_data* status2 = status_get_status_data(*bl); // Battle status
  9720. val3 = 0;
  9721. val4 = 0;
  9722. max_stat = battle_config.max_parameter; // Cap to 99 (default)
  9723. stat = (psce->val3 >>16)&0xFF; stat = min(stat, max_stat - status2->str ); val3 |= cap_value(stat,0,0xFF)<<16;
  9724. stat = (psce->val3 >> 8)&0xFF; stat = min(stat, max_stat - status2->agi ); val3 |= cap_value(stat,0,0xFF)<<8;
  9725. stat = (psce->val3 >> 0)&0xFF; stat = min(stat, max_stat - status2->vit ); val3 |= cap_value(stat,0,0xFF);
  9726. stat = (psce->val4 >>16)&0xFF; stat = min(stat, max_stat - status2->int_); val4 |= cap_value(stat,0,0xFF)<<16;
  9727. stat = (psce->val4 >> 8)&0xFF; stat = min(stat, max_stat - status2->dex ); val4 |= cap_value(stat,0,0xFF)<<8;
  9728. stat = (psce->val4 >> 0)&0xFF; stat = min(stat, max_stat - status2->luk ); val4 |= cap_value(stat,0,0xFF);
  9729. break;
  9730. }
  9731. case SC_SPIRIT:
  9732. //1st Transcendent Spirit works similar to Marionette Control
  9733. if(sd && val2 == SL_HIGH) {
  9734. int32 stat,max_stat;
  9735. status_data *status2 = status_get_base_status(bl);
  9736. val3 = 0;
  9737. val4 = 0;
  9738. max_stat = (status_get_lv(bl)-10<50)?status_get_lv(bl)-10:50;
  9739. stat = max(0, max_stat - status2->str); val3 |= cap_value(stat,0,0xFF)<<16;
  9740. stat = max(0, max_stat - status2->agi ); val3 |= cap_value(stat,0,0xFF)<<8;
  9741. stat = max(0, max_stat - status2->vit ); val3 |= cap_value(stat,0,0xFF);
  9742. stat = max(0, max_stat - status2->int_); val4 |= cap_value(stat,0,0xFF)<<16;
  9743. stat = max(0, max_stat - status2->dex ); val4 |= cap_value(stat,0,0xFF)<<8;
  9744. stat = max(0, max_stat - status2->luk ); val4 |= cap_value(stat,0,0xFF);
  9745. }
  9746. break;
  9747. case SC_REJECTSWORD:
  9748. val2 = 15*val1; // Reflect chance
  9749. val3 = 3; // Reflections
  9750. tick = INFINITE_TICK;
  9751. break;
  9752. case SC_MEMORIZE:
  9753. val2 = 5; // Memorized casts.
  9754. tick = INFINITE_TICK;
  9755. break;
  9756. #ifndef RENEWAL
  9757. case SC_GRAVITATION:
  9758. val2 = 50*val1; // aspd reduction
  9759. break;
  9760. #endif
  9761. case SC_REGENERATION:
  9762. if (val1 == 1)
  9763. val2 = 2;
  9764. else
  9765. val2 = val1; // HP Regerenation rate: 200% 200% 300%
  9766. val3 = val1; // SP Regeneration Rate: 100% 200% 300%
  9767. // If val4 comes set, this blocks regen rather than increase it.
  9768. break;
  9769. case SC_DEVOTION:
  9770. {
  9771. block_list* d_bl = map_id2bl( val1 );
  9772. if( d_bl == nullptr ){
  9773. break;
  9774. }
  9775. status_change* d_sc = status_get_sc( d_bl );
  9776. if( d_sc != nullptr && !d_sc->empty() ){
  9777. // Inherits status from source
  9778. const enum sc_type types[] = { SC_AUTOGUARD, SC_DEFENDER, SC_REFLECTSHIELD, SC_ENDURE };
  9779. int32 i = (map_flag_gvg2(bl->m) || map_getmapflag(bl->m, MF_BATTLEGROUND))?2:3;
  9780. while( i >= 0 ) {
  9781. enum sc_type type2 = types[i];
  9782. if( d_sc->getSCE(type2) )
  9783. status_change_start(d_bl, bl, type2, 10000, d_sc->getSCE(type2)->val1, 0, 0, (type2 == SC_REFLECTSHIELD ? 1 : 0), skill_get_time(status_db.getSkill(type2),d_sc->getSCE(type2)->val1), (type2 == SC_DEFENDER) ? SCSTART_NOAVOID : SCSTART_NOAVOID|SCSTART_NOICON);
  9784. i--;
  9785. }
  9786. }
  9787. break;
  9788. }
  9789. case SC_COMA: // Coma. Sends a char to 1HP. If val2, do not zap sp
  9790. status_zap(bl, status->hp-1, val2?0:status->sp-1);
  9791. return 1;
  9792. break;
  9793. case SC_CLOSECONFINE2:
  9794. {
  9795. struct block_list *src2 = val2?map_id2bl(val2):nullptr;
  9796. status_change *sc2 = src2?status_get_sc(src2):nullptr;
  9797. struct status_change_entry *sce2 = sc2?sc2->getSCE(SC_CLOSECONFINE):nullptr;
  9798. if (src2 && sc2) {
  9799. if (!sce2) { // Start lock on caster.
  9800. #ifdef RENEWAL
  9801. val3 = 50; // Flee increase
  9802. #else
  9803. val3 = 10; // Flee increase
  9804. #endif
  9805. sc_start4(src2,src2,SC_CLOSECONFINE,100,val1,1,val3,0,tick+1000);
  9806. } else { // Increase count of locked enemies and refresh time.
  9807. (sce2->val2)++;
  9808. delete_timer(sce2->timer, status_change_timer);
  9809. sce2->timer = add_timer(gettick()+tick+1000, status_change_timer, src2->id, SC_CLOSECONFINE);
  9810. }
  9811. } else // Status failed.
  9812. return 0;
  9813. }
  9814. break;
  9815. case SC_KAITE:
  9816. val2 = 1+val1/5; // Number of bounces: 1 + skill_lv/5
  9817. break;
  9818. case SC_KAUPE:
  9819. switch (val1) {
  9820. case 3: // 33*3 + 1 -> 100%
  9821. val2++;
  9822. [[fallthrough]];
  9823. case 1:
  9824. case 2: // 33, 66%
  9825. val2 += 33*val1;
  9826. val3 = 1; // Dodge 1 attack total.
  9827. break;
  9828. default: // Custom. For high level mob usage, higher level means more blocks. [Skotlex]
  9829. val2 = 100;
  9830. val3 = val1-2;
  9831. break;
  9832. }
  9833. break;
  9834. case SC_COMBO:
  9835. {
  9836. // val1: Skill ID
  9837. // val2: When given, target (for autotargetting skills)
  9838. // val3: When set, this combo time should NOT delay attack/movement
  9839. // val3: If set to 2 this combo will delay ONLY attack
  9840. // val3: TK: Last used kick
  9841. // val4: TK: Combo time
  9842. struct unit_data *ud = unit_bl2ud(bl);
  9843. if ( ud && (!val3 || val3 == 2) ) {
  9844. tick += 300 * battle_config.combo_delay_rate/100;
  9845. ud->attackabletime = gettick()+tick;
  9846. if( !val3 )
  9847. unit_set_walkdelay(bl, gettick(), tick, 1);
  9848. }
  9849. val3 = 0;
  9850. val4 = tick;
  9851. break;
  9852. }
  9853. case SC_EARTHSCROLL:
  9854. val2 = 11-val1; // Chance to consume: 11-skill_lv%
  9855. break;
  9856. case SC_RUN:
  9857. {
  9858. //Store time at which you started running.
  9859. t_tick currenttick = gettick();
  9860. // Note: this int64 value is stored in two separate int32 variables (FIXME)
  9861. val3 = (int32)(currenttick & 0x00000000ffffffffLL);
  9862. val4 = (int32)((currenttick & 0xffffffff00000000LL) >> 32);
  9863. tick = INFINITE_TICK;
  9864. break;
  9865. }
  9866. case SC_KAAHI:
  9867. val2 = 200*val1; // HP heal
  9868. val3 = 5*val1; // SP cost
  9869. break;
  9870. case SC_BLESSING:
  9871. if (bl->type == BL_PC || (!undead_flag && status->race != RC_DEMON))
  9872. val2 = val1;
  9873. else
  9874. val2 = 0; // 0 -> Half stat.
  9875. break;
  9876. case SC_TRICKDEAD:
  9877. if (vd) vd->dead_sit = 1;
  9878. tick = INFINITE_TICK;
  9879. break;
  9880. case SC_CONCENTRATE:
  9881. val2 = 2 + val1;
  9882. if (sd) { // Store the card-bonus data that should not count in the %
  9883. val3 = sd->indexed_bonus.param_bonus[1]; // Agi
  9884. val4 = sd->indexed_bonus.param_bonus[4]; // Dex
  9885. } else
  9886. val3 = val4 = 0;
  9887. break;
  9888. case SC_MAXOVERTHRUST:
  9889. val2 = 20*val1; // Power increase
  9890. break;
  9891. case SC_OVERTHRUST:
  9892. case SC_ADRENALINE2:
  9893. case SC_ADRENALINE:
  9894. case SC_WEAPONPERFECTION:
  9895. {
  9896. map_session_data * s_sd = BL_CAST(BL_PC, src);
  9897. if (type == SC_OVERTHRUST) {
  9898. // val2 holds if it was casted on self, or is bonus received from others
  9899. #ifdef RENEWAL
  9900. val3 = (val2) ? 5 * val1 : (val1 > 4) ? 15 : (val1 > 2) ? 10 : 5; // Power increase
  9901. #else
  9902. val3 = (val2) ? 5 * val1 : 5; // Power increase
  9903. #endif
  9904. }
  9905. else if (type == SC_ADRENALINE2 || type == SC_ADRENALINE) {
  9906. val3 = (val2) ? 300 : 200; // Aspd increase
  9907. }
  9908. if (s_sd && pc_checkskill(s_sd, BS_HILTBINDING) > 0)
  9909. tick += tick / 10; //If caster has Hilt Binding, duration increases by 10%
  9910. }
  9911. break;
  9912. case SC_CONCENTRATION:
  9913. #ifdef RENEWAL
  9914. val2 = 5 + val1 * 2; // Batk/Watk Increase
  9915. val4 = 5 + val1 * 2; // Def reduction
  9916. #else
  9917. val2 = 5*val1; // Batk/Watk Increase
  9918. val4 = 5*val1; // Def reduction
  9919. #endif
  9920. val3 = 10*val1; // Hit Increase
  9921. sc_start(src, bl, SC_ENDURE, 100, 1, tick); // Level 1 Endure effect
  9922. break;
  9923. case SC_ANGELUS:
  9924. val2 = 5*val1; // def increase
  9925. break;
  9926. case SC_IMPOSITIO:
  9927. val2 = 5*val1; // WATK/MATK increase
  9928. break;
  9929. case SC_MELTDOWN:
  9930. val2 = 100*val1; // Chance to break weapon
  9931. val3 = 70*val1; // Change to break armor
  9932. break;
  9933. case SC_TRUESIGHT:
  9934. val2 = 10*val1; // Critical increase
  9935. val3 = 3*val1; // Hit increase
  9936. break;
  9937. case SC_SUN_COMFORT:
  9938. val2 = (status_get_lv(bl) + status->dex + status->luk)/2; // def increase
  9939. break;
  9940. case SC_MOON_COMFORT:
  9941. val2 = (status_get_lv(bl) + status->dex + status->luk)/10; // flee increase
  9942. break;
  9943. case SC_STAR_COMFORT:
  9944. val2 = (status_get_lv(bl) + status->dex + status->luk); // Aspd increase
  9945. break;
  9946. case SC_QUAGMIRE:
  9947. val2 = (sd?5:10)*val1; // Agi/Dex decrease.
  9948. break;
  9949. // gs_something1 [Vicious]
  9950. case SC_GATLINGFEVER:
  9951. val2 = 20*val1; // Aspd increase
  9952. val3 = 20+10*val1; // Atk increase
  9953. val4 = 5*val1; // Flee decrease
  9954. break;
  9955. case SC_FLING:
  9956. if (bl->type == BL_PC)
  9957. val2 = 0; // No armor reduction to players.
  9958. else
  9959. val2 = 5*val1; // Def reduction
  9960. val3 = 5*val1; // Def2 reduction
  9961. break;
  9962. case SC_PROVOKE:
  9963. val2 = 2+3*val1; // Atk increase
  9964. val3 = 5+5*val1; // Def reduction.
  9965. // val4 signals autoprovoke.
  9966. break;
  9967. case SC_AVOID:
  9968. // Speed change rate.
  9969. if (bl->type == BL_HOM)
  9970. val2 = 40 * val1;
  9971. else
  9972. val2 = 10 * val1;
  9973. break;
  9974. case SC_DEFENCE:
  9975. // Vit bonus for players / Def bonus for homunculus
  9976. #ifdef RENEWAL
  9977. val2 = 5 + (5 * val1);
  9978. #else
  9979. val2 = 2 * val1;
  9980. #endif
  9981. break;
  9982. case SC_BLOODLUST:
  9983. // Atk rate change
  9984. val2 = 20 + (10 * val1);
  9985. // Leech chance
  9986. // It's actually 9 * level on both pre-re and renewal, despite the description
  9987. val3 = 9 * val1;
  9988. // Leech percent
  9989. val4 = 20;
  9990. break;
  9991. case SC_FLEET:
  9992. val2 = 30*val1; // Aspd change
  9993. val3 = 5+5*val1; // bAtk/wAtk rate change
  9994. break;
  9995. case SC_MINDBREAKER:
  9996. val2 = 20*val1; // matk increase.
  9997. val3 = 12*val1; // mdef2 reduction.
  9998. break;
  9999. case SC_JAILED:
  10000. // Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time.
  10001. if (sd) {
  10002. if (sd->mapindex != val2) {
  10003. int32 pos = (bl->x&0xFFFF)|(bl->y<<16), // Current Coordinates
  10004. map_idx = sd->mapindex; // Current Map
  10005. // 1. Place in Jail (val2 -> Jail Map, val3 -> x, val4 -> y
  10006. pc_setpos(sd,(uint16)val2,val3,val4, CLR_TELEPORT);
  10007. // 2. Set restore point (val3 -> return map, val4 return coords
  10008. val3 = map_idx;
  10009. val4 = pos;
  10010. } else if (!val3 || val3 == sd->mapindex) { // Use save point.
  10011. val3 = mapindex_name2id( sd->status.save_point.map );
  10012. val4 = (sd->status.save_point.x&0xFFFF)
  10013. |(sd->status.save_point.y<<16);
  10014. }
  10015. }
  10016. break;
  10017. case SC_UTSUSEMI:
  10018. val2=(val1+1)/2; // Number of hits blocked
  10019. val3=skill_get_blewcount(NJ_UTSUSEMI, val1); // knockback value.
  10020. break;
  10021. case SC_BUNSINJYUTSU:
  10022. val2=(val1+1)/2; // Number of hits blocked
  10023. break;
  10024. case SC_CHANGE:
  10025. val2= 30*val1; // Vit increase
  10026. val3= 20*val1; // Int increase
  10027. break;
  10028. case SC_SWOO:
  10029. if(status_has_mode(status,MD_STATUSIMMUNE))
  10030. tick /= 5; // !TODO: Reduce skill's duration. But for how long?
  10031. break;
  10032. case SC_ARMOR:
  10033. // NPC_DEFENDER:
  10034. val2 = 8; // Damage will be divided by this value
  10035. // Attack requirements to be blocked:
  10036. val3 = BF_LONG; // Range
  10037. val4 = BF_WEAPON|BF_MISC; // Type
  10038. break;
  10039. case SC_ENCHANTARMS:
  10040. // Make sure the received element is valid.
  10041. if (val1 >= ELE_ALL)
  10042. val1 = val1%ELE_ALL;
  10043. else if (val1 < 0)
  10044. val1 = rnd()%ELE_ALL;
  10045. break;
  10046. case SC_CRITICALWOUND:
  10047. // Level 1 ~ 5 & 6 ~ 10 has different duration
  10048. // Level 6 ~ 10 use effect of level 1 ~ 5
  10049. val1 = 1 + ((val1-1)%5);
  10050. val2 = 20*val1; // Heal effectiveness decrease
  10051. break;
  10052. case SC_MAGICMIRROR:
  10053. // Level 1 ~ 5 & 6 ~ 10 has different duration
  10054. // Level 6 ~ 10 use effect of level 1 ~ 5
  10055. val1 = 1 + ((val1-1)%5);
  10056. [[fallthrough]];
  10057. case SC_SLOWCAST:
  10058. val2 = 20*val1; // Magic reflection/cast rate
  10059. break;
  10060. case SC_ARMORCHANGE:
  10061. if (val2 == NPC_ANTIMAGIC) { // Boost mdef
  10062. val2 =-20;
  10063. val3 = 20;
  10064. } else { // Boost def
  10065. val2 = 20;
  10066. val3 =-20;
  10067. }
  10068. // Level 1 ~ 5 & 6 ~ 10 has different duration
  10069. // Level 6 ~ 10 use effect of level 1 ~ 5
  10070. val1 = 1 + ((val1-1)%5);
  10071. val2 *= val1; // 20% per level
  10072. val3 *= val1;
  10073. break;
  10074. case SC_EXPBOOST:
  10075. case SC_JEXPBOOST:
  10076. case SC_PERIOD_RECEIVEITEM_2ND:
  10077. case SC_PERIOD_PLUSEXP_2ND:
  10078. if (val1 < 1)
  10079. return 0;
  10080. break;
  10081. case SC_SUFFRAGIUM:
  10082. #ifdef RENEWAL
  10083. val2 = 5 + val1 * 5; // Speed cast decrease
  10084. #else
  10085. val2 = 15 * val1; // Speed cast decrease
  10086. #endif
  10087. break;
  10088. case SC_INCHEALRATE:
  10089. if (val1 < 1)
  10090. val1 = 1;
  10091. break;
  10092. case SC_DOUBLECAST:
  10093. val2 = 30+10*val1; // Trigger rate
  10094. break;
  10095. case SC_KAIZEL:
  10096. val2 = 10*val1; // % of life to be revived with
  10097. break;
  10098. // case ????:
  10099. // Place here SCs that have no SCB_* data, no skill associated, no ICON
  10100. // associated, and yet are not wrong/unknown. [Skotlex]
  10101. // break;
  10102. case SC_MERC_FLEEUP:
  10103. case SC_MERC_ATKUP:
  10104. case SC_MERC_HITUP:
  10105. val2 = 15 * val1;
  10106. break;
  10107. case SC_MERC_HPUP:
  10108. case SC_MERC_SPUP:
  10109. val2 = 5 * val1;
  10110. break;
  10111. case SC_REBIRTH:
  10112. val2 = 20*val1; // % of life to be revived with
  10113. break;
  10114. case SC_INVINCIBLE:
  10115. val2 = 100; // ATKpercent increase
  10116. val3 = 50; // Speed increase
  10117. val4 = 700; // ASPD increase
  10118. break;
  10119. /* General */
  10120. case SC_FEAR:
  10121. sc_start(src, bl, SC_ANKLE, 100, 0, 2000);
  10122. break;
  10123. /* Rune Knight */
  10124. case SC_DEATHBOUND:
  10125. val2 = 500 + 100 * val1;
  10126. break;
  10127. case SC_STONEHARDSKIN:
  10128. if (!status_charge(bl, status->hp / 5, 0)) // 20% of HP
  10129. return 0;
  10130. if (sd)
  10131. val1 = sd->status.job_level * pc_checkskill(sd, RK_RUNEMASTERY) / 4; // DEF/MDEF Increase
  10132. break;
  10133. case SC_REFRESH:
  10134. status_heal(bl, status_get_max_hp(bl) * 25 / 100, 0, 1);
  10135. status_change_clear_buffs(bl, SCCB_REFRESH);
  10136. break;
  10137. case SC_MILLENNIUMSHIELD:
  10138. {
  10139. int8 chance = rnd()%100;
  10140. val2 = ((chance < 20) ? 4 : (chance < 50) ? 3 : 2); // Shield count
  10141. val3 = 1000; // Shield HP
  10142. clif_millenniumshield( *bl, val2 );
  10143. }
  10144. break;
  10145. case SC_ABUNDANCE:
  10146. val4 = tick / 10000;
  10147. tick_time = 10000; // [GodLesZ] tick time
  10148. break;
  10149. case SC_GIANTGROWTH:
  10150. val2 = 30; // Damage success rate and STR increase
  10151. break;
  10152. case SC_LUXANIMA:
  10153. val2 = 15; // Storm Blast success %
  10154. val3 = 30; // Damage/HP/SP % increase
  10155. break;
  10156. /* Arch Bishop */
  10157. case SC_RENOVATIO:
  10158. val4 = tick / 5000;
  10159. tick_time = 5000;
  10160. break;
  10161. case SC_SECRAMENT:
  10162. val2 = 10 * val1;
  10163. break;
  10164. case SC_VENOMIMPRESS:
  10165. val2 = 10 * val1;
  10166. break;
  10167. case SC_WEAPONBLOCKING:
  10168. val2 = 10 + 2 * val1; // Chance
  10169. val4 = tick / 5000;
  10170. tick_time = 5000; // [GodLesZ] tick time
  10171. break;
  10172. case SC_OBLIVIONCURSE:
  10173. if (val3 == 0)
  10174. break;
  10175. val4 = tick / 3000;
  10176. tick_time = 3000; // [GodLesZ] tick time
  10177. break;
  10178. case SC_CLOAKINGEXCEED:
  10179. val2 = (val1 + 1) / 2; // Hits
  10180. val3 = (val1 - 1) * 10; // Walk speed
  10181. if (bl->type == BL_PC)
  10182. val4 |= battle_config.pc_cloak_check_type&7;
  10183. else
  10184. val4 |= battle_config.monster_cloak_check_type&7;
  10185. tick_time = 1000; // [GodLesZ] tick time
  10186. break;
  10187. case SC_HALLUCINATIONWALK:
  10188. case SC_NPC_HALLUCINATIONWALK:
  10189. val2 = 50 * val1; // Evasion rate of physical attacks. Flee
  10190. val3 = 10 * val1; // Evasion rate of magical attacks.
  10191. break;
  10192. case SC_MARSHOFABYSS:
  10193. if( bl->type == BL_PC )
  10194. val2 = 3 * val1; // AGI and DEX Reduction
  10195. else // BL_MOB
  10196. val2 = 6 * val1; // AGI and DEX Reduction
  10197. val3 = 10 * val1; // Movement Speed Reduction
  10198. break;
  10199. case SC_FREEZE_SP:
  10200. // val2 = sp drain per 10 seconds
  10201. tick_time = 10000; // [GodLesZ] tick time
  10202. break;
  10203. case SC_SPHERE_1:
  10204. case SC_SPHERE_2:
  10205. case SC_SPHERE_3:
  10206. case SC_SPHERE_4:
  10207. case SC_SPHERE_5:
  10208. if( !sd )
  10209. return 0; // Should only work on players.
  10210. val4 = tick / 1000;
  10211. if( val4 < 1 )
  10212. val4 = 1;
  10213. tick_time = 1000; // [GodLesZ] tick time
  10214. break;
  10215. case SC_SHAPESHIFT:
  10216. switch( val1 ) {
  10217. case 1: val2 = ELE_FIRE; break;
  10218. case 2: val2 = ELE_EARTH; break;
  10219. case 3: val2 = ELE_WIND; break;
  10220. case 4: val2 = ELE_WATER; break;
  10221. }
  10222. break;
  10223. case SC_ELECTRICSHOCKER:
  10224. case SC_CRYSTALIZE:
  10225. val4 = tick / 1000;
  10226. if( val4 < 1 )
  10227. val4 = 1;
  10228. tick_time = 1000; // [GodLesZ] tick time
  10229. break;
  10230. case SC_MEIKYOUSISUI:
  10231. val2 = val1 * 2; // % HP each sec
  10232. val3 = val1; // % SP each sec
  10233. val4 = tick / 1000;
  10234. if( val4 < 1 )
  10235. val4 = 1;
  10236. tick_time = 1000;
  10237. break;
  10238. case SC_CAMOUFLAGE:
  10239. val4 = tick/1000;
  10240. tick_time = 1000; // [GodLesZ] tick time
  10241. break;
  10242. case SC_WUGDASH:
  10243. {
  10244. //Store time at which you started running.
  10245. t_tick currenttick = gettick();
  10246. // Note: this int64 value is stored in two separate int32 variables (FIXME)
  10247. val3 = (int32)(currenttick&0x00000000ffffffffLL);
  10248. val4 = (int32)((currenttick&0xffffffff00000000LL)>>32);
  10249. tick = INFINITE_TICK;
  10250. break;
  10251. }
  10252. case SC__SHADOWFORM:
  10253. {
  10254. map_session_data * s_sd = map_id2sd(val2);
  10255. if( s_sd )
  10256. s_sd->shadowform_id = bl->id;
  10257. val4 = tick / 1000;
  10258. tick_time = 1000; // [GodLesZ] tick time
  10259. }
  10260. break;
  10261. case SC__STRIPACCESSORY:
  10262. if (!sd)
  10263. val2 = 20;
  10264. break;
  10265. case SC__INVISIBILITY:
  10266. val2 = 50 - 10 * val1; // ASPD
  10267. val3 = 20 * val1; // CRITICAL
  10268. val4 = tick / 1000;
  10269. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  10270. tick_time = 1000; // [GodLesZ] tick time
  10271. break;
  10272. case SC__ENERVATION:
  10273. val2 = 20 + 10 * val1; // ATK Reduction
  10274. if (sd) {
  10275. pc_delspiritball(sd,sd->spiritball,0);
  10276. pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type);
  10277. }
  10278. break;
  10279. case SC__GROOMY:
  10280. val2 = 20 + 10 * val1; // ASPD
  10281. val3 = 20 * val1; // HIT
  10282. if( sd ) { // Removes Animals
  10283. if( pc_isriding(sd) ) pc_setriding(sd, 0);
  10284. if( pc_isridingdragon(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_DRAGON);
  10285. if( pc_iswug(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_WUG);
  10286. if( pc_isridingwug(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_WUGRIDER);
  10287. if( pc_isfalcon(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_FALCON);
  10288. if( sd->status.pet_id > 0 ) pet_return_egg(sd, sd->pd);
  10289. if( hom_is_active(sd->hd) ) hom_vaporize(sd, HOM_ST_ACTIVE);
  10290. //if( sd->md ) mercenary_delete(sd->md,3); // Are Mercenaries removed? [aleos]
  10291. }
  10292. break;
  10293. case SC__LAZINESS:
  10294. val2 = 10 + 10 * val1; // Cast Increase
  10295. val3 = 10 * val1; // Flee Reduction
  10296. break;
  10297. case SC__UNLUCKY:
  10298. {
  10299. sc_type rand_eff;
  10300. switch(rnd() % 3) {
  10301. case 1: rand_eff = SC_BLIND; break;
  10302. case 2: rand_eff = SC_SILENCE; break;
  10303. default: rand_eff = SC_POISON; break;
  10304. }
  10305. val2 = 10 * val1; // Crit and Flee2 Reduction
  10306. status_change_start(src,bl,rand_eff,10000,val1,0,(rand_eff == SC_POISON ? src->id : 0),0,tick,SCSTART_NOTICKDEF|SCSTART_NORATEDEF);
  10307. break;
  10308. }
  10309. case SC__WEAKNESS:
  10310. val2 = 10 * val1;
  10311. // Bypasses coating protection and MADO
  10312. sc_start(src,bl,SC_STRIPWEAPON,100,val1,tick);
  10313. sc_start(src,bl,SC_STRIPSHIELD,100,val1,tick);
  10314. break;
  10315. case SC_GN_CARTBOOST:
  10316. if( val1 < 3 )
  10317. val2 = 50;
  10318. else if( val1 > 2 && val1 < 5 )
  10319. val2 = 75;
  10320. else
  10321. val2 = 100;
  10322. break;
  10323. case SC_PROPERTYWALK:
  10324. val3 = 0;
  10325. break;
  10326. case SC_STRIKING:
  10327. // val2 = watk bonus already calc
  10328. val3 = 6 - val1;// spcost = 6 - level (lvl1:5 ... lvl 5: 1)
  10329. val4 = tick / 1000;
  10330. tick_time = 1000; // [GodLesZ] tick time
  10331. break;
  10332. case SC_WARMER:
  10333. val4 = tick / 3000;
  10334. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  10335. tick_time = 3000;
  10336. break;
  10337. case SC_HELLS_PLANT:
  10338. tick_time = status_get_sc_interval(type);
  10339. val4 = tick - tick_time; // Remaining time
  10340. break;
  10341. case SC_SWINGDANCE:
  10342. val3 = 3 * val1 + val2; // Walk speed and aspd reduction.
  10343. break;
  10344. case SC_SYMPHONYOFLOVER:
  10345. val3 = 2 * val1 + val2 + (sd?sd->status.job_level:50) / 4; // MDEF Increase
  10346. break;
  10347. case SC_MOONLITSERENADE: // MATK Increase
  10348. case SC_RUSHWINDMILL: // ATK Increase
  10349. val3 = 4 + val1 * 3 + val2 + (sd?sd->status.job_level:50) / 5;
  10350. break;
  10351. case SC_ECHOSONG:
  10352. val3 = 6 * val1 + val2 + (sd?sd->status.job_level:50) / 4; // DEF Increase
  10353. break;
  10354. case SC_HARMONIZE:
  10355. val2 = 5 + 5 * val1;
  10356. break;
  10357. case SC_VOICEOFSIREN:
  10358. val4 = tick / 2000;
  10359. tick_time = 2000; // [GodLesZ] tick time
  10360. break;
  10361. case SC_DEEPSLEEP:
  10362. val4 = tick / 2000;
  10363. tick_time = 2000; // [GodLesZ] tick time
  10364. break;
  10365. case SC_SIRCLEOFNATURE:
  10366. val2 = 50 * val1; // HP recovery rate
  10367. break;
  10368. case SC_SONGOFMANA:
  10369. status_heal(bl, 0, status->max_sp * (val1 <= 2 ? 10 : val1 <= 4 ? 15 : 20) / 100, 1);
  10370. val3 = 50 * val1;
  10371. break;
  10372. case SC_SATURDAYNIGHTFEVER:
  10373. if (!val4) val4 = skill_get_time2(scdb->skill_id,val1);
  10374. if (!val4) val4 = 3000;
  10375. val3 = tick/val4;
  10376. tick_time = val4; // [GodLesZ] tick time
  10377. break;
  10378. case SC_GLOOMYDAY:
  10379. val2 = 20 + 5 * val1; // Flee reduction.
  10380. val3 = 15 + 5 * val1; // ASPD reduction.
  10381. if( sd && rnd()%100 < val1 ) { // (Skill Lv) %
  10382. val4 = 1; // Reduce walk speed by half.
  10383. if( pc_isriding(sd) ) pc_setriding(sd, 0);
  10384. if( pc_isridingdragon(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_DRAGON);
  10385. }
  10386. break;
  10387. case SC_GLOOMYDAY_SK:
  10388. // Random number between [15 ~ (Voice Lesson Skill Level x 5) + (Skill Level x 10)] %.
  10389. val2 = 15 + rnd()%( (sd?pc_checkskill(sd, WM_LESSON)*5:0) + val1*10 );
  10390. break;
  10391. case SC_SITDOWN_FORCE:
  10392. case SC_BANANA_BOMB_SITDOWN:
  10393. if( sd && !pc_issit(sd) ) {
  10394. pc_setsit(sd);
  10395. skill_sit(sd, true);
  10396. clif_sitting(*bl);
  10397. }
  10398. break;
  10399. case SC_DANCEWITHWUG:
  10400. val3 = 5 * val1; // ASPD Increase
  10401. val4 = 20 + 10 * val1; // Fixed Cast Time Reduction
  10402. break;
  10403. case SC_LERADSDEW:
  10404. val3 = 2 + 3 * val1 + min(3 * val2, 25); // MaxHP Increase
  10405. break;
  10406. case SC_MELODYOFSINK:
  10407. val2 = 10 * val1; // INT Reduction.
  10408. val3 = 2 + 2 * val1; // MaxSP reduction
  10409. break;
  10410. case SC_BEYONDOFWARCRY:
  10411. val2 = 10 + 10 * val1; // STR Reduction
  10412. val3 = 4 * val1; // MaxHP Reduction
  10413. break;
  10414. case SC_UNLIMITEDHUMMINGVOICE:
  10415. val3 = 4 * val1 + min(3 * val2, 15); // !TODO: What's the Lesson bonus?
  10416. break;
  10417. case SC_REFLECTDAMAGE:
  10418. val2 = 10 * val1; // Reflect reduction amount
  10419. val4 = tick/1000; // Number of SP cycles (duration)
  10420. tick_time = 1000; // [GodLesZ] tick time
  10421. break;
  10422. case SC_FORCEOFVANGUARD:
  10423. val2 = 8 + 12 * val1; // Chance
  10424. val3 = 5 + 2 * val1; // Max rage counters
  10425. tick = INFINITE_TICK; // Endless duration in the client
  10426. tick_time = 10000; // [GodLesZ] tick time
  10427. break;
  10428. case SC_EXEEDBREAK:
  10429. val2 = 150 * val1;
  10430. if (sd) { // Players
  10431. int16 index = sd->equip_index[EQI_HAND_R];
  10432. if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON)
  10433. val2 += 15 * sd->status.job_level + sd->inventory_data[index]->weight / 10 * sd->inventory_data[index]->weapon_level * status_get_lv(bl) / 100;
  10434. } else // Monster
  10435. val2 += 750;
  10436. break;
  10437. case SC_PRESTIGE:
  10438. val2 = (status->int_ + status->luk) * val1 / 20 * status_get_lv(bl) / 200 + val1; // Chance to evade magic damage.
  10439. val3 = ((val1 * 15) + (10 * (sd?pc_checkskill(sd,CR_DEFENDER):skill_get_max(CR_DEFENDER)))) * status_get_lv(bl) / 100; // Defence added
  10440. break;
  10441. case SC_SHIELDSPELL_HP:
  10442. val2 = 3; // 3% HP every 3 seconds
  10443. tick_time = status_get_sc_interval(type);
  10444. val4 = tick - tick_time; // Remaining time
  10445. break;
  10446. case SC_SHIELDSPELL_SP:
  10447. val2 = 3; // 3% SP every 5 seconds
  10448. tick_time = status_get_sc_interval(type);
  10449. val4 = tick - tick_time; // Remaining time
  10450. break;
  10451. case SC_SHIELDSPELL_ATK:
  10452. val2 = 150; // WATK/MATK bonus
  10453. break;
  10454. case SC_BANDING:
  10455. val2 = (sd ? skill_banding_count(sd) : 1);
  10456. tick_time = 5000; // [GodLesZ] tick time
  10457. break;
  10458. case SC_MAGNETICFIELD:
  10459. tick_time = 1000; // [GodLesZ] tick time
  10460. val4 = tick / tick_time;
  10461. break;
  10462. case SC_INSPIRATION:
  10463. val2 = 40 * val1; // ATK/MATK
  10464. val3 = 6 * val1; //All stat bonus
  10465. val4 = tick / 5000;
  10466. tick_time = 5000; // [GodLesZ] tick time
  10467. status_change_clear_buffs(bl, SCCB_DEBUFFS); // Remove debuffs
  10468. break;
  10469. case SC_CRESCENTELBOW:
  10470. val2 = (sd?sd->status.job_level:50) / 2 + (50 + 5 * val1);
  10471. break;
  10472. case SC_LIGHTNINGWALK: // [(Job Level / 2) + (40 + 5 * Skill Level)] %
  10473. val1 = (sd?sd->status.job_level:2)/2 + 40 + 5 * val1;
  10474. break;
  10475. case SC_GT_ENERGYGAIN:
  10476. val2 = 10 + 5 * val1; // Sphere gain chance.
  10477. break;
  10478. case SC_GT_CHANGE:
  10479. // Take note there is no def increase as skill desc says. [malufett]
  10480. val2 = val1 * 8; // ATK increase
  10481. val3 = status->agi * val1 / 60; // ASPD increase: [(Target AGI x Skill Level) / 60] %
  10482. break;
  10483. case SC_GT_REVITALIZE:
  10484. // Take note there is no vit, aspd, speed increase as skill desc says. [malufett]
  10485. val2 = 2 * val1; // MaxHP: [(Skill Level * 2)]%
  10486. val3 = val1 * 30 + 50; // Natural HP recovery increase: [(Skill Level x 30) + 50] %
  10487. // The stat def is not shown in the status window and it is processed differently
  10488. val4 = val1 * 20; // STAT DEF increase
  10489. break;
  10490. case SC_PYROTECHNIC_OPTION:
  10491. val2 = 60; // Eatk Renewal (Atk2)
  10492. break;
  10493. case SC_HEATER_OPTION:
  10494. val2 = 120; // Eatk Renewal (Atk2)
  10495. val3 = ELE_FIRE; // Change into fire element.
  10496. break;
  10497. case SC_TROPIC_OPTION:
  10498. val2 = 180; // Eatk Renewal (Atk2)
  10499. val3 = MG_FIREBOLT;
  10500. break;
  10501. case SC_AQUAPLAY_OPTION:
  10502. val2 = 40;
  10503. break;
  10504. case SC_COOLER_OPTION:
  10505. val2 = 80;
  10506. val3 = ELE_WATER; // Change into water element.
  10507. break;
  10508. case SC_CHILLY_AIR_OPTION:
  10509. val2 = 120; // Matk. Renewal (Matk1)
  10510. val3 = MG_COLDBOLT;
  10511. break;
  10512. case SC_WIND_STEP_OPTION:
  10513. val2 = 50; // % Increase speed and flee.
  10514. break;
  10515. case SC_BLAST_OPTION:
  10516. val2 = 20;
  10517. val3 = ELE_WIND; // Change into wind element.
  10518. break;
  10519. case SC_WILD_STORM_OPTION:
  10520. val2 = MG_LIGHTNINGBOLT;
  10521. break;
  10522. case SC_PETROLOGY_OPTION:
  10523. val2 = 5; //HP Rate bonus
  10524. val3 = 50;
  10525. break;
  10526. case SC_SOLID_SKIN_OPTION:
  10527. val2 = 33; //% Increase DEF
  10528. break;
  10529. case SC_CURSED_SOIL_OPTION:
  10530. val2 = 10; //HP rate bonus
  10531. val3 = ELE_EARTH; // Change into earth element.
  10532. break;
  10533. case SC_UPHEAVAL_OPTION:
  10534. val2 = 15; //HP rate bonus
  10535. val3 = WZ_EARTHSPIKE;
  10536. break;
  10537. case SC_CIRCLE_OF_FIRE_OPTION:
  10538. val2 = 300;
  10539. break;
  10540. case SC_WATER_SCREEN_OPTION:
  10541. tick_time = 10000;
  10542. break;
  10543. case SC_FIRE_CLOAK_OPTION:
  10544. case SC_WATER_DROP_OPTION:
  10545. case SC_WIND_CURTAIN_OPTION:
  10546. case SC_STONE_SHIELD_OPTION:
  10547. val2 = 100; // Elemental modifier.
  10548. break;
  10549. case SC_TROPIC:
  10550. case SC_CHILLY_AIR:
  10551. case SC_WILD_STORM:
  10552. case SC_UPHEAVAL:
  10553. val2 += 10;
  10554. [[fallthrough]];
  10555. case SC_HEATER:
  10556. case SC_COOLER:
  10557. case SC_BLAST:
  10558. case SC_CURSED_SOIL:
  10559. val2 += 10;
  10560. [[fallthrough]];
  10561. case SC_PYROTECHNIC:
  10562. case SC_AQUAPLAY:
  10563. case SC_GUST:
  10564. case SC_PETROLOGY:
  10565. val2 += 5;
  10566. val3 += 9000;
  10567. [[fallthrough]];
  10568. case SC_CIRCLE_OF_FIRE:
  10569. case SC_FIRE_CLOAK:
  10570. case SC_WATER_DROP:
  10571. case SC_WATER_SCREEN:
  10572. case SC_WIND_CURTAIN:
  10573. case SC_WIND_STEP:
  10574. case SC_STONE_SHIELD:
  10575. case SC_SOLID_SKIN:
  10576. val2 += 5;
  10577. val3 += 1000;
  10578. tick_time = val3; // [GodLesZ] tick time
  10579. break;
  10580. case SC_WATER_BARRIER:
  10581. val2 = 30; // Reductions. Atk2 and Flee1
  10582. break;
  10583. case SC_ZEPHYR:
  10584. val2 = 25; // Flee.
  10585. break;
  10586. case SC_TIDAL_WEAPON:
  10587. val2 = 20; // Increase Elemental's attack.
  10588. break;
  10589. case SC_ROCK_CRUSHER:
  10590. case SC_ROCK_CRUSHER_ATK:
  10591. case SC_POWER_OF_GAIA:
  10592. val2 = 33; //Def rate bonus/Speed rate reduction
  10593. val3 = 20; //HP rate bonus
  10594. break;
  10595. case SC_TEARGAS:
  10596. val2 = status_get_max_hp(bl) * 5 / 100; // Drain 5% HP
  10597. val4 = tick / 2000;
  10598. tick_time = 2000;
  10599. break;
  10600. case SC_TEARGAS_SOB:
  10601. val4 = tick / 3000;
  10602. tick_time = 3000;
  10603. break;
  10604. case SC_STOMACHACHE:
  10605. val2 = 8; // SP consume.
  10606. val4 = tick / 10000;
  10607. tick_time = 10000; // [GodLesZ] tick time
  10608. break;
  10609. case SC_PROMOTE_HEALTH_RESERCH:
  10610. //val1: 1 = Regular Potion, 2 = Thrown Potion
  10611. //val2: 1 = Small Potion, 2 = Medium Potion, 3 = Large Potion
  10612. //val3: MaxHP Increase By Fixed Amount
  10613. if (val1 == 1) // If potion was normally used, take the user's BaseLv
  10614. val3 = 1000 * val2 - 500 + status_get_lv(bl) * 10 / 3;
  10615. else if (val1 == 2) // If potion was thrown at someone, take the thrower's BaseLv
  10616. val3 = 1000 * val2 - 500 + status_get_lv(src) * 10 / 3;
  10617. if (val3 <= 0) // Prevents a negeative value from happening
  10618. val3 = 0;
  10619. break;
  10620. case SC_ENERGY_DRINK_RESERCH:
  10621. //val1: 1 = Regular Potion, 2 = Thrown Potion
  10622. //val2: 1 = Small Potion, 2 = Medium Potion, 3 = Large Potion
  10623. //val3: MaxSP Increase By Percentage Amount
  10624. if (val1 == 1) // If potion was normally used, take the user's BaseLv
  10625. val3 = status_get_lv(bl) / 10 + 5 * val2 - 10;
  10626. else if (val1 == 2) // If potion was thrown at someone, take the thrower's BaseLv
  10627. val3 = status_get_lv(src) / 10 + 5 * val2 - 10;
  10628. if (val3 <= 0) // Prevents a negeative value from happening
  10629. val3 = 0;
  10630. break;
  10631. case SC_KYOUGAKU:
  10632. val2 = 2*val1 + rnd()%val1;
  10633. clif_status_change(bl,EFST_ACTIVE_MONSTER_TRANSFORM,1,0,1002,0,0);
  10634. break;
  10635. case SC_KAGEMUSYA:
  10636. val2 = 20; // Damage increase bonus
  10637. val3 = val1 * 2;
  10638. tick_time = 1000;
  10639. val4 = tick / tick_time;
  10640. break;
  10641. case SC_ZANGETSU:
  10642. if( status_get_hp(bl) % 2 == 0 )
  10643. val2 = (status_get_lv(bl) / 3) + (20 * val1); //+Watk
  10644. else
  10645. val2 -= (status_get_lv(bl) / 3) + (30 * val1); //-Watk
  10646. if( status_get_sp(bl) % 2 == 0 )
  10647. val3 = (status_get_lv(bl) / 3) + (20 * val1); //+Matk
  10648. else
  10649. val3 -= (status_get_lv(bl) / 3) + (30 * val1); //-Matk
  10650. break;
  10651. case SC_GENSOU:
  10652. {
  10653. int32 hp = status_get_hp(bl), lv = 5;
  10654. int16 per = 100 / (status_get_max_hp(bl) / hp);
  10655. if( per <= 15 )
  10656. lv = 1;
  10657. else if( per <= 30 )
  10658. lv = 2;
  10659. else if( per <= 50 )
  10660. lv = 3;
  10661. else if( per <= 75 )
  10662. lv = 4;
  10663. if( hp % 2 == 0)
  10664. status_heal(bl, hp * (6-lv) * 4 / 100, status_get_sp(bl) * (6-lv) * 3 / 100, 1);
  10665. else
  10666. status_zap(bl, hp * (lv*4) / 100, status_get_sp(bl) * (lv*3) / 100);
  10667. }
  10668. break;
  10669. case SC_ANGRIFFS_MODUS:
  10670. val2 = 50 + 20 * val1; // atk bonus
  10671. val3 = 25 + 10 * val1; // Flee reduction.
  10672. val4 = tick/1000; // hp/sp reduction timer
  10673. tick_time = 1000;
  10674. break;
  10675. case SC_GOLDENE_FERSE:
  10676. val2 = 10 + 10*val1; // flee bonus
  10677. val3 = 6 + 4 * val1; // Aspd Bonus
  10678. val4 = 2 + 2 * val1; // Chance of holy attack
  10679. break;
  10680. case SC_STONE_WALL:
  10681. val2 = 100 * val1; // DEF bonus
  10682. val3 = 30 * val1; // MDEF bonus
  10683. break;
  10684. case SC_OVERED_BOOST:
  10685. val2 = 400 + 40 * val1; // flee bonus
  10686. val3 = 180 + 2 * val1; // aspd bonus
  10687. val4 = 50; // def reduc %
  10688. break;
  10689. case SC_GRANITIC_ARMOR:
  10690. val2 = 2*val1; // dmg reduction
  10691. val3 = 6*val1; // dmg taken on status end (6%:12%:18%:24%:30%)
  10692. val4 = 5*val1; // unknow formula
  10693. break;
  10694. case SC_MAGMA_FLOW:
  10695. val2 = 3*val1; // Activation chance
  10696. break;
  10697. case SC_PYROCLASTIC:
  10698. val2 += 100 + 10*val1; // atk bonus // !TODO: Confirm formula
  10699. break;
  10700. case SC_TEMPERING:
  10701. val2 += 5 + val1; // patk bonus
  10702. break;
  10703. case SC_GOLDENE_TONE:
  10704. val2 += 3 * val1; // res/mres bonus
  10705. break;
  10706. case SC_PARALYSIS: // [Lighta] need real info
  10707. val2 = 2*val1; // def reduction
  10708. val3 = 500*val1; // varcast augmentation
  10709. break;
  10710. case SC_TOXIN_OF_MANDARA:
  10711. val2 = 15*val1; // res reduction
  10712. break;
  10713. case SC_LIGHT_OF_REGENE: // Yommy leak need confirm
  10714. val2 = 20 * val1; // hp reco on death %
  10715. break;
  10716. case SC_PAIN_KILLER: // Yommy leak need confirm
  10717. val2 = min((( 200 * val1 ) * status_get_lv(src)) / 150, 1000); // dmg reduction linear. upto a maximum of 1000 [iRO Wiki]
  10718. if(sc->getSCE(SC_PARALYSIS))
  10719. sc_start(src,bl, SC_ENDURE, 100, val1, tick); // Start endure for same duration
  10720. break;
  10721. case SC_STYLE_CHANGE:
  10722. tick = INFINITE_TICK; // Infinite duration
  10723. break;
  10724. case SC_CBC:
  10725. val3 = 10; // Drain sp % dmg
  10726. val4 = tick/1000; // dmg each sec
  10727. tick = 1000;
  10728. break;
  10729. case SC_EQC:
  10730. val2 = 5 * val1; // def % reduc
  10731. val3 = 2 * val1; // HP drain %
  10732. break;
  10733. case SC_ASH:
  10734. val2 = 0; // hit % reduc
  10735. val3 = 0; // def % reduc
  10736. val4 = 0; // atk flee % reduc
  10737. if (!status_bl_has_mode(bl,MD_STATUSIMMUNE)) {
  10738. val2 = 50;
  10739. if (status_get_race(bl) == RC_PLANT) // plant type
  10740. val3 = 50;
  10741. if (status_get_element(bl) == ELE_WATER) // defense water type
  10742. val4 = 50;
  10743. }
  10744. break;
  10745. case SC_FULL_THROTTLE:
  10746. val2 = ( val1 == 1 ? 6 : 6 - val1 );
  10747. val3 = 20; //+% AllStats
  10748. tick_time = 1000;
  10749. val4 = tick / tick_time;
  10750. break;
  10751. case SC_REBOUND:
  10752. tick_time = 2000;
  10753. val4 = tick / tick_time;
  10754. clif_emotion(bl, ET_SWEAT);
  10755. break;
  10756. case SC_KINGS_GRACE:
  10757. val2 = 3 + val1; //HP Recover rate
  10758. tick_time = 1000;
  10759. val4 = tick / tick_time;
  10760. break;
  10761. case SC_TELEKINESIS_INTENSE:
  10762. val2 = 10 * val1; // sp consum / casttime reduc %
  10763. val3 = 40 * val1; // magic dmg bonus
  10764. break;
  10765. case SC_OFFERTORIUM:
  10766. val2 = 30 * val1; // heal power bonus
  10767. val3 = 100 + 20 * val1; // sp cost inc
  10768. break;
  10769. case SC_FRIGG_SONG:
  10770. val2 = 5 * val1; // maxhp bonus
  10771. val3 = 80 + 20 * val1; // healing
  10772. tick_time = 1000;
  10773. val4 = tick / tick_time;
  10774. break;
  10775. case SC_FLASHCOMBO:
  10776. val2 = 20 * val1 + 20; // atk bonus
  10777. break;
  10778. case SC_DARKCROW:
  10779. val2 = 30 * val1; // ATK bonus
  10780. break;
  10781. case SC_UNLIMIT:
  10782. val2 = 50 * val1;
  10783. break;
  10784. case SC_MONSTER_TRANSFORM:
  10785. case SC_ACTIVE_MONSTER_TRANSFORM:
  10786. if( !mobdb_checkid(val1) )
  10787. val1 = MOBID_PORING; // Default poring
  10788. break;
  10789. #ifndef RENEWAL
  10790. case SC_APPLEIDUN:
  10791. {
  10792. map_session_data * s_sd = BL_CAST(BL_PC, src);
  10793. val2 = (5 + 2 * val1) + (status_get_vit(src) / 10); //HP Rate: (5 + 2 * skill_lv) + (vit/10) + (BA_MUSICALLESSON level)
  10794. if (s_sd)
  10795. val2 += pc_checkskill(s_sd, BA_MUSICALLESSON) / 2;
  10796. break;
  10797. }
  10798. #endif
  10799. case SC_EPICLESIS:
  10800. val2 = 5 * val1; //HP rate bonus
  10801. break;
  10802. case SC_ILLUSIONDOPING:
  10803. val2 = 50; // -Hit
  10804. break;
  10805. case SC_OVERHEAT:
  10806. case SC_OVERHEAT_LIMITPOINT:
  10807. case SC_STEALTHFIELD:
  10808. tick_time = tick;
  10809. tick = INFINITE_TICK;
  10810. break;
  10811. case SC_STEALTHFIELD_MASTER:
  10812. tick_time = val3 = 2000 + 1000 * val1;
  10813. val4 = tick / tick_time;
  10814. break;
  10815. case SC_VACUUM_EXTREME:
  10816. // Suck target at n second, only if the n second is lower than the duration
  10817. // Does not suck targets on no-knockback maps
  10818. if (val4 < tick && unit_blown_immune(bl, 0x9) == UB_KNOCKABLE) {
  10819. tick_time = val4;
  10820. val4 = tick - tick_time;
  10821. } else
  10822. val4 = 0;
  10823. break;
  10824. case SC_FIRE_INSIGNIA:
  10825. case SC_WATER_INSIGNIA:
  10826. case SC_WIND_INSIGNIA:
  10827. case SC_EARTH_INSIGNIA:
  10828. tick_time = 5000;
  10829. val4 = tick / tick_time;
  10830. break;
  10831. case SC_NEUTRALBARRIER:
  10832. val2 = 10 + val1 * 5; // Def/Mdef
  10833. tick = INFINITE_TICK;
  10834. break;
  10835. case SC_MAGIC_POISON:
  10836. val2 = 50; // Attribute Reduction
  10837. break;
  10838. /* Rebellion */
  10839. case SC_B_TRAP:
  10840. val2 = src->id;
  10841. val3 = val1 * 25; // -movespeed TODO: Figure out movespeed rate
  10842. break;
  10843. case SC_C_MARKER:
  10844. case SC_BURNT:
  10845. // val1 = skill_lv
  10846. // val2 = src_id
  10847. val3 = 10; // -10 flee
  10848. //Start timer to send mark on mini map
  10849. val4 = tick/1000;
  10850. tick_time = 1000; // Sends every 1 seconds
  10851. break;
  10852. case SC_H_MINE:
  10853. val2 = src->id;
  10854. break;
  10855. case SC_HEAT_BARREL:
  10856. {
  10857. uint8 n = 10;
  10858. if (sd)
  10859. n = (uint8)sd->spiritball_old;
  10860. //kRO Update 2016-05-25
  10861. val2 = n * 5; // -fixed casttime
  10862. val3 = (6 + val1 * 2) * n; // ATK
  10863. val4 = 25 + val1 * 5; // -hit
  10864. }
  10865. break;
  10866. case SC_P_ALTER:
  10867. {
  10868. uint8 n = 10;
  10869. if (sd)
  10870. n = (uint8)sd->spiritball_old;
  10871. val2 = 10 * n; // +atk
  10872. val3 = (status->max_hp * (val1 * 5) / 100); // Barrier HP
  10873. }
  10874. break;
  10875. case SC_E_CHAIN:
  10876. val2 = 10;
  10877. if (sd)
  10878. val2 = sd->spiritball_old;
  10879. break;
  10880. case SC_ANTI_M_BLAST:
  10881. val2 = val1 * 10;
  10882. break;
  10883. case SC_CATNIPPOWDER:
  10884. val2 = -50; // WATK%, MATK%
  10885. val3 = 25 * val1; // Move speed reduction
  10886. if (bl->type == BL_PC && pc_checkskill(sd, SU_SPIRITOFLAND))
  10887. val4 = status_get_lv(src) / 12;
  10888. break;
  10889. case SC_BITESCAR: {
  10890. const struct status_data *b_status = status_get_base_status(src); // Base Status
  10891. val2 = (status_get_max_hp(bl) * (val1 + (b_status->dex / 25))) / status_get_max_hp(bl); // MHP% damage
  10892. tick_time = 1000;
  10893. val4 = tick / tick_time;
  10894. }
  10895. break;
  10896. case SC_ARCLOUSEDASH:
  10897. val2 = 15 + 5 * val1; // AGI
  10898. val3 = 25; // Move speed increase
  10899. if (sd && (sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER)
  10900. val4 = 10; // Ranged ATK increase if the target is a Doram
  10901. break;
  10902. case SC_SHRIMP:
  10903. val2 = 10; // BATK%, MATK%
  10904. break;
  10905. case SC_FRESHSHRIMP: {
  10906. int32 min = 0, max = 0;
  10907. map_session_data* ssd = BL_CAST( BL_PC, src );
  10908. #ifdef RENEWAL
  10909. status_data* sstatus = status_get_status_data(*src);
  10910. min = status_base_matk_min(src, sstatus, status_get_lv(src));
  10911. max = status_base_matk_max(src, sstatus, status_get_lv(src));
  10912. if (sstatus->rhw.matk > 0) {
  10913. int32 wMatk, variance;
  10914. wMatk = sstatus->rhw.matk;
  10915. variance = wMatk * sstatus->rhw.wlv / 10;
  10916. min += wMatk - variance;
  10917. max += wMatk + variance;
  10918. }
  10919. #endif
  10920. if (ssd != nullptr && ssd->right_weapon.overrefine > 0) {
  10921. min++;
  10922. max += ssd->right_weapon.overrefine - 1;
  10923. }
  10924. val2 += min + 178; // Heal
  10925. if (max > min)
  10926. val2 += rnd() % (max - min); // Heal
  10927. if (ssd != nullptr) {
  10928. if (pc_checkskill(ssd, SU_POWEROFSEA) > 0) {
  10929. val2 += val2 * 10 / 100;
  10930. if (pc_checkskill_summoner(ssd, SUMMONER_POWER_SEA) >= 20)
  10931. val2 += val2 * 20 / 100;
  10932. }
  10933. if (pc_checkskill(ssd, SU_SPIRITOFSEA) > 0)
  10934. val2 *= 2; // Doubles HP
  10935. }
  10936. tick_time = 10000 - ((val1 - 1) * 1000);
  10937. val4 = tick / tick_time;
  10938. }
  10939. break;
  10940. case SC_TUNAPARTY:
  10941. val2 = status_get_max_hp(src) * (val1 * 10) / 100; // Shield according to the Caster's MaxHP%
  10942. if (map_session_data* ssd = BL_CAST(BL_PC, src); pc_checkskill(ssd, SU_SPIRITOFSEA) > 0)
  10943. val2 *= 2; // Double the shield life if the caster has learned Spirit of Sea
  10944. break;
  10945. case SC_HISS:
  10946. val2 = 50; // Perfect Dodge
  10947. sc_start(src, bl, SC_DORAM_WALKSPEED, 100, 50, skill_get_time2(SU_HISS, val1));
  10948. break;
  10949. case SC_GROOMING:
  10950. val2 = 100; // Flee
  10951. break;
  10952. case SC_CHATTERING:
  10953. val2 = 100; // eATK, eMATK
  10954. sc_start(src, bl, SC_DORAM_WALKSPEED, 100, 50, skill_get_time2(SU_CHATTERING, val1));
  10955. break;
  10956. case SC_SWORDCLAN:
  10957. case SC_ARCWANDCLAN:
  10958. case SC_GOLDENMACECLAN:
  10959. case SC_CROSSBOWCLAN:
  10960. case SC_JUMPINGCLAN:
  10961. tick = INFINITE_TICK;
  10962. status_change_start(src,bl,SC_CLAN_INFO,10000,0,val2,0,0,INFINITE_TICK,flag);
  10963. break;
  10964. case SC_ANCILLA:
  10965. val1 = 15; // Heal Power rate bonus
  10966. val2 = 30; // SP Recovery rate bonus
  10967. break;
  10968. case SC_HELPANGEL:
  10969. tick_time = 1000;
  10970. val4 = tick / tick_time;
  10971. break;
  10972. case SC_EMERGENCY_MOVE:
  10973. val2 = 25; // Movement speed increase
  10974. break;
  10975. case SC_SUNSTANCE:
  10976. val2 = 2 + val1; // ATK Increase
  10977. tick = INFINITE_TICK;
  10978. break;
  10979. case SC_LUNARSTANCE:
  10980. val2 = 2 + val1; // MaxHP Increase
  10981. tick = INFINITE_TICK;
  10982. break;
  10983. case SC_STARSTANCE:
  10984. val2 = 4 + 2 * val1; // ASPD Increase
  10985. tick = INFINITE_TICK;
  10986. break;
  10987. case SC_DIMENSION1:
  10988. case SC_DIMENSION2:
  10989. if (sd)
  10990. pc_addspiritball(sd, skill_get_time2(SJ_BOOKOFDIMENSION, 1), 2);
  10991. break;
  10992. case SC_UNIVERSESTANCE:
  10993. val2 = 2 + val1; // All Stats Increase
  10994. tick = INFINITE_TICK;
  10995. break;
  10996. case SC_NEWMOON:
  10997. val2 = 7; // Number of Regular Attacks Until Reveal
  10998. tick_time = 1000;
  10999. val4 = tick / tick_time;
  11000. break;
  11001. case SC_FALLINGSTAR:
  11002. val2 = 8 + 2 * (1 + val1) / 2; // Autocast Chance
  11003. if (val1 >= 7)
  11004. val2 += 1; // Make it 15% at level 7.
  11005. break;
  11006. case SC_CREATINGSTAR:
  11007. tick_time = 500;
  11008. val4 = tick / tick_time;
  11009. break;
  11010. case SC_LIGHTOFSUN:
  11011. case SC_LIGHTOFMOON:
  11012. case SC_LIGHTOFSTAR:
  11013. val2 = 5 * val1; // Skill Damage Increase.
  11014. break;
  11015. case SC_SOULGOLEM:
  11016. val2 = 60 * val1; // DEF Increase
  11017. val3 = 15 + 5 * val1; // MDEF Increase
  11018. break;
  11019. case SC_SOULSHADOW:
  11020. val2 = (1 + val1) / 2; // ASPD Increase
  11021. val3 = 10 + 2 * val1; // CRIT Increase
  11022. break;
  11023. case SC_SOULFALCON:
  11024. val2 = 10 * val1; // WATK Increase
  11025. val3 = 10; // HIT Increase
  11026. if (val1 >= 3)
  11027. val3 += 3;
  11028. else if (val1 >= 5)
  11029. val3 += 5;
  11030. break;
  11031. case SC_SOULFAIRY:
  11032. val2 = 10 * val1; // MATK Increase
  11033. val3 = 5; // Variable Cast Time Reduction
  11034. if (val1 >= 3)
  11035. val3 += 2;
  11036. else if (val1 >= 5)
  11037. val3 += 5;
  11038. break;
  11039. case SC_SOULUNITY:
  11040. tick_time = 3000;
  11041. val4 = tick / tick_time;
  11042. break;
  11043. case SC_SOULDIVISION:
  11044. val2 = 10 * val1; // Skill Aftercast Increase
  11045. break;
  11046. case SC_SOULREAPER:
  11047. val2 = 10 + 5 * val1; // Chance of Getting A Soul Sphere.
  11048. break;
  11049. case SC_SOULCOLLECT:
  11050. val2 = 5 + 3 * val2; // Max Soul Sphere's.
  11051. val3 = tick > 0 ? tick : 60000;
  11052. tick_time = tick;
  11053. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  11054. break;
  11055. case SC_SP_SHA:
  11056. val2 = 50; // Move speed reduction
  11057. break;
  11058. case SC_SERVANTWEAPON:
  11059. if( sd ){
  11060. // Generate 5 servants on start
  11061. pc_addservantball( *sd, MAX_SERVANTBALL );
  11062. }
  11063. tick_time = skill_get_time2(DK_SERVANTWEAPON,val1); // Servant Regen Interval
  11064. if (tick_time < 500)
  11065. tick_time = 500; // Avoid being brought down to 0.
  11066. val4 = tick - tick_time; // Remaining Time
  11067. break;
  11068. case SC_RELIEVE_ON:
  11069. val2 = min(10*val1, 99); // % damage received reduced from 10 * skill lvl up to 99%
  11070. break;
  11071. case SC_VIGOR:
  11072. val2 = 100 - 10 * (val1 - 1); // HP consumption with each attack is reduced by skill lvl
  11073. val2 = max(val2, 0);
  11074. break;
  11075. case SC_POWERFUL_FAITH:
  11076. val2 = 5 + 5 * val1;// ATK Increase
  11077. val3 = 5 + 2 * val1;// PAtk Increase
  11078. break;
  11079. case SC_FIRM_FAITH:
  11080. val2 = 2 * val1;// MaxHP Increase
  11081. val3 = 8 * val1;// Res Increase
  11082. break;
  11083. case SC_SINCERE_FAITH:
  11084. val2 = (1 + val1) / 2;// ASPD Increase
  11085. val3 = 4 * val1;// Perfect Hit Increase
  11086. break;
  11087. case SC_GUARD_STANCE:
  11088. val2 = 50 + 50 * val1;// DEF Increase
  11089. val3 = 50 * val1;// ATK Decrease
  11090. tick = INFINITE_TICK;
  11091. break;
  11092. case SC_GUARDIAN_S:
  11093. val2 = ( status->max_hp * 30 / 100 ) * ( 25 * val1 ) / 100 + 15 * status->sta; // Barrier HP
  11094. break;
  11095. case SC_REBOUND_S:
  11096. val2 = 10 * val1;// Reduced Damage From Devotion
  11097. if (val2 > 99)
  11098. val2 = 99;// Lets not let it reduce above 99.
  11099. break;
  11100. case SC_ATTACK_STANCE:
  11101. val2 = 40 * val1;// DEF Decrease
  11102. val3 = 3 * val1; // P.ATK/S.MATK Increase
  11103. tick = INFINITE_TICK;
  11104. break;
  11105. case SC_HOLY_S:
  11106. val2 = 5 + 2 * val1;// Damage Reduction / Holy Damage Increase
  11107. break;
  11108. case SC_MEDIALE:
  11109. val2 = 2 * val1;// Heal Rate
  11110. val4 = tick / 2000;
  11111. tick_time = 2000;
  11112. break;
  11113. case SC_A_VITA:
  11114. case SC_A_TELUM:
  11115. val2 = 5 * val1;// Res/MRes Pierce Percentage
  11116. break;
  11117. case SC_PRE_ACIES:
  11118. val2 = 2 * val1;// CRate Increase
  11119. break;
  11120. case SC_COMPETENTIA:
  11121. val2 = 10 * val1;// PAtk/SMatk Increase - Unconfirmed if this is official formula but its 50 at Lv 5. [Rytech]
  11122. break;
  11123. case SC_RELIGIO:
  11124. case SC_BENEDICTUM:
  11125. val2 = 2 * val1;// Trait Stats Increase
  11126. break;
  11127. case SC_DANCING_KNIFE:
  11128. val4 = tick / 300;
  11129. tick_time = 300;
  11130. break;
  11131. case SC_POTENT_VENOM:
  11132. val2 = 2 * val1;// Res Pierce Percentage
  11133. break;
  11134. case SC_A_MACHINE:
  11135. val4 = tick / 1000;
  11136. tick_time = 1000;
  11137. break;
  11138. case SC_D_MACHINE:
  11139. val2 = 200 + 50 * val1;// DEF Increase
  11140. val3 = 20 * val1;// Res Increase
  11141. break;
  11142. case SC_SHADOW_STRIP:
  11143. if (!sd)// Res/MRes on mobs only.
  11144. val2 = 25;// Need official reduction amount.
  11145. break;
  11146. case SC_ABYSSFORCEWEAPON:
  11147. if( sd ){
  11148. // Generate 5 abyss spheres on start.
  11149. pc_addabyssball( *sd, MAX_ABYSSBALL );
  11150. }
  11151. tick_time = skill_get_time2(ABC_FROM_THE_ABYSS, val1);// Abyss Regen Interval
  11152. if (tick_time < 500)
  11153. tick_time = 500;// Avoid being brought down to 0.
  11154. val4 = tick - tick_time;// Remaining Time
  11155. break;
  11156. case SC_ABYSS_SLAYER:
  11157. val2 = 10 + 2 * val1;// PAtk/SMatk Increase
  11158. val3 = 100 + 20 * val1;// Hit Increase
  11159. break;
  11160. case SC_WINDSIGN:
  11161. val2 = 8 + 6 * val1;// Chance to gain AP on attack.
  11162. if (val1 == 5)// Its 40% on level 5.
  11163. val2 += 2;
  11164. break;
  11165. case SC_CALAMITYGALE:// Unlimit runs along with this.
  11166. sc_start(bl, bl, SC_UNLIMIT, 100, 5, skill_get_time(RA_UNLIMIT, 5));
  11167. break;
  11168. case SC_GEF_NOCTURN:// MRes Reduction. Official formula unknown.
  11169. case SC_AIN_RHAPSODY:// Res Reduction. Official formula unknown.
  11170. val2 = 10 * val1;// Res/MRes Decrease
  11171. if (val3&2)// Bonus if partner is found in party.
  11172. val2 *= 2;
  11173. break;
  11174. case SC_MUSICAL_INTERLUDE:
  11175. val2 = 5 + 5 * val1;// Res Increase
  11176. if (val3&2)// Bonus if partner is found in party.
  11177. val2 *= 2;
  11178. break;
  11179. case SC_JAWAII_SERENADE:
  11180. val2 = 3 * val1;// SMatk Increase
  11181. if (val3 & 2)// Bonus if partner is found in party.
  11182. val2 *= 2;
  11183. break;
  11184. case SC_PRON_MARCH:
  11185. val2 = 3 * val1;// PAtk Increase
  11186. if (val3 & 2)// Bonus if partner is found in party.
  11187. val2 *= 2;
  11188. break;
  11189. case SC_SPELL_ENCHANTING:
  11190. val2 = 4 * val1;// SMatk Increase
  11191. break;
  11192. case SC_FLAMETECHNIC:
  11193. case SC_FLAMEARMOR:
  11194. case SC_COLD_FORCE:
  11195. case SC_CRYSTAL_ARMOR:
  11196. case SC_GRACE_BREEZE:
  11197. case SC_EYES_OF_STORM:
  11198. case SC_EARTH_CARE:
  11199. case SC_STRONG_PROTECTION:
  11200. case SC_DEEP_POISONING:
  11201. case SC_POISON_SHIELD:
  11202. val2 += 10;
  11203. val3 += 10000;
  11204. tick_time = val3;
  11205. break;
  11206. case SC_FLAMETECHNIC_OPTION:
  11207. val3 = ELE_FIRE;
  11208. break;
  11209. case SC_COLD_FORCE_OPTION:
  11210. val3 = ELE_WATER;
  11211. break;
  11212. case SC_GRACE_BREEZE_OPTION:
  11213. val3 = ELE_WIND;
  11214. break;
  11215. case SC_EARTH_CARE_OPTION:
  11216. val3 = ELE_EARTH;
  11217. break;
  11218. case SC_DEEP_POISONING_OPTION:
  11219. val3 = ELE_POISON;
  11220. break;
  11221. case SC_SUB_WEAPONPROPERTY:
  11222. if (sd && val3 == ASC_EDP) {
  11223. uint16 poison_level = pc_checkskill(sd, GC_RESEARCHNEWPOISON);
  11224. if (poison_level > 0) {
  11225. tick += 30000; // Base of 30 seconds
  11226. tick += poison_level * 15 * 1000; // Additional 15 seconds per level
  11227. }
  11228. }
  11229. break;
  11230. case SC_WEAPONBREAKER:
  11231. val2 = val1 * 2 * 100; // Chance to break weapon
  11232. break;
  11233. case SC_INTENSIVE_AIM:
  11234. tick = 500;
  11235. break;
  11236. case SC_HIDDEN_CARD:
  11237. val2 = 3 * val1;
  11238. val3 = 10 * val1;
  11239. break;
  11240. case SC_TALISMAN_OF_PROTECTION:
  11241. // Heal value is static per cast of skill
  11242. val3 = skill_calc_heal(src, bl, SOA_TALISMAN_OF_PROTECTION, val1, true);
  11243. val4 = tick / 3000;
  11244. // First heal tick applies on cast
  11245. tick_time = 100;
  11246. break;
  11247. case SC_TALISMAN_OF_WARRIOR:
  11248. case SC_TALISMAN_OF_MAGICIAN:
  11249. val2 = 2 * val1;
  11250. break;
  11251. case SC_T_FIFTH_GOD:
  11252. val2 = 5 * val1;
  11253. break;
  11254. case SC_TALISMAN_OF_FIVE_ELEMENTS:
  11255. val2 = 4 * val1;
  11256. break;
  11257. case SC_HEAVEN_AND_EARTH:
  11258. val2 = 5 + 2 * val1;
  11259. break;
  11260. case SC_TEMPORARY_COMMUNION:
  11261. val2 = val1 * 3;
  11262. break;
  11263. case SC_MARINE_FESTIVAL:
  11264. case SC_SANDY_FESTIVAL:
  11265. val2 = 2 * val1;
  11266. break;
  11267. case SC_KI_SUL_RAMPAGE:
  11268. tick_time = 100;
  11269. val4 = tick / 1000;
  11270. break;
  11271. case SC_BLESSING_OF_M_CREATURES:
  11272. val2 = val1 * 10;
  11273. break;
  11274. case SC_COLORS_OF_HYUN_ROK_BUFF:
  11275. val2 = 50;
  11276. break;
  11277. case SC_STAR_BURST:
  11278. tick_time = status_get_sc_interval(type);
  11279. val4 = tick - tick_time; // Remaining time
  11280. break;
  11281. default:
  11282. if (calc_flag.none() && scdb->skill_id == 0 && scdb->icon == EFST_BLANK && scdb->opt1 == OPT1_NONE && scdb->opt2 == OPT2_NONE && scdb->state.none() && scdb->flag.none() && scdb->endonstart.empty() && scdb->endreturn.empty() && scdb->fail.empty() && scdb->endonend.empty()) {
  11283. // Status change with no calc, no icon, and no skill associated...?
  11284. ShowWarning("status_change_start: Status %s (%d) is bare. Add the NoWarning flag to suppress this message.\n", script_get_constant_str("SC_", type), type);
  11285. return 0;
  11286. }
  11287. } else // Special considerations when loading SC data.
  11288. switch( type ) {
  11289. case SC_WEDDING:
  11290. case SC_XMAS:
  11291. case SC_SUMMER:
  11292. case SC_HANBOK:
  11293. case SC_OKTOBERFEST:
  11294. case SC_DRESSUP:
  11295. if( !vd )
  11296. break;
  11297. clif_changelook(bl,LOOK_BASE,vd->class_);
  11298. clif_changelook(bl,LOOK_WEAPON,0);
  11299. clif_changelook(bl,LOOK_SHIELD,0);
  11300. clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color);
  11301. clif_changelook(bl,LOOK_BODY2,0);
  11302. break;
  11303. case SC_STONE:
  11304. case SC_STONEWAIT:
  11305. case SC_POISON:
  11306. case SC_DPOISON:
  11307. case SC_BLEEDING:
  11308. case SC_BURNING:
  11309. case SC_TOXIN:
  11310. tick_time = tick;
  11311. tick = tick_time + max(val4, 0);
  11312. break;
  11313. case SC_DEATHHURT:
  11314. if (val3 == 1)
  11315. break;
  11316. tick_time = tick;
  11317. tick = tick_time + max(val4, 0);
  11318. [[fallthrough]];
  11319. case SC_MAGICMUSHROOM:
  11320. case SC_PYREXIA:
  11321. case SC_LEECHESEND:
  11322. if (val3 == 0)
  11323. break;
  11324. tick_time = tick;
  11325. tick = tick_time + max(val4, 0);
  11326. break;
  11327. case SC_SWORDCLAN:
  11328. case SC_ARCWANDCLAN:
  11329. case SC_GOLDENMACECLAN:
  11330. case SC_CROSSBOWCLAN:
  11331. case SC_JUMPINGCLAN:
  11332. case SC_CLAN_INFO:
  11333. // If the player still has a clan status, but was removed from his clan
  11334. if( sd && sd->status.clan_id == 0 ){
  11335. return 0;
  11336. }
  11337. break;
  11338. case SC_SERVANTWEAPON:
  11339. case SC_ABYSSFORCEWEAPON:
  11340. tick_time = tick;
  11341. tick = tick_time + max(val4, 0);
  11342. break;
  11343. }
  11344. if (sd && current_equip_combo_pos > 0 && tick == INFINITE_TICK) {
  11345. ShowWarning("sc_start: Item combo of item #%u contains an INFINITE_TICK duration. Skipping bonus.\n", sd->inventory_data[pc_checkequip(sd, current_equip_combo_pos)]->nameid);
  11346. return 0;
  11347. }
  11348. /* [Ind] */
  11349. if (scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC]) {
  11350. int32 dval1 = 0, dval2 = 0, dval3 = 0;
  11351. switch (type) {
  11352. case SC_ALL_RIDING:
  11353. dval1 = 1;
  11354. break;
  11355. case SC_CLAN_INFO:
  11356. dval1 = val1;
  11357. dval2 = val2;
  11358. dval3 = val3;
  11359. break;
  11360. default: /* All others: just copy val1 */
  11361. dval1 = val1;
  11362. break;
  11363. }
  11364. status_display_add(bl,type,dval1,dval2,dval3);
  11365. }
  11366. //SC that force player to stand if is sitting
  11367. if (scdb->flag[SCF_SETSTAND] && sd && pc_issit(sd))
  11368. pc_setstand(sd, true);
  11369. //SC that make stop attacking [LuzZza]
  11370. if (scdb->flag[SCF_STOPATTACKING])
  11371. unit_stop_attack(bl);
  11372. //SC that make stop walking
  11373. if (scdb->flag[SCF_STOPWALKING]) {
  11374. switch (type) {
  11375. case SC__MANHOLE:
  11376. if (bl->type == BL_PC || !unit_blown_immune(bl,0x1))
  11377. unit_stop_walking( bl, USW_FIXPOS );
  11378. break;
  11379. case SC_VACUUM_EXTREME:
  11380. if (bl->type != BL_PC && unit_blown_immune(bl, 0x1) == UB_KNOCKABLE) {
  11381. unit_stop_walking( bl, USW_FIXPOS );
  11382. unit_stop_attack(bl);
  11383. }
  11384. break;
  11385. case SC_FREEZE:
  11386. case SC_STUN:
  11387. case SC_STONE:
  11388. if (sc->getSCE(SC_DANCING)) {
  11389. unit_stop_walking( bl, USW_FIXPOS );
  11390. status_change_end(bl, SC_DANCING);
  11391. }
  11392. break;
  11393. default:
  11394. if (!unit_blown_immune(bl,0x1))
  11395. unit_stop_walking( bl, USW_FIXPOS );
  11396. break;
  11397. }
  11398. }
  11399. //SC that make stop casting
  11400. if (battle_config.sc_castcancel&bl->type && scdb->flag[SCF_STOPCASTING])
  11401. unit_skillcastcancel(bl,0);
  11402. if(scdb->opt1 != OPT1_NONE) sc->opt1 = scdb->opt1;
  11403. sc->opt2 |= scdb->opt2;
  11404. sc->opt3 |= scdb->opt3;
  11405. sc->option |= scdb->look;
  11406. std::bitset<SCF_MAX> opt_flag = scdb->flag;
  11407. uint16 disable_opt_flag = false;
  11408. switch(type) {
  11409. case SC_DANCING:
  11410. if ((val1&0xFFFF) == CG_MOONLIT)
  11411. sc->opt3 |= OPT3_MOONLIT;
  11412. break;
  11413. }
  11414. // On Aegis, when turning on a status change, first goes the option packet, then the sc packet.
  11415. if (!disable_opt_flag && (opt_flag[SCF_SENDOPTION] || opt_flag[SCF_ONTOUCH] || opt_flag[SCF_UNITMOVE] || opt_flag[SCF_NONPLAYER] || opt_flag[SCF_SENDLOOK])) {
  11416. clif_changeoption(bl);
  11417. if(sd && opt_flag[SCF_SENDLOOK]) {
  11418. clif_changelook(bl,LOOK_BASE,vd->class_);
  11419. clif_changelook(bl,LOOK_WEAPON,0);
  11420. clif_changelook(bl,LOOK_SHIELD,0);
  11421. clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color);
  11422. }
  11423. }
  11424. if (calc_flag[SCB_DYE]) { // Reset DYE color
  11425. if (vd && vd->cloth_color) {
  11426. val4 = vd->cloth_color;
  11427. clif_changelook(bl,LOOK_CLOTHES_COLOR,0);
  11428. }
  11429. calc_flag.reset(SCB_DYE);
  11430. }
  11431. /*if (calc_flag[SCB_BODY])// Might be needed in the future. [Rytech]
  11432. { //Reset body style
  11433. if (vd && vd->body_style)
  11434. {
  11435. val4 = vd->body_style;
  11436. clif_changelook(bl,LOOK_BODY2,0);
  11437. }
  11438. calc_flag.reset(SCB_BODY);
  11439. }*/
  11440. if (!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED && scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC])) {
  11441. int32 status_icon = scdb->icon;
  11442. #if PACKETVER < 20151104
  11443. if (status_icon == EFST_WEAPONPROPERTY)
  11444. status_icon = EFST_ATTACK_PROPERTY_NOTHING + val1; // Assign status icon for older clients
  11445. #endif
  11446. clif_status_change(bl, status_icon, 1, tick, scdb->flag[SCF_SENDVAL1] ? val1 : 1, scdb->flag[SCF_SENDVAL2] ? val2 : 0, scdb->flag[SCF_SENDVAL3] ? val3 : 0);
  11447. }
  11448. // Used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first.
  11449. if( tick_time )
  11450. tick = tick_time;
  11451. // Don't trust the previous sce assignment, in case the SC ended somewhere between there and here.
  11452. if((sce=sc->getSCE(type))) { // reuse old sc
  11453. if( sce->timer != INVALID_TIMER )
  11454. delete_timer(sce->timer, status_change_timer);
  11455. sc_isnew = false;
  11456. } else { // New sc
  11457. ++(sc->count);
  11458. sce = sc->createSCE(type);
  11459. }
  11460. sce->val1 = val1;
  11461. sce->val2 = val2;
  11462. sce->val3 = val3;
  11463. sce->val4 = val4;
  11464. if (tick >= 0)
  11465. sce->timer = add_timer(gettick() + tick, status_change_timer, bl->id, type);
  11466. else
  11467. sce->timer = INVALID_TIMER; // Infinite duration
  11468. if (calc_flag.any()) {
  11469. if (sd != nullptr) {
  11470. switch(type) {
  11471. // Statuses that adjust HP/SP and heal after starting
  11472. case SC_BERSERK:
  11473. case SC_MERC_HPUP:
  11474. case SC_MERC_SPUP:
  11475. // Status needs to be updated immediately and not at the end of the damage
  11476. case SC_EXTREMITYFIST:
  11477. status_calc_bl_(bl, calc_flag, SCO_FORCE);
  11478. break;
  11479. default:
  11480. if (!sd->state.connect_new)
  11481. status_calc_bl_(bl, calc_flag);
  11482. break;
  11483. }
  11484. } else
  11485. status_calc_bl_(bl, calc_flag);
  11486. }
  11487. // Non-zero
  11488. if (sc_isnew && scdb->state.any())
  11489. status_calc_state(bl, sc, scdb->state, true);
  11490. if (sd != nullptr && sd->pd != nullptr)
  11491. pet_sc_check(sd, type); // Skotlex: Pet Status Effect Healing
  11492. // 1st thing to execute when loading status
  11493. switch (type) {
  11494. case SC_BERSERK:
  11495. if (!(sce->val2)) { // Don't heal if already set
  11496. status_heal(bl, status->max_hp, 0, 1); // Do not use percent_heal as this healing must override BERSERK's block.
  11497. status_set_sp(bl, 0, 0); // Damage all SP
  11498. }
  11499. sce->val2 = 5 * status->max_hp / 100;
  11500. break;
  11501. case SC_RUN:
  11502. {
  11503. struct unit_data *ud = unit_bl2ud(bl);
  11504. if( ud )
  11505. ud->state.running = unit_run(bl, nullptr, SC_RUN);
  11506. }
  11507. break;
  11508. case SC_BOSSMAPINFO:
  11509. if( sd == nullptr ){
  11510. return 0;
  11511. }else{
  11512. mob_data* boss_md = map_id2boss( sce->val1 );
  11513. if( boss_md == nullptr ){
  11514. return 0;
  11515. }
  11516. // Not on same map anymore
  11517. if( sd->bl.m != boss_md->bl.m ){
  11518. return 0;
  11519. // Boss is alive
  11520. }else if( boss_md->bl.prev != nullptr ){
  11521. sce->val2 = 0;
  11522. clif_bossmapinfo( *sd, boss_md, BOSS_INFO_ALIVE_WITHMSG );
  11523. // Boss is dead
  11524. }else if( boss_md->spawn_timer != INVALID_TIMER ){
  11525. sce->val2 = 1;
  11526. clif_bossmapinfo( *sd, boss_md, BOSS_INFO_DEAD );
  11527. }
  11528. }
  11529. break;
  11530. case SC_FULL_THROTTLE:
  11531. case SC_MERC_HPUP:
  11532. status_percent_heal(bl, 100, 0); // Recover Full HP
  11533. break;
  11534. case SC_MERC_SPUP:
  11535. status_percent_heal(bl, 0, 100); // Recover Full SP
  11536. break;
  11537. case SC_WUGDASH:
  11538. {
  11539. struct unit_data *ud = unit_bl2ud(bl);
  11540. if( ud )
  11541. ud->state.running = unit_run(bl, sd, SC_WUGDASH);
  11542. }
  11543. break;
  11544. case SC_COMBO:
  11545. switch(sce->val1) {
  11546. case TK_STORMKICK:
  11547. skill_combo_toggle_inf(bl, TK_JUMPKICK, 0);
  11548. clif_skill_nodamage(bl,*bl,TK_READYSTORM,1);
  11549. break;
  11550. case TK_DOWNKICK:
  11551. skill_combo_toggle_inf(bl, TK_JUMPKICK, 0);
  11552. clif_skill_nodamage(bl,*bl,TK_READYDOWN,1);
  11553. break;
  11554. case TK_TURNKICK:
  11555. skill_combo_toggle_inf(bl, TK_JUMPKICK, 0);
  11556. clif_skill_nodamage(bl,*bl,TK_READYTURN,1);
  11557. break;
  11558. case TK_COUNTER:
  11559. skill_combo_toggle_inf(bl, TK_JUMPKICK, 0);
  11560. clif_skill_nodamage(bl,*bl,TK_READYCOUNTER,1);
  11561. break;
  11562. default: // Rest just toggle inf to enable autotarget
  11563. skill_combo_toggle_inf(bl,sce->val1,INF_SELF_SKILL);
  11564. break;
  11565. }
  11566. break;
  11567. case SC_C_MARKER:
  11568. //Send mini-map, don't wait for first timer triggered
  11569. if (src->type == BL_PC) {
  11570. clif_crimson_marker(*(map_session_data *)(src), *bl, false);
  11571. }
  11572. break;
  11573. case SC_ITEMSCRIPT: // Shows Buff Icons
  11574. if (sd)
  11575. clif_status_change(bl, (efst_type)val2, 1, tick, 0, 0, 0);
  11576. break;
  11577. case SC_GVG_GIANT:
  11578. case SC_GVG_GOLEM:
  11579. case SC_GVG_STUN:
  11580. case SC_GVG_STONE:
  11581. case SC_GVG_FREEZ:
  11582. case SC_GVG_SLEEP:
  11583. case SC_GVG_CURSE:
  11584. case SC_GVG_SILENCE:
  11585. case SC_GVG_BLIND:
  11586. if (val1 || val2)
  11587. status_zap(bl, val1 ? val1 : 0, val2 ? val2 : 0);
  11588. break;
  11589. }
  11590. if( opt_flag[SCF_ONTOUCH] && sd && !sd->npc_ontouch_.empty() )
  11591. npc_touchnext_areanpc(sd,false); // Run OnTouch_ on next char in range
  11592. return 1;
  11593. }
  11594. /**
  11595. * End all statuses except those listed
  11596. * TODO: May be useful for dispel instead resetting a list there
  11597. * @param src: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
  11598. * @param type: Changes behaviour of the function
  11599. * 0: PC killed -> Place here statuses that do not dispel on death.
  11600. * 1: If for some reason status_change_end decides to still keep the status when quitting.
  11601. * 2: Do clif_changeoption()
  11602. * 3: Do not remove some permanent/time-independent effects
  11603. * @return 1: Success 0: Fail
  11604. */
  11605. int32 status_change_clear(struct block_list* bl, int32 type)
  11606. {
  11607. status_change* sc;
  11608. sc = status_get_sc(bl);
  11609. if (!sc)
  11610. return 0;
  11611. // Cleaning all extras vars
  11612. sc->comet_x = 0;
  11613. sc->comet_y = 0;
  11614. #ifndef RENEWAL
  11615. sc->sg_counter = 0;
  11616. #endif
  11617. if (sc->empty())
  11618. return 0;
  11619. for (const auto &it : status_db) {
  11620. sc_type status = static_cast<sc_type>(it.first);
  11621. if (!sc->getSCE(status))
  11622. continue;
  11623. if (type == 0) { // Type 0: PC killed
  11624. if (it.second->flag[SCF_NOREMOVEONDEAD]) {
  11625. switch (status) {
  11626. case SC_ELEMENTALCHANGE: // Only when its Holy or Dark that it doesn't dispell on death
  11627. if (sc->getSCE(status)->val2 != ELE_HOLY && sc->getSCE(status)->val2 != ELE_DARK)
  11628. break;
  11629. default:
  11630. continue;
  11631. }
  11632. }
  11633. }
  11634. if (type == 3 && it.second->flag[SCF_NOCLEARBUFF])
  11635. continue;
  11636. status_change_end(bl, status);
  11637. if( type == 1 && sc->getSCE(status) ) { // If for some reason status_change_end decides to still keep the status when quitting. [Skotlex]
  11638. (sc->count)--;
  11639. if (sc->getSCE(status)->timer != INVALID_TIMER)
  11640. delete_timer(sc->getSCE(status)->timer, status_change_timer);
  11641. sc->deleteSCE(status);
  11642. }
  11643. }
  11644. sc->opt1 = 0;
  11645. sc->opt2 = 0;
  11646. sc->opt3 = 0;
  11647. if( type == 0 || type == 2 )
  11648. clif_changeoption(bl);
  11649. return 1;
  11650. }
  11651. /**
  11652. * End a specific status after checking
  11653. * @param bl: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
  11654. * @param type: Status change (SC_*)
  11655. * @param tid: Timer
  11656. * @param file: Used for dancing save
  11657. * @param line: Used for dancing save
  11658. * @return 1: Success 0: Fail
  11659. */
  11660. int32 status_change_end(struct block_list* bl, enum sc_type type, int32 tid)
  11661. {
  11662. map_session_data *sd;
  11663. status_change *sc;
  11664. struct status_change_entry *sce;
  11665. struct view_data *vd;
  11666. std::shared_ptr<s_status_change_db> scdb = status_db.find(type);
  11667. nullpo_ret(bl);
  11668. sc = status_get_sc(bl);
  11669. if(!sc || !(sce = sc->getSCE(type)) || !scdb)
  11670. return 0;
  11671. sd = BL_CAST(BL_PC,bl);
  11672. if (sce->timer != tid && tid != INVALID_TIMER)
  11673. return 0;
  11674. if (tid == INVALID_TIMER) {
  11675. if (type == SC_ENDURE && sce->val4)
  11676. // Do not end infinite endure.
  11677. return 0;
  11678. if (type == SC_SPIDERWEB) {
  11679. //Delete the unit group first to expire found in the status change
  11680. std::shared_ptr<s_skill_unit_group> group, group2;
  11681. t_tick tick = gettick();
  11682. int32 pos = 1;
  11683. if (sce->val2)
  11684. if (!(group = skill_id2group(sce->val2)))
  11685. sce->val2 = 0;
  11686. if (sce->val3) {
  11687. if (!(group2 = skill_id2group(sce->val3)))
  11688. sce->val3 = 0;
  11689. else if (!group || ((group->limit - DIFF_TICK(tick, group->tick)) > (group2->limit - DIFF_TICK(tick, group2->tick)))) {
  11690. group = group2;
  11691. pos = 2;
  11692. }
  11693. }
  11694. if (sce->val4) {
  11695. if (!(group2 = skill_id2group(sce->val4)))
  11696. sce->val4 = 0;
  11697. else if (!group || ((group->limit - DIFF_TICK(tick, group->tick)) > (group2->limit - DIFF_TICK(tick, group2->tick)))) {
  11698. group = group2;
  11699. pos = 3;
  11700. }
  11701. }
  11702. if (pos == 1)
  11703. sce->val2 = 0;
  11704. else if (pos == 2)
  11705. sce->val3 = 0;
  11706. else if (pos == 3)
  11707. sce->val4 = 0;
  11708. if (group)
  11709. skill_delunitgroup(group);
  11710. if (!status_isdead(*bl) && (sce->val2 || sce->val3 || sce->val4))
  11711. return 0; //Don't end the status change yet as there are still unit groups associated with it
  11712. }
  11713. if (sce->timer != INVALID_TIMER) // Could be a SC with infinite duration
  11714. delete_timer(sce->timer,status_change_timer);
  11715. }
  11716. (sc->count)--;
  11717. if (scdb->state.any())
  11718. status_calc_state(bl,sc,scdb->state,false);
  11719. sc->clearSCE(type);
  11720. if (scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC])
  11721. status_display_remove(bl,type);
  11722. vd = status_get_viewdata(bl);
  11723. std::bitset<SCB_MAX> calc_flag = scdb->calc_flag;
  11724. status_data* status = status_get_status_data(*bl);
  11725. switch(type) {
  11726. case SC_KEEPING:
  11727. case SC_BARRIER: {
  11728. unit_data *ud = unit_bl2ud(bl);
  11729. if (ud)
  11730. ud->attackabletime = ud->canact_tick = ud->canmove_tick = gettick();
  11731. }
  11732. break;
  11733. case SC_GRANITIC_ARMOR:
  11734. {
  11735. int32 damage = status->max_hp*sce->val3/100;
  11736. if(status->hp < damage) // to not kill him
  11737. damage = status->hp-1;
  11738. status_damage(nullptr,bl,damage,0,0,1,0);
  11739. }
  11740. break;
  11741. case SC_RUN:
  11742. {
  11743. struct unit_data *ud = unit_bl2ud(bl);
  11744. bool begin_spurt = true;
  11745. // Note: this int64 value is stored in two separate int32 variables (FIXME)
  11746. t_tick starttick = (t_tick)sce->val3&0x00000000ffffffffLL;
  11747. starttick |= ((t_tick)sce->val4<<32)&0xffffffff00000000LL;
  11748. if (ud) {
  11749. if(!ud->state.running)
  11750. begin_spurt = false;
  11751. ud->state.running = 0;
  11752. if (ud->walktimer != INVALID_TIMER)
  11753. unit_stop_walking( bl, USW_FIXPOS );
  11754. }
  11755. if (begin_spurt && sce->val1 >= 7 &&
  11756. DIFF_TICK(gettick(), starttick) <= 1000 &&
  11757. (!sd || (sd->weapontype1 == W_FIST && sd->weapontype2 == W_FIST))
  11758. )
  11759. sc_start(bl,bl,SC_SPURT,100,sce->val1,skill_get_time2(scdb->skill_id, sce->val1));
  11760. }
  11761. break;
  11762. case SC_AUTOBERSERK:
  11763. if (sc->getSCE(SC_PROVOKE) && sc->getSCE(SC_PROVOKE)->val4 == 1)
  11764. status_change_end(bl, SC_PROVOKE);
  11765. break;
  11766. case SC_ENDURE:
  11767. case SC_DEFENDER:
  11768. case SC_REFLECTSHIELD:
  11769. case SC_AUTOGUARD:
  11770. {
  11771. map_session_data *tsd;
  11772. if( bl->type == BL_PC ) { // Clear Status from others
  11773. int32 i;
  11774. for( i = 0; i < MAX_DEVOTION; i++ ) {
  11775. if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) && tsd->sc.getSCE(type) )
  11776. status_change_end(&tsd->bl, type);
  11777. }
  11778. }
  11779. else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag ) { // Clear Status from Master
  11780. tsd = ((TBL_MER*)bl)->master;
  11781. if( tsd && tsd->sc.getSCE(type) )
  11782. status_change_end(&tsd->bl, type);
  11783. }
  11784. }
  11785. break;
  11786. case SC_DEVOTION:
  11787. {
  11788. struct block_list *d_bl = map_id2bl(sce->val1);
  11789. if( d_bl ) {
  11790. if( d_bl->type == BL_PC )
  11791. ((TBL_PC*)d_bl)->devotion[sce->val2] = 0;
  11792. else if( d_bl->type == BL_MER )
  11793. ((TBL_MER*)d_bl)->devotion_flag = 0;
  11794. clif_devotion(d_bl, nullptr);
  11795. }
  11796. }
  11797. break;
  11798. case SC_FLASHKICK: {
  11799. map_session_data *tsd;
  11800. if (!(tsd = map_id2sd(sce->val1)))
  11801. break;
  11802. tsd->stellar_mark[sce->val2] = 0;
  11803. }
  11804. break;
  11805. case SC_SOULUNITY: {
  11806. map_session_data *tsd;
  11807. if (!(tsd = map_id2sd(sce->val2)))
  11808. break;
  11809. tsd->united_soul[sce->val3] = 0;
  11810. }
  11811. break;
  11812. case SC_BLADESTOP:
  11813. if(sce->val4) {
  11814. int32 tid2 = sce->val4; //stop the status for the other guy of bladestop as well
  11815. struct block_list *tbl = map_id2bl(tid2);
  11816. status_change *tsc = status_get_sc(tbl);
  11817. sce->val4 = 0;
  11818. if(tbl && tsc && tsc->getSCE(SC_BLADESTOP)) {
  11819. tsc->getSCE(SC_BLADESTOP)->val4 = 0;
  11820. status_change_end(tbl, SC_BLADESTOP);
  11821. }
  11822. clif_bladestop( *bl, tid2, false );
  11823. }
  11824. break;
  11825. case SC_DANCING:
  11826. {
  11827. map_session_data *dsd;
  11828. if(sce->val4 && sce->val4 != BCT_SELF && (dsd=map_id2sd(sce->val4))) { // End status on partner as well
  11829. status_change_entry *dsc = dsd->sc.getSCE(SC_DANCING);
  11830. if(dsc) {
  11831. // This will prevent recursive loops.
  11832. dsc->val2 = 0;
  11833. dsc->val4 = BCT_SELF;
  11834. status_change_end(&dsd->bl, SC_DANCING);
  11835. }
  11836. }
  11837. if(sce->val2) { // Erase associated land skill
  11838. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val2);
  11839. sce->val2 = 0;
  11840. if (group)
  11841. skill_delunitgroup(group);
  11842. }
  11843. if((sce->val1&0xFFFF) == CG_MOONLIT)
  11844. clif_status_change(bl,EFST_MOON,0,0,0,0,0);
  11845. }
  11846. break;
  11847. case SC_NOCHAT:
  11848. if (sd && sd->status.manner < 0 && tid != INVALID_TIMER)
  11849. sd->status.manner = 0;
  11850. if (sd && tid == INVALID_TIMER) {
  11851. clif_changemanner( *sd );
  11852. clif_updatestatus(*sd,SP_MANNER);
  11853. }
  11854. break;
  11855. case SC_SPLASHER:
  11856. case SC_ROSEBLOSSOM:
  11857. {
  11858. struct block_list *src=map_id2bl(sce->val3);
  11859. if(src && tid != INVALID_TIMER)
  11860. skill_castend_damage_id(src, bl, sce->val2, sce->val1, gettick(), SD_LEVEL );
  11861. }
  11862. break;
  11863. case SC_CLOSECONFINE2:
  11864. {
  11865. struct block_list *src = sce->val2?map_id2bl(sce->val2):nullptr;
  11866. status_change *sc2 = src?status_get_sc(src):nullptr;
  11867. if (src && sc2 && sc2->getSCE(SC_CLOSECONFINE)) {
  11868. // If status was already ended, do nothing.
  11869. // Decrease count
  11870. if (--(sc2->getSCE(SC_CLOSECONFINE)->val1) <= 0) // No more holds, free him up.
  11871. status_change_end(src, SC_CLOSECONFINE);
  11872. }
  11873. }
  11874. [[fallthrough]];
  11875. case SC_CLOSECONFINE:
  11876. if (sce->val2 > 0) {
  11877. // Caster has been unlocked... nearby chars need to be unlocked.
  11878. int32 range = 1
  11879. + skill_get_range2(bl, scdb->skill_id, sce->val1, true)
  11880. + skill_get_range2(bl, TF_BACKSLIDING, 1, true); // Since most people use this to escape the hold....
  11881. map_foreachinallarea(status_change_timer_sub,
  11882. bl->m, bl->x-range, bl->y-range, bl->x+range,bl->y+range,BL_CHAR,bl,sce,type,gettick());
  11883. }
  11884. break;
  11885. case SC_COMBO:
  11886. skill_combo_toggle_inf(bl,sce->val1,0);
  11887. break;
  11888. case SC_MARIONETTE:
  11889. case SC_MARIONETTE2: // Marionette target
  11890. if (sce->val1) { // Check for partner and end their marionette status as well
  11891. enum sc_type type2 = (type == SC_MARIONETTE) ? SC_MARIONETTE2 : SC_MARIONETTE;
  11892. struct block_list *pbl = map_id2bl(sce->val1);
  11893. status_change* sc2 = pbl?status_get_sc(pbl):nullptr;
  11894. if (sc2 && sc2->getSCE(type2)) {
  11895. sc2->getSCE(type2)->val1 = 0;
  11896. status_change_end(pbl, type2);
  11897. }
  11898. }
  11899. break;
  11900. case SC_CONCENTRATION:
  11901. if (sc->getSCE(SC_ENDURE) && !sc->getSCE(SC_ENDURE)->val4)
  11902. status_change_end(bl, SC_ENDURE);
  11903. break;
  11904. case SC_BERSERK:
  11905. if(status->hp > 200 && sc && sc->getSCE(SC__BLOODYLUST)) {
  11906. status_percent_heal(bl, 100, 0);
  11907. status_change_end(bl, SC__BLOODYLUST);
  11908. } else if (status->hp > 100 && sce->val2) // If val2 is removed, no HP penalty (dispelled?) [Skotlex]
  11909. status_set_hp(bl, 100, 0);
  11910. if(sc->getSCE(SC_ENDURE) && sc->getSCE(SC_ENDURE)->val4) {
  11911. sc->getSCE(SC_ENDURE)->val4 = 0;
  11912. status_change_end(bl, SC_ENDURE);
  11913. }
  11914. sc_start4(bl, bl, SC_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill_get_time(LK_BERSERK, sce->val1));
  11915. break;
  11916. case SC_GOSPEL:
  11917. if (sce->val3) { // Clear the group.
  11918. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val3);
  11919. sce->val3 = 0;
  11920. if (group)
  11921. skill_delunitgroup(group);
  11922. }
  11923. break;
  11924. #ifndef RENEWAL
  11925. case SC_HERMODE:
  11926. if(sce->val3 == BCT_SELF)
  11927. skill_clear_unitgroup(bl);
  11928. break;
  11929. case SC_BASILICA: // Clear the skill area. [Skotlex]
  11930. if (sce->val3 && sce->val4 == bl->id) {
  11931. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val3);
  11932. sce->val3 = 0;
  11933. if (group)
  11934. skill_delunitgroup(group);
  11935. }
  11936. break;
  11937. #endif
  11938. case SC_TRICKDEAD:
  11939. if (vd) vd->dead_sit = 0;
  11940. break;
  11941. case SC_WARM:
  11942. case SC__MANHOLE:
  11943. case SC_BANDING:
  11944. case SC_LEADERSHIP:
  11945. case SC_GLORYWOUNDS:
  11946. case SC_SOULCOLD:
  11947. case SC_HAWKEYES:
  11948. if (sce->val4) { // Clear the group.
  11949. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val4);
  11950. sce->val4 = 0;
  11951. if( group ) // Might have been cleared before status ended, e.g. land protector
  11952. skill_delunitgroup(group);
  11953. }
  11954. break;
  11955. case SC_JAILED:
  11956. if(sd && sd->mapindex == sce->val2)
  11957. pc_setpos(sd,(uint16)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT);
  11958. break; // Guess hes not in jail :P
  11959. case SC_CHANGE:
  11960. if (tid == INVALID_TIMER)
  11961. break;
  11962. // "lose almost all their HP and SP" on natural expiration.
  11963. status_set_hp(bl, 10, 0);
  11964. status_set_sp(bl, 10, 0);
  11965. break;
  11966. case SC_AUTOTRADE:
  11967. if (tid == INVALID_TIMER)
  11968. break;
  11969. // Vending is not automatically closed for autovenders
  11970. vending_closevending(sd);
  11971. map_quit(sd);
  11972. // Because map_quit calls status_change_end with tid -1
  11973. // from here it's not neccesary to continue
  11974. return 1;
  11975. break;
  11976. case SC_STOP:
  11977. if( sce->val2 ) {
  11978. struct block_list* tbl = map_id2bl(sce->val2);
  11979. sce->val2 = 0;
  11980. if( tbl && (sc = status_get_sc(tbl)) && sc->getSCE(SC_STOP) && sc->getSCE(SC_STOP)->val2 == bl->id )
  11981. status_change_end(tbl, SC_STOP);
  11982. }
  11983. break;
  11984. case SC_TENSIONRELAX:
  11985. if (sc && (sc->getSCE(SC_WEIGHT50) || sc->getSCE(SC_WEIGHT90)))
  11986. status_get_regen_data(bl)->state.overweight = 1; // Add the overweight flag back
  11987. break;
  11988. case SC_MONSTER_TRANSFORM:
  11989. case SC_ACTIVE_MONSTER_TRANSFORM:
  11990. if (sce->val2)
  11991. status_change_end(bl, (sc_type)sce->val2);
  11992. break;
  11993. /* 3rd Stuff */
  11994. case SC_MILLENNIUMSHIELD:
  11995. clif_millenniumshield( *bl, 0 );
  11996. break;
  11997. case SC_HALLUCINATIONWALK:
  11998. sc_start(bl,bl,SC_HALLUCINATIONWALK_POSTDELAY,100,sce->val1,skill_get_time2(GC_HALLUCINATIONWALK,sce->val1));
  11999. break;
  12000. case SC_WHITEIMPRISON:
  12001. {
  12002. struct block_list* src = map_id2bl(sce->val2);
  12003. if( tid == -1 || !src)
  12004. break; // Terminated by Damage
  12005. status_fix_damage(src,bl,400*sce->val1,clif_damage(*bl,*bl,gettick(),0,0,400*sce->val1,0,DMG_NORMAL,0,false),WL_WHITEIMPRISON);
  12006. }
  12007. break;
  12008. case SC_WUGDASH:
  12009. {
  12010. struct unit_data *ud = unit_bl2ud(bl);
  12011. if (ud) {
  12012. ud->state.running = 0;
  12013. if (ud->walktimer != INVALID_TIMER)
  12014. unit_stop_walking( bl, USW_FIXPOS );
  12015. }
  12016. }
  12017. break;
  12018. case SC__SHADOWFORM:
  12019. {
  12020. map_session_data *s_sd = map_id2sd(sce->val2);
  12021. if (s_sd) s_sd->shadowform_id = 0;
  12022. }
  12023. break;
  12024. case SC_SATURDAYNIGHTFEVER: // Sit down force of Saturday Night Fever has the duration of only 3 seconds.
  12025. sc_start(bl, bl,SC_SITDOWN_FORCE,100,sce->val1,skill_get_time2(WM_SATURDAY_NIGHT_FEVER,sce->val1));
  12026. break;
  12027. case SC_NEUTRALBARRIER_MASTER:
  12028. case SC_STEALTHFIELD_MASTER:
  12029. if( sce->val2 ) {
  12030. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val2);
  12031. sce->val2 = 0;
  12032. if( group ) // Might have been cleared before status ended, e.g. land protector
  12033. skill_delunitgroup(group);
  12034. }
  12035. break;
  12036. case SC_CURSEDCIRCLE_ATKER:
  12037. if( sce->val2 ) // Used the default area size cause there is a chance the caster could knock back and can't clear the target.
  12038. map_foreachinallrange(status_change_timer_sub, bl, AREA_SIZE + 3, BL_CHAR, bl, sce, SC_CURSEDCIRCLE_TARGET, gettick());
  12039. break;
  12040. case SC_RAISINGDRAGON:
  12041. if( sd && !pc_isdead(sd) ) {
  12042. int32 i = min(sd->spiritball,5);
  12043. pc_delspiritball(sd, sd->spiritball, 0);
  12044. status_change_end(bl, SC_EXPLOSIONSPIRITS);
  12045. while( i > 0 ) {
  12046. pc_addspiritball(sd, skill_get_time(MO_CALLSPIRITS, pc_checkskill(sd,MO_CALLSPIRITS)), 5);
  12047. --i;
  12048. }
  12049. }
  12050. break;
  12051. case SC_CURSEDCIRCLE_TARGET:
  12052. {
  12053. struct block_list *src = map_id2bl(sce->val2);
  12054. status_change *sc2 = status_get_sc(src);
  12055. if( sc2 && sc2->getSCE(SC_CURSEDCIRCLE_ATKER) && --(sc2->getSCE(SC_CURSEDCIRCLE_ATKER)->val2) == 0 ) {
  12056. clif_bladestop( *bl, sce->val2, false );
  12057. status_change_end(src, SC_CURSEDCIRCLE_ATKER);
  12058. }
  12059. }
  12060. break;
  12061. case SC_SITDOWN_FORCE:
  12062. case SC_BANANA_BOMB_SITDOWN:
  12063. if( sd && pc_issit(sd) && pc_setstand(sd, false) )
  12064. skill_sit(sd, false);
  12065. break;
  12066. case SC_KYOUGAKU:
  12067. clif_status_load(bl, EFST_KYOUGAKU, 0); // Avoid client crash
  12068. clif_status_load(bl, EFST_ACTIVE_MONSTER_TRANSFORM, 0);
  12069. break;
  12070. case SC_INTRAVISION:
  12071. calc_flag = status_db.getSCB_ALL(); // Required for overlapping
  12072. break;
  12073. case SC_GRAVITYCONTROL:
  12074. status_fix_damage(bl, bl, sce->val2, clif_damage(*bl, *bl, gettick(), 0, 0, sce->val2, 0, DMG_NORMAL, 0, false), 0);
  12075. clif_specialeffect(bl, 223, AREA);
  12076. clif_specialeffect(bl, 330, AREA);
  12077. break;
  12078. case SC_OVERED_BOOST:
  12079. switch (bl->type) {
  12080. case BL_HOM: {
  12081. struct homun_data *hd = BL_CAST(BL_HOM,bl);
  12082. if( hd )
  12083. hd->homunculus.hunger = max(1,hd->homunculus.hunger - 50);
  12084. }
  12085. break;
  12086. case BL_PC:
  12087. status_zap(bl,0,status_get_max_sp(bl) / 2);
  12088. break;
  12089. }
  12090. break;
  12091. case SC_FULL_THROTTLE: {
  12092. int32 sec = skill_get_time2(scdb->skill_id, sce->val1);
  12093. clif_status_change(bl, EFST_DEC_AGI, 1, sec, 0, 0, 0);
  12094. sc_start(bl, bl, SC_REBOUND, 100, sce->val1, sec);
  12095. }
  12096. break;
  12097. case SC_REBOUND:
  12098. clif_status_load(bl, EFST_DEC_AGI, 0);
  12099. break;
  12100. case SC_ITEMSCRIPT: // Removes Buff Icons
  12101. if (sd)
  12102. clif_status_load(bl, (enum efst_type)sce->val2, 0);
  12103. break;
  12104. case SC_C_MARKER:
  12105. {
  12106. // Remove mark data from caster
  12107. map_session_data *caster = map_id2sd(sce->val2);
  12108. uint8 i = 0;
  12109. if (!caster)
  12110. break;
  12111. ARR_FIND(0,MAX_SKILL_CRIMSON_MARKER,i,caster->c_marker[i] == bl->id);
  12112. if (i < MAX_SKILL_CRIMSON_MARKER) {
  12113. caster->c_marker[i] = 0;
  12114. clif_crimson_marker( *caster, *bl, true );
  12115. }
  12116. }
  12117. break;
  12118. case SC_H_MINE:
  12119. // Only drop the material from target if expired naturally
  12120. if( tid != INVALID_TIMER ){
  12121. map_session_data *caster = nullptr;
  12122. if (status_isdead(*bl) || !(caster = map_id2sd(sce->val2)))
  12123. break;
  12124. std::shared_ptr<s_skill_db> skill = skill_db.find(RL_H_MINE);
  12125. if (!item_db.exists(skill->require.itemid[0]))
  12126. break;
  12127. struct item it = {};
  12128. it.nameid = skill->require.itemid[0];
  12129. it.amount = max(skill->require.amount[0],1);
  12130. it.identify = 1;
  12131. map_addflooritem(&it, it.amount, bl->m,bl->x, bl->y, caster->status.char_id, 0, 0, 4, 0);
  12132. }
  12133. break;
  12134. case SC_VACUUM_EXTREME:
  12135. ///< !CHECKME: Seems on official, there's delay before same target can be vacuumed in same area again [Cydh]
  12136. sc_start2(bl, bl, SC_VACUUM_EXTREME_POSTDELAY, 100, sce->val1, sce->val2, skill_get_time2(SO_VACUUM_EXTREME,sce->val1));
  12137. break;
  12138. case SC_DIMENSION1:
  12139. case SC_DIMENSION2:
  12140. if (sd)
  12141. pc_delspiritball(sd, 1, 0);
  12142. break;
  12143. case SC_SOULENERGY:
  12144. if (sd != nullptr && sd->soulball > 0) {
  12145. // When SC_SOULENERGY ends, removes all soulball if SC_SOULCOLLECT is active otherwise 1
  12146. if (sc->getSCE(SC_SOULCOLLECT))
  12147. pc_delsoulball( *sd, sd->soulball );
  12148. else
  12149. pc_delsoulball( *sd, 1 );
  12150. }
  12151. break;
  12152. case SC_MADOGEAR:
  12153. status_db.removeByStatusFlag(bl, { SCF_MADOENDCANCEL });
  12154. if (sd)
  12155. pc_bonus_script_clear(sd, BSF_REM_ON_MADOGEAR);
  12156. break;
  12157. case SC_HOMUN_TIME:
  12158. if (sd && hom_is_active(sd->hd))
  12159. hom_vaporize(sd, HOM_ST_REST);
  12160. break;
  12161. case SC_SERVANT_SIGN: {
  12162. map_session_data *tsd = map_id2sd(sce->val1);
  12163. if( tsd != nullptr )
  12164. tsd->servant_sign[sce->val2] = 0;
  12165. }
  12166. break;
  12167. case SC_SOUNDBLEND: {
  12168. block_list *src = map_id2bl(sce->val2);
  12169. if (src && tid != INVALID_TIMER)
  12170. skill_castend_damage_id(src, bl, TR_SOUNDBLEND, sce->val1, gettick(), SD_LEVEL|SD_ANIMATION);
  12171. }
  12172. break;
  12173. case SC_SERVANTWEAPON:
  12174. if( sd ){
  12175. pc_delservantball( *sd, sd->servantball );
  12176. }
  12177. break;
  12178. case SC_ABYSSFORCEWEAPON:
  12179. if( sd ){
  12180. pc_delabyssball( *sd, sd->abyssball );
  12181. }
  12182. break;
  12183. case SC_BLESSING_OF_M_CREATURES:
  12184. sc_start(bl,bl, SC_BLESSING_OF_M_C_DEBUFF, 100, 1, skill_get_time2(SH_BLESSING_OF_MYSTICAL_CREATURES, 1));
  12185. status_percent_change(bl,bl,0, 0, -100,1);
  12186. break;
  12187. }
  12188. // End statuses found in the EndOnEnd list.
  12189. if (!scdb->endonend.empty()) {
  12190. for (const auto &it : scdb->endonend) {
  12191. status_change_end(bl, it);
  12192. }
  12193. }
  12194. // Reset the options as needed
  12195. std::bitset<SCF_MAX> opt_flag = scdb->flag;
  12196. bool disable_opt_flag = false;
  12197. switch (type) {
  12198. case SC_DANCING:
  12199. if ((sce->val1&0xFFFF) == CG_MOONLIT)
  12200. sc->opt3 &= ~OPT3_MOONLIT;
  12201. break;
  12202. case SC_INCATKRATE: // Simulated Explosion spirits effect.
  12203. if (bl->type != BL_MOB) {
  12204. disable_opt_flag = true;
  12205. break;
  12206. }
  12207. break;
  12208. }
  12209. if (scdb->opt1)
  12210. sc->opt1 = OPT1_NONE;
  12211. if (scdb->opt2)
  12212. sc->opt2 &= ~scdb->opt2;
  12213. if (scdb->opt3)
  12214. sc->opt3 &= ~scdb->opt3;
  12215. if (scdb->look)
  12216. sc->option &= ~scdb->look;
  12217. if (calc_flag[SCB_DYE]) { // Restore DYE color
  12218. if (vd && !vd->cloth_color && sce->val4)
  12219. clif_changelook(bl,LOOK_CLOTHES_COLOR,sce->val4);
  12220. calc_flag.reset(SCB_DYE);
  12221. }
  12222. /*if (calc_flag[SCB_BODY])// Might be needed in the future. [Rytech]
  12223. { //Restore body style
  12224. if (vd && !vd->body_style && sce->val4)
  12225. clif_changelook(bl,LOOK_BODY2,sce->val4);
  12226. calc_flag.reset(SCB_BODY);
  12227. }*/
  12228. // On Aegis, when turning off a status change, first goes the sc packet, then the option packet.
  12229. int32 status_icon = scdb->icon;
  12230. #if PACKETVER < 20151104
  12231. if (status_icon == EFST_WEAPONPROPERTY)
  12232. status_icon = EFST_ATTACK_PROPERTY_NOTHING + sce->val1; // Assign status icon for older clients
  12233. #endif
  12234. clif_status_change(bl,status_icon,0,0,0,0,0);
  12235. if( opt_flag[SCF_NONPLAYER] ) // bugreport:681
  12236. clif_changeoption2( *bl );
  12237. else if (!disable_opt_flag && (opt_flag[SCF_SENDOPTION] || opt_flag[SCF_ONTOUCH] || opt_flag[SCF_UNITMOVE] || opt_flag[SCF_NONPLAYER] || opt_flag[SCF_SENDLOOK])) {
  12238. clif_changeoption(bl);
  12239. if (sd && opt_flag[SCF_SENDLOOK]) {
  12240. clif_changelook(bl,LOOK_BASE,sd->vd.class_);
  12241. clif_get_weapon_view(sd,&sd->vd.weapon,&sd->vd.shield);
  12242. clif_changelook(bl,LOOK_WEAPON,sd->vd.weapon);
  12243. clif_changelook(bl,LOOK_SHIELD,sd->vd.shield);
  12244. clif_changelook(bl,LOOK_CLOTHES_COLOR,cap_value(sd->status.clothes_color,0,battle_config.max_cloth_color));
  12245. clif_changelook(bl,LOOK_BODY2,cap_value(sd->status.body,0,battle_config.max_body_style));
  12246. }
  12247. }
  12248. if (calc_flag.any()) {
  12249. #ifndef RENEWAL
  12250. if (type == SC_MAGICPOWER) {
  12251. //If Mystical Amplification ends, MATK is immediately recalculated
  12252. status_calc_bl_(bl, calc_flag, SCO_FORCE);
  12253. } else
  12254. #endif
  12255. status_calc_bl_(bl, calc_flag);
  12256. }
  12257. if(opt_flag[SCF_UNITMOVE]) // Out of hiding, invoke on place.
  12258. skill_unit_move(bl,gettick(),1);
  12259. if(opt_flag[SCF_ONTOUCH] && sd && !sd->state.warping && map_getcell(bl->m,bl->x,bl->y,CELL_CHKNPC))
  12260. npc_touch_area_allnpc(sd,bl->m,bl->x,bl->y); // Trigger on-touch event.
  12261. // Needed to be here to make sure OPT1_STONEWAIT has been cleared from the target (only on natural expiration of the stone wait timer)
  12262. if (type == SC_STONEWAIT && tid != INVALID_TIMER)
  12263. status_change_start(bl, bl, SC_STONE, 100, sce->val1, sce->val2, 0, 0, sce->val3, SCSTART_NOAVOID);
  12264. ers_free(sc_data_ers, sce);
  12265. return 1;
  12266. }
  12267. /**
  12268. * Resets timers for statuses
  12269. * Used with reoccurring status effects, such as dropping SP every 5 seconds
  12270. * @param tid: Timer ID
  12271. * @param tick: How long before next call
  12272. * @param id: ID of character
  12273. * @param data: Information passed through the timer call
  12274. * @return 1: Success 0: Fail
  12275. */
  12276. TIMER_FUNC(status_change_timer){
  12277. enum sc_type type = (sc_type)data;
  12278. struct block_list *bl;
  12279. map_session_data *sd;
  12280. int32 interval = status_get_sc_interval(type);
  12281. bool dounlock = false;
  12282. bl = map_id2bl(id);
  12283. if(!bl) {
  12284. ShowDebug("status_change_timer: Null pointer id: %d data: %" PRIdPTR "\n", id, data);
  12285. return 0;
  12286. }
  12287. status_change * const sc = status_get_sc(bl);
  12288. if(!sc) {
  12289. ShowDebug("status_change_timer: Null pointer id: %d data: %" PRIdPTR " bl-type: %d\n", id, data, bl->type);
  12290. return 0;
  12291. }
  12292. struct status_change_entry * const sce = sc->getSCE(type);
  12293. if(!sce) {
  12294. ShowDebug("status_change_timer: Null pointer id: %d data: %" PRIdPTR " bl-type: %d\n", id, data, bl->type);
  12295. return 0;
  12296. }
  12297. if( sce->timer != tid ) {
  12298. ShowError("status_change_timer: Mismatch for type %d: %d != %d (bl id %d)\n",type,tid,sce->timer, bl->id);
  12299. return 0;
  12300. }
  12301. const status_data* status = status_get_status_data(*bl);
  12302. sd = BL_CAST(BL_PC, bl);
  12303. std::function<void (t_tick)> sc_timer_next = [&sce, &bl, &data](t_tick t) {
  12304. sce->timer = add_timer(t, status_change_timer, bl->id, data);
  12305. };
  12306. switch(type) {
  12307. case SC_MAXIMIZEPOWER:
  12308. case SC_CLOAKING:
  12309. if(!status_charge(bl, 0, 1))
  12310. break; // Not enough SP to continue.
  12311. sc_timer_next(sce->val2+tick);
  12312. return 0;
  12313. case SC_CHASEWALK:
  12314. if(!status_charge(bl, 0, sce->val4))
  12315. break; // Not enough SP to continue.
  12316. if (!sc->getSCE(SC_CHASEWALK2)) {
  12317. sc_start(bl,bl, SC_CHASEWALK2,100,1<<(sce->val1-1),
  12318. (t_tick)(sc->getSCE(SC_SPIRIT) && sc->getSCE(SC_SPIRIT)->val2 == SL_ROGUE?10:1) // SL bonus -> x10 duration
  12319. *skill_get_time2(status_db.getSkill(type),sce->val1));
  12320. }
  12321. sc_timer_next(sce->val2+tick);
  12322. return 0;
  12323. break;
  12324. case SC_HIDING:
  12325. if(--(sce->val2)>0) {
  12326. if(sce->val2 % sce->val4 == 0 && !status_charge(bl, 0, 1))
  12327. break; // Fail if it's time to substract SP and there isn't.
  12328. sc_timer_next(1000+tick);
  12329. return 0;
  12330. }
  12331. break;
  12332. case SC_SIGHT:
  12333. case SC_RUWACH:
  12334. case SC_SIGHTBLASTER:
  12335. if(type == SC_SIGHTBLASTER) {
  12336. //Restore trap immunity
  12337. if(sce->val4%2)
  12338. sce->val4--;
  12339. map_foreachinallrange( status_change_timer_sub, bl, sce->val3, BL_CHAR|BL_SKILL, bl, sce, type, tick);
  12340. } else {
  12341. map_foreachinallrange( status_change_timer_sub, bl, sce->val3, BL_CHAR, bl, sce, type, tick);
  12342. skill_reveal_trap_inarea(bl, sce->val3, bl->x, bl->y);
  12343. }
  12344. if( --(sce->val2)>0 ) {
  12345. sce->val4 += 20; // Use for Shadow Form 2 seconds checking.
  12346. sc_timer_next(20+tick);
  12347. return 0;
  12348. }
  12349. break;
  12350. case SC_PROVOKE:
  12351. if(sce->val4) { // Auto-provoke (it is ended in status_heal)
  12352. sc_timer_next(1000*60+tick);
  12353. return 0;
  12354. }
  12355. break;
  12356. case SC_STONE:
  12357. if (sce->val4 >= 0 && status->hp > status->max_hp / 4)
  12358. status_percent_damage(nullptr, bl, -1, 0, false);
  12359. break;
  12360. case SC_POISON:
  12361. case SC_DPOISON:
  12362. if (sce->val4 >= 0 && !sc->getSCE(SC_SLOWPOISON)) {
  12363. uint32 damage = 0;
  12364. if (sd)
  12365. damage = (type == SC_DPOISON) ? 2 + status->max_hp / 50 : 2 + status->max_hp * 3 / 200;
  12366. else
  12367. damage = (type == SC_DPOISON) ? 2 + status->max_hp / 100 : 2 + status->max_hp / 200;
  12368. if (status->hp > umax(status->max_hp / 4, damage)) // Stop damaging after 25% HP left.
  12369. status_zap(bl, damage, 0);
  12370. }
  12371. break;
  12372. case SC_BLEEDING:
  12373. if (sce->val4 >= 0) {
  12374. int64 damage = rnd() % 600 + 200;
  12375. if (!sd && damage >= status->hp)
  12376. damage = status->hp - 1; // No deadly damage for monsters
  12377. map_freeblock_lock();
  12378. dounlock = true;
  12379. status_zap(bl, damage, 0);
  12380. }
  12381. break;
  12382. case SC_BURNING:
  12383. if (sce->val4 >= 0) {
  12384. int64 damage = 1000 + (3 * status->max_hp) / 100; // Deals fixed (1000 + 3%*MaxHP)
  12385. map_freeblock_lock();
  12386. dounlock = true;
  12387. status_fix_damage(bl, bl, damage, clif_damage(*bl, *bl, tick, 0, 1, damage, 1, DMG_NORMAL, 0, false),0);
  12388. }
  12389. break;
  12390. case SC_TOXIN:
  12391. if (sce->val4 >= 0) { // Damage is every 10 seconds including 3%sp drain.
  12392. if (sce->val3 == 1) { // Target
  12393. map_freeblock_lock();
  12394. dounlock = true;
  12395. status_damage(bl, bl, 1, status->max_sp * 3 / 100, clif_damage(*bl, *bl, tick, status->amotion, status->dmotion + 500, 1, 1, DMG_NORMAL, 0, false), 0, 0);
  12396. } else { // Caster
  12397. interval = 1000; // Assign here since status_get_sc_internval() contains the target interval.
  12398. if (status->sp < status->max_sp)
  12399. status_heal(bl, 0, (int32)status->max_sp * 1 / 100, 1);
  12400. }
  12401. }
  12402. break;
  12403. case SC_MAGICMUSHROOM:
  12404. if (sce->val4 >= 0) {
  12405. bool flag = 0;
  12406. int64 damage = status->max_hp * 3 / 100;
  12407. if (status->hp <= damage)
  12408. damage = status->hp - 1; // Cannot Kill
  12409. if (damage > 0) { // 3% Damage each 4 seconds
  12410. map_freeblock_lock();
  12411. status_zap(bl, damage, 0);
  12412. flag = !sc->getSCE(type); // Killed? Should not
  12413. map_freeblock_unlock();
  12414. }
  12415. if (!flag) { // Random Skill Cast
  12416. if (magic_mushroom_db.size() > 0 && sd && !pc_issit(sd)) { // Can't cast if sit
  12417. auto mushroom_spell = magic_mushroom_db.begin();
  12418. std::advance(mushroom_spell, rnd() % magic_mushroom_db.size());
  12419. uint16 mushroom_skill_id = mushroom_spell->second->skill_id;
  12420. if (!skill_get_index(mushroom_skill_id))
  12421. break;
  12422. unit_stop_attack(bl);
  12423. unit_skillcastcancel(bl, 1);
  12424. switch (skill_get_casttype(mushroom_skill_id)) { // Magic Mushroom skills are buffs or area damage
  12425. case CAST_GROUND:
  12426. skill_castend_pos2(bl, bl->x, bl->y, mushroom_skill_id, 1, tick, 0);
  12427. break;
  12428. case CAST_NODAMAGE:
  12429. skill_castend_nodamage_id(bl, bl, mushroom_skill_id, 1, tick, 0);
  12430. break;
  12431. case CAST_DAMAGE:
  12432. skill_castend_damage_id(bl, bl, mushroom_skill_id, 1, tick, 0);
  12433. break;
  12434. }
  12435. }
  12436. clif_emotion(bl, ET_SMILE);
  12437. }
  12438. }
  12439. break;
  12440. case SC_PYREXIA:
  12441. if (sce->val4 >= 0) {
  12442. map_freeblock_lock();
  12443. dounlock = true;
  12444. status_fix_damage(bl, bl, 100, clif_damage(*bl, *bl, tick, status->amotion, status->dmotion + 500, 100, 1, DMG_NORMAL, 0, false),0);
  12445. unit_skillcastcancel(bl, 2);
  12446. }
  12447. break;
  12448. case SC_LEECHESEND:
  12449. if (sce->val4 >= 0) {
  12450. int64 damage = status->vit * (sce->val1 - 3) + (int32)status->max_hp / 100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100)
  12451. map_freeblock_lock();
  12452. dounlock = true;
  12453. status_fix_damage(bl, bl, damage, clif_damage(*bl, *bl, tick, status->amotion, status->dmotion + 500, damage, 1, DMG_NORMAL, 0, false),0);
  12454. unit_skillcastcancel(bl, 2);
  12455. }
  12456. break;
  12457. case SC_DEATHHURT:
  12458. if (sce->val4 >= 0) {
  12459. if (status->hp < status->max_hp)
  12460. status_heal(bl, (int32)status->max_hp * 1 / 100, 0, 1);
  12461. }
  12462. break;
  12463. case SC_TENSIONRELAX:
  12464. if(status->max_hp > status->hp && --(sce->val3) >= 0) {
  12465. sc_timer_next(10000 + tick);
  12466. return 0;
  12467. }
  12468. break;
  12469. case SC_KNOWLEDGE:
  12470. if (!sd) break;
  12471. if(bl->m == sd->feel_map[0].m ||
  12472. bl->m == sd->feel_map[1].m ||
  12473. bl->m == sd->feel_map[2].m)
  12474. { // Timeout will be handled by pc_setpos
  12475. sce->timer = INVALID_TIMER;
  12476. return 0;
  12477. }
  12478. break;
  12479. case SC_GRADUAL_GRAVITY:
  12480. if (sce->val4 >= 0) {
  12481. status_zap(bl, status->max_hp * sce->val2 / 100, 0);
  12482. }
  12483. break;
  12484. case SC_BOSSMAPINFO:
  12485. if( sd && sce->val4 >= 0 ){
  12486. mob_data* boss_md = map_id2boss( sce->val1 );
  12487. if( boss_md == nullptr ){
  12488. sce->val4 = 0;
  12489. break;
  12490. }
  12491. // Not on same map anymore
  12492. if( sd->bl.m != boss_md->bl.m ){
  12493. sce->val4 = 0;
  12494. break;
  12495. // Boss is alive - Update X, Y on minimap
  12496. }else if( boss_md->bl.prev != nullptr ){
  12497. sce->val2 = 0;
  12498. clif_bossmapinfo( *sd, boss_md, BOSS_INFO_ALIVE );
  12499. // Boss is dead
  12500. }else if( boss_md->spawn_timer != INVALID_TIMER && sce->val2 == 0 ){
  12501. sce->val2 = 1;
  12502. clif_bossmapinfo( *sd, boss_md, BOSS_INFO_DEAD );
  12503. }
  12504. }
  12505. break;
  12506. case SC_DANCING: // SP consumption by time of dancing skills
  12507. {
  12508. int32 s = 0;
  12509. int32 sp = 1;
  12510. if (--sce->val3 <= 0)
  12511. break;
  12512. switch(sce->val1&0xFFFF) {
  12513. #ifndef RENEWAL
  12514. case BD_RICHMANKIM:
  12515. case BD_DRUMBATTLEFIELD:
  12516. case BD_RINGNIBELUNGEN:
  12517. case BD_SIEGFRIED:
  12518. case BA_DISSONANCE:
  12519. case BA_ASSASSINCROSS:
  12520. case DC_UGLYDANCE:
  12521. s=3;
  12522. break;
  12523. case BD_LULLABY:
  12524. case BD_ETERNALCHAOS:
  12525. case BD_ROKISWEIL:
  12526. case DC_FORTUNEKISS:
  12527. s=4;
  12528. break;
  12529. case CG_HERMODE:
  12530. case BD_INTOABYSS:
  12531. case BA_WHISTLE:
  12532. case DC_HUMMING:
  12533. case BA_POEMBRAGI:
  12534. case DC_SERVICEFORYOU:
  12535. s=5;
  12536. break;
  12537. case BA_APPLEIDUN:
  12538. s=6;
  12539. break;
  12540. #endif
  12541. case CG_MOONLIT:
  12542. // Moonlit's cost is 4sp*skill_lv [Skotlex]
  12543. sp= 4*(sce->val1>>16);
  12544. // Upkeep is also every 10 secs.
  12545. #ifndef RENEWAL
  12546. [[fallthrough]];
  12547. case DC_DONTFORGETME:
  12548. #endif
  12549. s=10;
  12550. break;
  12551. }
  12552. if( s != 0 && sce->val3 % s == 0 ) {
  12553. #ifndef RENEWAL
  12554. if (sc->getSCE(SC_LONGING))
  12555. sp*= 3;
  12556. #endif
  12557. if (!status_charge(bl, 0, sp))
  12558. break;
  12559. }
  12560. sc_timer_next(1000+tick);
  12561. return 0;
  12562. }
  12563. break;
  12564. case SC_BERSERK:
  12565. // 5% every 10 seconds [DracoRPG]
  12566. if( --( sce->val3 ) > 0 && status_charge(bl, sce->val2, 0) && status->hp > 100 ) {
  12567. sc_timer_next(sce->val4+tick);
  12568. return 0;
  12569. }
  12570. break;
  12571. case SC_NOCHAT:
  12572. if(sd) {
  12573. sd->status.manner++;
  12574. clif_changemanner( *sd );
  12575. clif_updatestatus(*sd,SP_MANNER);
  12576. if (sd->status.manner < 0) { // Every 60 seconds your manner goes up by 1 until it gets back to 0.
  12577. sc_timer_next(60000+tick);
  12578. return 0;
  12579. }
  12580. }
  12581. break;
  12582. case SC_SPLASHER:
  12583. // Custom Venom Splasher countdown timer
  12584. // if (sce->val4 % 1000 == 0) {
  12585. // char timer[10];
  12586. // snprintf (timer, 10, "%d", sce->val4/1000);
  12587. // clif_message(bl, timer);
  12588. // }
  12589. if((sce->val4 -= 500) > 0) {
  12590. sc_timer_next(500 + tick);
  12591. return 0;
  12592. }
  12593. break;
  12594. case SC_MARIONETTE:
  12595. case SC_MARIONETTE2:
  12596. {
  12597. struct block_list *pbl = map_id2bl(sce->val1);
  12598. if( pbl && check_distance_bl(bl, pbl, 7) ) {
  12599. sc_timer_next(1000 + tick);
  12600. return 0;
  12601. }
  12602. }
  12603. break;
  12604. case SC_GOSPEL:
  12605. if(sce->val4 == BCT_SELF && --(sce->val2) > 0) {
  12606. int32 hp, sp;
  12607. hp = (sce->val1 > 5) ? 45 : 30;
  12608. sp = (sce->val1 > 5) ? 35 : 20;
  12609. if(!status_charge(bl, hp, sp))
  12610. break;
  12611. sc_timer_next(10000+tick);
  12612. return 0;
  12613. }
  12614. break;
  12615. case SC_JAILED:
  12616. if(sce->val1 == INT_MAX || --(sce->val1) > 0) {
  12617. sc_timer_next(60000+tick);
  12618. return 0;
  12619. }
  12620. break;
  12621. case SC_BLIND:
  12622. if(sc->getSCE(SC_FOGWALL)) { // Blind lasts forever while you are standing on the fog.
  12623. sc_timer_next(5000+tick);
  12624. return 0;
  12625. }
  12626. break;
  12627. case SC_ABUNDANCE:
  12628. if(--(sce->val4) > 0) {
  12629. status_heal(bl,0,60,0);
  12630. sc_timer_next(10000+tick);
  12631. }
  12632. break;
  12633. case SC_OBLIVIONCURSE:
  12634. if( --(sce->val4) >= 0 ) {
  12635. clif_emotion(bl,ET_QUESTION);
  12636. sc_timer_next(3000 + tick);
  12637. return 0;
  12638. }
  12639. break;
  12640. case SC_WEAPONBLOCKING:
  12641. if( --(sce->val4) >= 0 ) {
  12642. if( !status_charge(bl,0,3) )
  12643. break;
  12644. sc_timer_next(5000+tick);
  12645. return 0;
  12646. }
  12647. break;
  12648. case SC_CLOAKINGEXCEED:
  12649. if(!status_charge(bl,0,10-sce->val1))
  12650. break;
  12651. sc_timer_next(1000 + tick);
  12652. return 0;
  12653. case SC_RENOVATIO:
  12654. if( --(sce->val4) >= 0 ) {
  12655. int32 heal = status->max_hp * (sce->val1 + 4) / 100;
  12656. if( sc && sc->getSCE(SC_AKAITSUKI) && heal )
  12657. heal = ~heal + 1;
  12658. status_heal(bl, heal, 0, 3);
  12659. sc_timer_next(5000 + tick);
  12660. return 0;
  12661. }
  12662. break;
  12663. case SC_SPHERE_1:
  12664. case SC_SPHERE_2:
  12665. case SC_SPHERE_3:
  12666. case SC_SPHERE_4:
  12667. case SC_SPHERE_5:
  12668. if( --(sce->val4) >= 0 ) {
  12669. if( !status_charge(bl, 0, 1) )
  12670. break;
  12671. sc_timer_next(1000 + tick);
  12672. return 0;
  12673. }
  12674. break;
  12675. case SC_FREEZE_SP:
  12676. if( !status_charge(bl, 0, sce->val2) ) {
  12677. int32 i;
  12678. for(i = SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) // Also remove stored spell as well.
  12679. status_change_end(bl, (sc_type)i);
  12680. break;
  12681. }
  12682. sc_timer_next(10000 + tick);
  12683. return 0;
  12684. case SC_ELECTRICSHOCKER:
  12685. if( --(sce->val4) >= 0 ) {
  12686. status_charge(bl, 0, 5 * sce->val1 * status->max_sp / 100);
  12687. sc_timer_next(1000 + tick);
  12688. return 0;
  12689. }
  12690. break;
  12691. case SC_CAMOUFLAGE:
  12692. if (!status_charge(bl, 0, 7 - sce->val1))
  12693. break;
  12694. if (--sce->val4 >= 0)
  12695. sce->val3++;
  12696. sc_timer_next(1000 + tick);
  12697. return 0;
  12698. case SC__REPRODUCE:
  12699. if(!status_charge(bl, 0, 1))
  12700. break;
  12701. sc_timer_next(1000+tick);
  12702. return 0;
  12703. case SC__SHADOWFORM:
  12704. if( --(sce->val4) >= 0 ) {
  12705. if( !status_charge(bl, 0, 11 - sce->val1) )
  12706. break;
  12707. sc_timer_next(1000 + tick);
  12708. return 0;
  12709. }
  12710. break;
  12711. case SC__INVISIBILITY:
  12712. if( !status_charge(bl, 0, (12 - 2 * sce->val1) * status->max_sp / 100) ) // 6% - skill_lv.
  12713. break;
  12714. sc_timer_next(1000 + tick);
  12715. return 0;
  12716. case SC_STRIKING:
  12717. if( --(sce->val4) >= 0 ) {
  12718. if( !status_charge(bl,0, sce->val3 ) )
  12719. break;
  12720. sc_timer_next(1000 + tick);
  12721. return 0;
  12722. }
  12723. break;
  12724. case SC_WARMER: {
  12725. int32 hp = 0;
  12726. status_change *ssc = status_get_sc(map_id2bl(sce->val2));
  12727. if (ssc && ssc->getSCE(SC_HEATER_OPTION))
  12728. hp = status->max_hp * 3 * sce->val1 / 100;
  12729. else
  12730. hp = status->max_hp * sce->val1 / 100;
  12731. if (sc && sc->getSCE(SC_AKAITSUKI) && hp)
  12732. hp = ~hp + 1;
  12733. if (status->hp != status->max_hp)
  12734. status_heal(bl, hp, 0, 0);
  12735. sc_timer_next(3000 + tick);
  12736. return 0;
  12737. }
  12738. case SC_HELLS_PLANT:
  12739. if( sce->val4 >= 0 ){
  12740. skill_castend_damage_id( bl, bl, GN_HELLS_PLANT_ATK, sce->val1, tick, 0 );
  12741. }
  12742. break;
  12743. case SC_VOICEOFSIREN:
  12744. if( --(sce->val4) >= 0 ) {
  12745. clif_emotion(bl,ET_THROB);
  12746. sc_timer_next(2000 + tick);
  12747. return 0;
  12748. }
  12749. break;
  12750. case SC_DEEPSLEEP:
  12751. if( --(sce->val4) >= 0 ) { // Recovers 3% HP/SP every 2 seconds.
  12752. status_heal(bl, status->max_hp * 3 / 100, status->max_sp * 3 / 100, 2);
  12753. sc_timer_next(2000 + tick);
  12754. return 0;
  12755. }
  12756. break;
  12757. case SC_SATURDAYNIGHTFEVER:
  12758. // 1% HP/SP drain every val4 seconds [Jobbie]
  12759. if( --(sce->val3) >= 0 ) {
  12760. if( !status_charge(bl, status->hp / 100, status->sp / 100) )
  12761. break;
  12762. sc_timer_next(sce->val4+tick);
  12763. return 0;
  12764. }
  12765. break;
  12766. case SC_CRYSTALIZE:
  12767. if( --(sce->val4) >= 0 ) { // Drains 2% of HP and 1% of SP every seconds.
  12768. if (!status_charge(bl, status->max_hp * 2 / 100, status->max_sp / 100))
  12769. break;
  12770. sc_timer_next(1000 + tick);
  12771. return 0;
  12772. }
  12773. break;
  12774. case SC_FORCEOFVANGUARD:
  12775. if( !status_charge(bl,0,24 - 4 * sce->val1) )
  12776. break;
  12777. sc_timer_next(10000 + tick);
  12778. return 0;
  12779. case SC_BANDING:
  12780. if( status_charge(bl, 0, 7 - sce->val1) ) {
  12781. sce->val2 = (sd ? skill_banding_count(sd) : 1);
  12782. sc_timer_next(5000 + tick);
  12783. return 0;
  12784. }
  12785. break;
  12786. case SC_REFLECTDAMAGE:
  12787. if( --(sce->val4) > 0 ) {
  12788. if( !status_charge(bl,0,10) )
  12789. break;
  12790. sc_timer_next(1000 + tick);
  12791. return 0;
  12792. }
  12793. break;
  12794. case SC_OVERHEAT_LIMITPOINT:
  12795. if (--(sce->val1) >= 0) { // Cooling
  12796. if (sce->val2 == 0) { // Flag the overheat limit once it has been met.
  12797. static std::vector<int16> limit = { 150, 200, 280, 360, 450 };
  12798. uint16 skill_lv = (sd ? cap_value(pc_checkskill(sd, NC_MAINFRAME), 0, (uint16)(limit.size() - 1)) : 0);
  12799. if (sce->val1 > limit[skill_lv])
  12800. sce->val2 = 1;
  12801. } else {
  12802. status_change_end(bl, SC_OVERHEAT);
  12803. if (sce->val2 > 0)
  12804. sc_start(bl, bl, SC_OVERHEAT, 100, sce->val1, 975);
  12805. }
  12806. sc_timer_next(1000 + tick);
  12807. return 0;
  12808. }
  12809. break;
  12810. case SC_OVERHEAT: {
  12811. uint32 damage = status->max_hp / 100; // Suggestion 1% each second
  12812. if (damage >= status->hp)
  12813. damage = status->hp - 1; // Do not kill, just keep you with 1 hp minimum
  12814. map_freeblock_lock();
  12815. status_zap(bl, damage, 0);
  12816. sc_timer_next(975 + tick); // Tick is not 1000 to avoid desync with SC_OVERHEAT_LIMITPOINT.
  12817. map_freeblock_unlock();
  12818. return 0;
  12819. }
  12820. break;
  12821. case SC_MAGNETICFIELD:
  12822. if (--(sce->val4) >= 0) {
  12823. struct block_list *src = map_id2bl(sce->val2);
  12824. if (!src || (src && (status_isdead(*src) || src->m != bl->m)))
  12825. break;
  12826. map_freeblock_lock();
  12827. if (!status_charge(bl, 0, 50))
  12828. status_zap(bl, 0, status->sp);
  12829. if (sc->getSCE(type))
  12830. sc_timer_next(1000 + tick);
  12831. map_freeblock_unlock();
  12832. return 0;
  12833. }
  12834. break;
  12835. case SC_INSPIRATION:
  12836. if(--(sce->val4) >= 0) {
  12837. if (!status_charge(bl, status->max_hp * (35 - 5 * sce->val1) / 1000, status->max_sp * (45 - 5 * sce->val1) / 1000))
  12838. break;
  12839. sc_timer_next(5000+tick);
  12840. return 0;
  12841. }
  12842. break;
  12843. case SC_SHIELDSPELL_HP:
  12844. if( sce->val4 >= 0 && status->hp < status->max_hp ){
  12845. status_heal( bl, status->max_hp * sce->val2 / 100, 0, 1 );
  12846. }
  12847. break;
  12848. case SC_SHIELDSPELL_SP:
  12849. if( sce->val4 >= 0 && status->sp < status->max_sp ){
  12850. status_heal( bl, 0, status->max_sp * sce->val2 / 100, 1 );
  12851. }
  12852. break;
  12853. case SC_TROPIC:
  12854. case SC_CHILLY_AIR:
  12855. case SC_WILD_STORM:
  12856. case SC_UPHEAVAL:
  12857. case SC_HEATER:
  12858. case SC_COOLER:
  12859. case SC_BLAST:
  12860. case SC_CURSED_SOIL:
  12861. case SC_PYROTECHNIC:
  12862. case SC_AQUAPLAY:
  12863. case SC_GUST:
  12864. case SC_PETROLOGY:
  12865. case SC_CIRCLE_OF_FIRE:
  12866. case SC_FIRE_CLOAK:
  12867. case SC_WATER_DROP:
  12868. case SC_WATER_SCREEN:
  12869. case SC_WIND_CURTAIN:
  12870. case SC_WIND_STEP:
  12871. case SC_STONE_SHIELD:
  12872. case SC_SOLID_SKIN:
  12873. case SC_FLAMETECHNIC:
  12874. case SC_FLAMEARMOR:
  12875. case SC_COLD_FORCE:
  12876. case SC_CRYSTAL_ARMOR:
  12877. case SC_GRACE_BREEZE:
  12878. case SC_EYES_OF_STORM:
  12879. case SC_EARTH_CARE:
  12880. case SC_STRONG_PROTECTION:
  12881. case SC_DEEP_POISONING:
  12882. case SC_POISON_SHIELD:
  12883. if( !status_charge(bl,0,sce->val2) ) {
  12884. struct block_list *s_bl = battle_get_master(bl);
  12885. if (bl->type == BL_ELEM)
  12886. elemental_change_mode(BL_CAST(BL_ELEM, bl), EL_MODE_PASSIVE);
  12887. if( s_bl )
  12888. status_change_end(s_bl,static_cast<sc_type>(type+1));
  12889. status_change_end(bl,type);
  12890. break;
  12891. }
  12892. sc_timer_next(sce->val3 + tick);
  12893. return 0;
  12894. case SC_WATER_SCREEN_OPTION:
  12895. status_heal(bl,1000,0,2);
  12896. sc_timer_next(10000 + tick);
  12897. return 0;
  12898. case SC_TEARGAS:
  12899. if( --(sce->val4) >= 0 ) {
  12900. struct block_list *src = map_id2bl(sce->val3);
  12901. int32 damage = sce->val2;
  12902. map_freeblock_lock();
  12903. clif_damage(*bl, *bl, tick, 0, 0, damage, 1, DMG_MULTI_HIT_ENDURE, 0, false);
  12904. status_damage(src, bl, damage,0, 0, 1, 0);
  12905. if( sc->getSCE(type) ) {
  12906. sc_timer_next(2000 + tick);
  12907. }
  12908. map_freeblock_unlock();
  12909. return 0;
  12910. }
  12911. break;
  12912. case SC_TEARGAS_SOB:
  12913. if( --(sce->val4) >= 0 ) {
  12914. clif_emotion(bl, ET_CRY);
  12915. sc_timer_next(3000 + tick);
  12916. return 0;
  12917. }
  12918. break;
  12919. case SC_STOMACHACHE:
  12920. if( --(sce->val4) >= 0 ) {
  12921. status_charge(bl,0,sce->val2); // Reduce 8 every 10 seconds.
  12922. if( sd && !pc_issit(sd) ) { // Force to sit every 10 seconds.
  12923. pc_setsit(sd);
  12924. skill_sit(sd, true);
  12925. clif_sitting(*bl);
  12926. }
  12927. sc_timer_next(10000 + tick);
  12928. return 0;
  12929. }
  12930. break;
  12931. case SC_LEADERSHIP:
  12932. case SC_GLORYWOUNDS:
  12933. case SC_SOULCOLD:
  12934. case SC_HAWKEYES:
  12935. // They only end by status_change_end
  12936. sc_timer_next(600000 + tick);
  12937. return 0;
  12938. case SC_MEIKYOUSISUI:
  12939. if( --(sce->val4) >= 0 ) {
  12940. status_heal(bl, status->max_hp * sce->val2 / 100, status->max_sp * sce->val3 / 100, 0);
  12941. sc_timer_next(1000 + tick);
  12942. return 0;
  12943. }
  12944. break;
  12945. case SC_KAGEMUSYA:
  12946. if( --(sce->val4) >= 0 ) {
  12947. if(!status_charge(bl, 0, 1)) break;
  12948. sc_timer_next(1000+tick);
  12949. return 0;
  12950. }
  12951. break;
  12952. case SC_ANGRIFFS_MODUS:
  12953. if(--(sce->val4) >= 0) { // Drain hp/sp
  12954. if( !status_charge(bl,100,20) ) break;
  12955. sc_timer_next(1000+tick);
  12956. return 0;
  12957. }
  12958. break;
  12959. case SC_CBC:
  12960. if(--(sce->val4) >= 0) { // Drain hp/sp
  12961. int32 hp=0;
  12962. int32 sp = (status->max_sp * sce->val3) / 100;
  12963. if(bl->type == BL_MOB) hp = sp*10;
  12964. if( !status_charge(bl,hp,sp) )break;
  12965. sc_timer_next(1000+tick);
  12966. return 0;
  12967. }
  12968. break;
  12969. case SC_FULL_THROTTLE:
  12970. if( --(sce->val4) >= 0 ) {
  12971. status_percent_damage(bl, bl, 0, sce->val2, false);
  12972. sc_timer_next(1000 + tick);
  12973. return 0;
  12974. }
  12975. break;
  12976. case SC_REBOUND:
  12977. if( --(sce->val4) >= 0 ) {
  12978. clif_emotion(bl, ET_SWEAT);
  12979. sc_timer_next(2000 + tick);
  12980. return 0;
  12981. }
  12982. break;
  12983. case SC_KINGS_GRACE:
  12984. if( --(sce->val4) >= 0 ) {
  12985. status_percent_heal(bl, sce->val2, 0);
  12986. sc_timer_next(1000 + tick);
  12987. return 0;
  12988. }
  12989. break;
  12990. case SC_FRIGG_SONG:
  12991. if( --(sce->val4) >= 0 ) {
  12992. status_heal(bl, sce->val3, 0, 0);
  12993. sc_timer_next(1000 + tick);
  12994. return 0;
  12995. }
  12996. break;
  12997. case SC_C_MARKER:
  12998. if( --(sce->val4) >= 0 ) {
  12999. TBL_PC *caster = map_id2sd(sce->val2);
  13000. if (!caster || caster->bl.m != bl->m) //End the SC if caster isn't in same map
  13001. break;
  13002. sc_timer_next(1000 + tick);
  13003. clif_crimson_marker( *caster, *bl, false );
  13004. return 0;
  13005. }
  13006. break;
  13007. case SC_STEALTHFIELD_MASTER:
  13008. if (--(sce->val4) >= 0) {
  13009. if (!status_charge(bl, 0, status->max_sp * 3 / 100))
  13010. break;
  13011. sc_timer_next(sce->val3 + tick);
  13012. return 0;
  13013. }
  13014. break;
  13015. case SC_VACUUM_EXTREME:
  13016. if (sce->val4 > 0) {
  13017. // Only slide targets to center if they are standing still
  13018. if (unit_bl2ud(bl)->walktimer == INVALID_TIMER) {
  13019. uint16 x = sce->val3 >> 16, y = sce->val3 & 0xFFFF;
  13020. if (distance_xy(x, y, bl->x, bl->y) <= skill_get_unit_range(SO_VACUUM_EXTREME, sce->val1) && unit_movepos(bl, x, y, 0, false)) {
  13021. clif_slide(*bl, x, y);
  13022. clif_fixpos( *bl );
  13023. }
  13024. }
  13025. sc_timer_next(tick + sce->val4);
  13026. sce->val4 = 0;
  13027. }
  13028. break;
  13029. case SC_FIRE_INSIGNIA:
  13030. if (--(sce->val4) >= 0) {
  13031. if (status->def_ele == ELE_FIRE)
  13032. status_heal(bl, status->max_hp / 100, 0, 1);
  13033. else if (status->def_ele == ELE_EARTH)
  13034. status_zap(bl, status->max_hp / 100, 0);
  13035. sc_timer_next(5000 + tick);
  13036. return 0;
  13037. }
  13038. break;
  13039. case SC_WATER_INSIGNIA:
  13040. if (--(sce->val4) >= 0) {
  13041. if (status->def_ele == ELE_WATER)
  13042. status_heal(bl, status->max_hp / 100, 0, 1);
  13043. else if (status->def_ele == ELE_FIRE)
  13044. status_zap(bl, status->max_hp / 100, 0);
  13045. sc_timer_next(5000 + tick);
  13046. return 0;
  13047. }
  13048. break;
  13049. case SC_WIND_INSIGNIA:
  13050. if (--(sce->val4) >= 0) {
  13051. if (status->def_ele == ELE_WIND)
  13052. status_heal(bl, status->max_hp / 100, 0, 1);
  13053. else if (status->def_ele == ELE_WATER)
  13054. status_zap(bl, status->max_hp / 100, 0);
  13055. sc_timer_next(5000 + tick);
  13056. return 0;
  13057. }
  13058. break;
  13059. case SC_EARTH_INSIGNIA:
  13060. if (--(sce->val4) >= 0) {
  13061. if (status->def_ele == ELE_EARTH)
  13062. status_heal(bl, status->max_hp / 100, 0, 1);
  13063. else if (status->def_ele == ELE_WIND)
  13064. status_zap(bl, status->max_hp / 100, 0);
  13065. sc_timer_next(5000 + tick);
  13066. return 0;
  13067. }
  13068. break;
  13069. case SC_BITESCAR:
  13070. if (--(sce->val4) >= 0) {
  13071. status_percent_damage(bl, bl, -(sce->val2), 0, 0);
  13072. sc_timer_next(1000 + tick);
  13073. return 0;
  13074. }
  13075. break;
  13076. case SC_FRESHSHRIMP:
  13077. if (--(sce->val4) >= 0) {
  13078. status_heal(bl, sce->val2, 0, 2);
  13079. sc_timer_next((10000 - ((sce->val1 - 1) * 1000)) + tick);
  13080. return 0;
  13081. }
  13082. break;
  13083. case SC_NEWMOON:
  13084. if (--(sce->val4) >= 0) {
  13085. if (!status_charge(bl, 0, 1))
  13086. break;
  13087. sc_timer_next(1000 + tick);
  13088. return 0;
  13089. }
  13090. break;
  13091. case SC_CREATINGSTAR:
  13092. if (--(sce->val4) >= 0) { // Needed to check who the caster is and what AoE is giving the status.
  13093. struct block_list *star_caster = map_id2bl(sce->val2);
  13094. struct skill_unit *star_aoe = (struct skill_unit *)map_id2bl(sce->val3);
  13095. if (star_caster == nullptr || status_isdead(*star_caster) || star_caster->m != bl->m || star_aoe == nullptr)
  13096. break;
  13097. sc_timer_next(500 + tick);
  13098. // Attack after timer to prevent errors
  13099. skill_attack(BF_WEAPON, star_caster, &star_aoe->bl, bl, SJ_BOOKOFCREATINGSTAR, sce->val1, tick, 0);
  13100. return 0;
  13101. }
  13102. break;
  13103. case SC_SOULUNITY:
  13104. if (--(sce->val4) >= 0) { // Needed to check the caster's location for the range check.
  13105. struct block_list *unity_src = map_id2bl(sce->val2);
  13106. if (!unity_src || status_isdead(*unity_src) || unity_src->m != bl->m || !check_distance_bl(bl, unity_src, 11))
  13107. break;
  13108. status_heal(bl, 150 * sce->val1, 0, 2);
  13109. sc_timer_next(3000 + tick);
  13110. return 0;
  13111. }
  13112. break;
  13113. case SC_SOULCOLLECT:
  13114. pc_addsoulball( *sd, 1, sce->val2 );
  13115. sc_timer_next(sce->val3 + tick);
  13116. return 0;
  13117. case SC_HELPANGEL:
  13118. if (--(sce->val4) >= 0) {
  13119. status_heal(bl, 1000, 350, 0); // Heal amount not displayed
  13120. sc_timer_next(1000 + tick);
  13121. return 0;
  13122. }
  13123. break;
  13124. case SC_BURNT:
  13125. if( --(sce->val4) >= 0 ) {
  13126. int32 damage = 2000;
  13127. if( damage >= status->hp )
  13128. damage = status->hp - 1;
  13129. map_freeblock_lock();
  13130. status_zap(bl,damage,0);
  13131. if( sc->getSCE(type) ) {
  13132. sc_timer_next(1000 + tick);
  13133. }
  13134. map_freeblock_unlock();
  13135. return 0;
  13136. }
  13137. break;
  13138. case SC_MEDIALE:
  13139. if (--(sce->val4) >= 0) {
  13140. clif_specialeffect(bl, 1808, AREA);
  13141. skill_castend_nodamage_id(bl, bl, CD_MEDIALE_VOTUM, sce->val1, tick, 1);
  13142. sc_timer_next(2000 + tick);
  13143. return 0;
  13144. }
  13145. break;
  13146. case SC_DANCING_KNIFE:
  13147. if (--(sce->val4) >= 0) {
  13148. skill_castend_nodamage_id(bl, bl, SHC_DANCING_KNIFE, sce->val1, tick, 1);
  13149. sc_timer_next(300 + tick);
  13150. return 0;
  13151. }
  13152. break;
  13153. case SC_A_MACHINE:
  13154. if (--(sce->val4) >= 0) {
  13155. skill_castend_nodamage_id(bl, bl, MT_A_MACHINE, sce->val1, tick, 1);
  13156. sc_timer_next(1000 + tick);
  13157. return 0;
  13158. }
  13159. break;
  13160. case SC_SERVANTWEAPON:
  13161. if (sce->val4 >= 0) {
  13162. if( sd && sd->servantball < MAX_SERVANTBALL ){
  13163. pc_addservantball( *sd, MAX_SERVANTBALL );
  13164. }
  13165. interval = max(500, skill_get_time2(DK_SERVANTWEAPON, sce->val1));
  13166. map_freeblock_lock();
  13167. dounlock = true;
  13168. }
  13169. break;
  13170. case SC_ABYSSFORCEWEAPON:
  13171. if (sce->val4 >= 0) {
  13172. if( sd && sd->abyssball < MAX_ABYSSBALL ){
  13173. pc_addabyssball( *sd );
  13174. }
  13175. interval = max(500, skill_get_time2(ABC_FROM_THE_ABYSS, sce->val1));
  13176. map_freeblock_lock();
  13177. dounlock = true;
  13178. }
  13179. break;
  13180. case SC_KILLING_AURA:
  13181. if (sce->val4 >= 0)
  13182. skill_castend_damage_id( bl, bl, NPC_KILLING_AURA, sce->val1, tick, 0 );
  13183. break;
  13184. case SC_INTENSIVE_AIM:
  13185. if (!sc || !sc->getSCE(SC_INTENSIVE_AIM_COUNT))
  13186. sce->val4 = 0;
  13187. if (sce->val4 < 10) {
  13188. sce->val4++;
  13189. sc_start(bl, bl, SC_INTENSIVE_AIM_COUNT, 100, sce->val4, INFINITE_TICK);
  13190. }
  13191. sc_timer_next(500 + tick);
  13192. return 0;
  13193. case SC_TALISMAN_OF_PROTECTION:
  13194. if(--(sce->val4) >= 0){
  13195. // Get the original caster
  13196. map_session_data* ssd = map_id2sd( sce->val2 );
  13197. // If the caster is offline, dead, on another map or
  13198. // if the target is not a player or is in another party
  13199. if( ssd == nullptr || status_isdead( ssd->bl ) || ssd->bl.m != bl->m || sd == nullptr || ssd->status.party_id != sd->status.party_id ){
  13200. // End the status change
  13201. sce->val4 = 0;
  13202. break;
  13203. }
  13204. int32 hp = sc->getSCE(SC_TALISMAN_OF_PROTECTION)->val3;
  13205. status_heal( bl, hp, 0, 0, 0 );
  13206. clif_skill_nodamage( nullptr, *bl, AL_HEAL, hp );
  13207. sc_timer_next(3000 + tick);
  13208. return 0;
  13209. }
  13210. break;
  13211. case SC_KI_SUL_RAMPAGE:
  13212. if (--(sce->val4) >= 0) {
  13213. skill_castend_nodamage_id( bl, bl, SH_KI_SUL_RAMPAGE, sce->val1, tick, 1 );
  13214. sc_timer_next(1000 + tick);
  13215. return 0;
  13216. }
  13217. break;
  13218. case SC_STAR_BURST:
  13219. if (sce->val4 >= 0) {
  13220. block_list* src = map_id2bl( sce->val2 );
  13221. if( src != nullptr && tid != INVALID_TIMER ){
  13222. skill_unitsetting(src, SKE_STAR_BURST, sce->val1, bl->x, bl->y, 0);
  13223. }
  13224. }
  13225. break;
  13226. }
  13227. // If status has an interval and there is at least 100ms remaining time, wait for next interval
  13228. if(interval > 0 && sc->getSCE(type) && sce->val4 >= 100) {
  13229. sc_timer_next(min(sce->val4,interval)+tick);
  13230. sce->val4 -= interval;
  13231. if (dounlock)
  13232. map_freeblock_unlock();
  13233. return 0;
  13234. }
  13235. if (dounlock)
  13236. map_freeblock_unlock();
  13237. // Default for all non-handled control paths is to end the status
  13238. return status_change_end( bl,type,tid );
  13239. }
  13240. /**
  13241. * For each iteration of repetitive status
  13242. * @param bl: Object [PC|MOB|HOM|MER|ELEM]
  13243. * @param ap: va_list arguments (src, sce, type, tick)
  13244. */
  13245. int32 status_change_timer_sub(struct block_list* bl, va_list ap)
  13246. {
  13247. status_change* tsc;
  13248. struct block_list* src = va_arg(ap,struct block_list*);
  13249. struct status_change_entry* sce = va_arg(ap,struct status_change_entry*);
  13250. enum sc_type type = (sc_type)va_arg(ap,int32); // gcc: enum args get promoted to int32
  13251. t_tick tick = va_arg(ap,t_tick);
  13252. if (status_isdead(*bl))
  13253. return 0;
  13254. tsc = status_get_sc(bl);
  13255. switch( type ) {
  13256. case SC_SIGHT: // Reveal hidden ennemy on 3*3 range
  13257. case SC_CONCENTRATE:
  13258. status_change_end(bl, SC_HIDING);
  13259. status_change_end(bl, SC_CLOAKING);
  13260. status_change_end(bl, SC_CLOAKINGEXCEED);
  13261. status_change_end(bl, SC_CAMOUFLAGE);
  13262. status_change_end(bl, SC_NEWMOON);
  13263. if (tsc && tsc->getSCE(SC__SHADOWFORM) && (sce && sce->val4 > 0 && sce->val4%2000 == 0) && // For every 2 seconds do the checking
  13264. rnd()%100 < 100 - tsc->getSCE(SC__SHADOWFORM)->val1 * 10) // [100 - (Skill Level x 10)] %
  13265. status_change_end(bl, SC__SHADOWFORM);
  13266. break;
  13267. case SC_RUWACH: // Reveal hidden target and deal little dammages if enemy
  13268. if (tsc && (tsc->getSCE(SC_HIDING) || tsc->getSCE(SC_CLOAKING) ||
  13269. tsc->getSCE(SC_CAMOUFLAGE) || tsc->getSCE(SC_NEWMOON) || tsc->getSCE(SC_CLOAKINGEXCEED))) {
  13270. status_change_end(bl, SC_HIDING);
  13271. status_change_end(bl, SC_CLOAKING);
  13272. status_change_end(bl, SC_CAMOUFLAGE);
  13273. status_change_end(bl, SC_CLOAKINGEXCEED);
  13274. status_change_end(bl, SC_NEWMOON);
  13275. if(battle_check_target( src, bl, BCT_ENEMY ) > 0)
  13276. skill_attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0);
  13277. }
  13278. if (tsc && tsc->getSCE(SC__SHADOWFORM) && (sce && sce->val4 > 0 && sce->val4%2000 == 0) && // For every 2 seconds do the checking
  13279. rnd()%100 < 100 - tsc->getSCE(SC__SHADOWFORM)->val1 * 10 ) { // [100 - (Skill Level x 10)] %
  13280. status_change_end(bl, SC__SHADOWFORM);
  13281. if (battle_check_target(src, bl, BCT_ENEMY) > 0)
  13282. skill_attack(BF_MAGIC, src, src, bl, status_db.getSkill(type), 1, tick, 0);
  13283. }
  13284. break;
  13285. case SC_SIGHTBLASTER:
  13286. if (battle_check_target( src, bl, BCT_ENEMY ) > 0 &&
  13287. status_check_skilluse(src, bl, WZ_SIGHTBLASTER, 2))
  13288. {
  13289. if (sce) {
  13290. struct skill_unit *su = nullptr;
  13291. if(bl->type == BL_SKILL)
  13292. su = (struct skill_unit *)bl;
  13293. if (skill_attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,sce->val1,tick,0x1000000)
  13294. && (!su || !su->group || !skill_get_inf2(su->group->skill_id, INF2_ISTRAP))) { // The hit is not counted if it's against a trap
  13295. sce->val2 = 0; // This signals it to end.
  13296. } else if((bl->type&BL_SKILL) && sce->val4%2 == 0) {
  13297. //Remove trap immunity temporarily so it triggers if you still stand on it
  13298. sce->val4++;
  13299. }
  13300. }
  13301. }
  13302. break;
  13303. case SC_CLOSECONFINE:
  13304. // Lock char has released the hold on everyone...
  13305. if (tsc && tsc->getSCE(SC_CLOSECONFINE2) && tsc->getSCE(SC_CLOSECONFINE2)->val2 == src->id) {
  13306. tsc->getSCE(SC_CLOSECONFINE2)->val2 = 0;
  13307. status_change_end(bl, SC_CLOSECONFINE2);
  13308. }
  13309. break;
  13310. case SC_CURSEDCIRCLE_TARGET:
  13311. if( tsc && tsc->getSCE(SC_CURSEDCIRCLE_TARGET) && tsc->getSCE(SC_CURSEDCIRCLE_TARGET)->val2 == src->id ) {
  13312. clif_bladestop( *bl, tsc->getSCE(SC_CURSEDCIRCLE_TARGET)->val2, false );
  13313. status_change_end(bl, type);
  13314. }
  13315. break;
  13316. }
  13317. return 0;
  13318. }
  13319. /**
  13320. * Clears buffs/debuffs on an object
  13321. * @param bl: Object to clear [PC|MOB|HOM|MER|ELEM]
  13322. * @param type: Type to remove
  13323. * SCCB_BUFFS: Clear Buffs
  13324. * SCCB_DEBUFFS: Clear Debuffs
  13325. * SCCB_REFRESH: Clear specific debuffs through RK_REFRESH
  13326. * SCCB_CHEM_PROTECT: Clear AM_CP_ARMOR/HELM/SHIELD/WEAPON
  13327. * SCCB_LUXANIMA: Bonus Script removed through RK_LUXANIMA
  13328. */
  13329. void status_change_clear_buffs(struct block_list* bl, uint8 type)
  13330. {
  13331. status_change *sc= status_get_sc(bl);
  13332. if (sc == nullptr || sc->empty())
  13333. return;
  13334. //Clears buffs with specified flag and type
  13335. for (const auto &it : status_db) {
  13336. sc_type status = static_cast<sc_type>(it.first);
  13337. const std::bitset<SCF_MAX>& flag = it.second->flag;
  13338. bool end = false;
  13339. if (!sc->getSCE(status))
  13340. continue;
  13341. // Skip status with SCF_NOCLEARBUFF, no matter what
  13342. if (flag[SCF_NOCLEARBUFF])
  13343. continue;
  13344. // &SCCB_LUXANIMA : Cleared by RK_LUXANIMA and has the SCF_REMOVEONLUXANIMA flag
  13345. if ((type & SCCB_LUXANIMA) && flag[SCF_REMOVEONLUXANIMA])
  13346. end = true;
  13347. // &SCCB_CHEM_PROTECT : Clears AM_CP_ARMOR/HELP/SHIELD/WEAPON
  13348. else if ((type & SCCB_CHEM_PROTECT) && flag[SCF_REMOVECHEMICALPROTECT])
  13349. end = true;
  13350. // &SCCB_REFRESH : Cleared by RK_REFRESH and has the SCF_REMOVEONREFRESH flag
  13351. else if ((type & SCCB_REFRESH) && flag[SCF_REMOVEONREFRESH])
  13352. end = true;
  13353. // &SCCB_DEBUFFS : Clears debuffs
  13354. else if ((type & SCCB_DEBUFFS) && flag[SCF_DEBUFF])
  13355. end = true;
  13356. // &SCCB_BUFFS : Clears buffs - skip if it is a debuff
  13357. else if ((type & SCCB_BUFFS) && !flag[SCF_DEBUFF])
  13358. end = true;
  13359. // &SCCB_HERMODE : Cleared by CG_HERMODE and has the SCF_REMOVEONHERMODE flag
  13360. else if ((type & SCCB_HERMODE) && flag[SCF_REMOVEONHERMODE])
  13361. end = true;
  13362. if (status == SC_SATURDAYNIGHTFEVER || status == SC_BERSERK) // Mark to not lose HP
  13363. sc->getSCE(status)->val2 = 0;
  13364. if(end)
  13365. status_change_end(bl, status);
  13366. }
  13367. //Removes bonus_script
  13368. if (bl->type == BL_PC) {
  13369. uint32 i = 0;
  13370. if (type&SCCB_BUFFS) i |= BSF_REM_BUFF;
  13371. if (type&SCCB_DEBUFFS) i |= BSF_REM_DEBUFF;
  13372. if (type&SCCB_REFRESH) i |= BSF_REM_ON_REFRESH;
  13373. if (type&SCCB_LUXANIMA) i |= BSF_REM_ON_LUXANIMA;
  13374. pc_bonus_script_clear(BL_CAST(BL_PC,bl),i);
  13375. }
  13376. // Cleaning all extras vars
  13377. sc->comet_x = 0;
  13378. sc->comet_y = 0;
  13379. #ifndef RENEWAL
  13380. sc->sg_counter = 0;
  13381. #endif
  13382. return;
  13383. }
  13384. /**
  13385. * Infect a user with status effects (SC_DEADLYINFECT)
  13386. * @param src: Object initiating change on bl [PC|MOB|HOM|MER|ELEM]
  13387. * @param bl: Object to change
  13388. * @return 1: Success 0: Fail
  13389. */
  13390. int32 status_change_spread(block_list *src, block_list *bl)
  13391. {
  13392. if (src == nullptr || bl == nullptr)
  13393. return 0;
  13394. // Status Immunity resistance
  13395. if (status_bl_has_mode(src, MD_STATUSIMMUNE) || status_bl_has_mode(bl, MD_STATUSIMMUNE))
  13396. return 0;
  13397. status_change *sc = status_get_sc(src);
  13398. if (sc == nullptr || sc->empty())
  13399. return 0;
  13400. bool hasSpread = false;
  13401. t_tick tick = gettick(), sc_tick;
  13402. for (const auto &it : status_db) {
  13403. sc_type type = static_cast<sc_type>(it.first);
  13404. const TimerData *timer;
  13405. if (sc->getSCE(type) && it.second->flag[SCF_SPREADEFFECT]) {
  13406. if (sc->getSCE(type)->timer != INVALID_TIMER) {
  13407. timer = get_timer(sc->getSCE(type)->timer);
  13408. if (timer == nullptr || timer->func != status_change_timer || DIFF_TICK(timer->tick, tick) < 0)
  13409. continue;
  13410. int32 val4 = sc->getSCE(type)->val4;
  13411. sc_tick = DIFF_TICK(timer->tick, tick) + (val4 > 0 ? val4 : 0);
  13412. } else
  13413. sc_tick = INFINITE_TICK;
  13414. status_change_start(src, bl, type, 10000, sc->getSCE(type)->val1, sc->getSCE(type)->val2, sc->getSCE(type)->val3, sc->getSCE(type)->val4, sc_tick, SCSTART_NOAVOID | SCSTART_NOTICKDEF | SCSTART_NORATEDEF);
  13415. if (!hasSpread)
  13416. hasSpread = true;
  13417. }
  13418. }
  13419. return hasSpread;
  13420. }
  13421. /**
  13422. * Applying natural heal bonuses (sit, skill, homun, etc...)
  13423. * TODO: the va_list doesn't seem to be used, safe to remove?
  13424. * @param bl: Object applying bonuses to [PC|HOM|MER|ELEM]
  13425. * @param args: va_list arguments
  13426. * @return which regeneration bonuses have been applied (flag)
  13427. */
  13428. static t_tick natural_heal_prev_tick,natural_heal_diff_tick;
  13429. static int32 status_natural_heal(struct block_list* bl, va_list args)
  13430. {
  13431. struct regen_data *regen;
  13432. status_change *sc;
  13433. struct unit_data *ud;
  13434. struct view_data *vd = nullptr;
  13435. struct regen_data_sub *sregen;
  13436. map_session_data *sd;
  13437. int32 rate, multi = 1, flag;
  13438. regen = status_get_regen_data(bl);
  13439. if (!regen)
  13440. return 0;
  13441. status_data* status = status_get_status_data(*bl);
  13442. sc = status_get_sc(bl);
  13443. if (sc != nullptr && sc->empty())
  13444. sc = nullptr;
  13445. sd = BL_CAST(BL_PC,bl);
  13446. flag = regen->flag;
  13447. if (flag&RGN_HP && (regen->state.block&1))
  13448. flag &= ~(RGN_HP|RGN_SHP);
  13449. if (flag&RGN_SP && (regen->state.block&2))
  13450. flag &= ~(RGN_SP|RGN_SSP);
  13451. // Only skill-based regen is disabled at max HP/SP
  13452. if (flag&RGN_SHP && (status->hp >= status->max_hp))
  13453. flag &= ~RGN_SHP;
  13454. if (flag&RGN_SSP && (status->sp >= status->max_sp))
  13455. flag &= ~RGN_SSP;
  13456. if (flag && (
  13457. status_isdead(*bl) ||
  13458. (sc && (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || sc->getSCE(SC__INVISIBILITY)))
  13459. ))
  13460. flag = RGN_NONE;
  13461. if (sd) {
  13462. if (sd->hp_loss.value || sd->sp_loss.value)
  13463. pc_bleeding(sd, natural_heal_diff_tick);
  13464. if (sd->hp_regen.value || sd->sp_regen.value || sd->percent_hp_regen.value || sd->percent_sp_regen.value)
  13465. pc_regen(sd, natural_heal_diff_tick);
  13466. }
  13467. if(flag&(RGN_SHP|RGN_SSP) && regen->ssregen &&
  13468. (vd = status_get_viewdata(bl)) && vd->dead_sit == 2)
  13469. { // Apply sitting regen bonus.
  13470. sregen = regen->ssregen;
  13471. if(flag&(RGN_SHP)) { // Sitting HP regen
  13472. rate = (int32)(natural_heal_diff_tick * (sregen->rate.hp / 100.));
  13473. if (regen->state.overweight)
  13474. rate /= 2; // Half as fast when overweight.
  13475. sregen->tick.hp += rate;
  13476. while(sregen->tick.hp >= (uint32)battle_config.natural_heal_skill_interval) {
  13477. sregen->tick.hp -= battle_config.natural_heal_skill_interval;
  13478. if(status_heal(bl, sregen->hp, 0, 3) < sregen->hp) { // Full
  13479. flag &= ~RGN_SHP;
  13480. break;
  13481. }
  13482. }
  13483. }
  13484. if(flag&(RGN_SSP)) { // Sitting SP regen
  13485. rate = (int32)(natural_heal_diff_tick * (sregen->rate.sp / 100.));
  13486. if (regen->state.overweight)
  13487. rate /= 2; // Half as fast when overweight.
  13488. sregen->tick.sp += rate;
  13489. while(sregen->tick.sp >= (uint32)battle_config.natural_heal_skill_interval) {
  13490. sregen->tick.sp -= battle_config.natural_heal_skill_interval;
  13491. if(status_heal(bl, 0, sregen->sp, 3) < sregen->sp) { // Full
  13492. flag &= ~RGN_SSP;
  13493. break;
  13494. }
  13495. }
  13496. }
  13497. }
  13498. if (flag && regen->state.overweight)
  13499. flag = RGN_NONE;
  13500. ud = unit_bl2ud(bl);
  13501. if (ud && ud->walktimer != INVALID_TIMER) {
  13502. flag &= ~(RGN_SHP|RGN_SSP);
  13503. //Mercenaries recover HP even while walking
  13504. if(bl->type != BL_MER && !regen->state.walk)
  13505. flag &= ~RGN_HP;
  13506. //Homunculus don't recover SP while walking
  13507. if (bl->type == BL_HOM && !regen->state.walk)
  13508. flag &= ~RGN_SP;
  13509. }
  13510. if (flag&(RGN_HP|RGN_SP)) {
  13511. if(!vd)
  13512. vd = status_get_viewdata(bl);
  13513. if(vd && vd->dead_sit == 2)
  13514. multi += 1; //This causes the interval to be halved
  13515. if(regen->state.gc)
  13516. multi += 1; //This causes the interval to be halved
  13517. }
  13518. // Natural Hp regen
  13519. if (flag&RGN_HP) {
  13520. // Interval to next recovery tick
  13521. rate = (int32)(battle_config.natural_healhp_interval / (regen->rate.hp/100. * multi));
  13522. // Half recovery while moving only applies to players with certain traits
  13523. if (sd && ud && ud->walktimer != INVALID_TIMER)
  13524. rate *= 2;
  13525. // Homun HP regen fix (2 seconds instead of 6 seconds)
  13526. if(bl->type == BL_HOM)
  13527. rate /= 3;
  13528. // Mercenary HP regen fix (8 seconds instead of 6 seconds)
  13529. if (bl->type == BL_MER)
  13530. rate = (rate * 4) / 3;
  13531. // Our timer system isn't 100% accurate so make sure we use the closest interval
  13532. rate -= NATURAL_HEAL_INTERVAL / 2;
  13533. if(regen->tick.hp + rate <= natural_heal_prev_tick) {
  13534. regen->tick.hp = natural_heal_prev_tick;
  13535. if (status->hp >= status->max_hp)
  13536. flag &= ~(RGN_HP | RGN_SHP);
  13537. else if (status_heal(bl, regen->hp, 0, 1) < regen->hp)
  13538. flag &= ~RGN_SHP; // Full
  13539. }
  13540. }
  13541. else {
  13542. regen->tick.hp = natural_heal_prev_tick;
  13543. }
  13544. // Natural SP regen
  13545. if(flag&RGN_SP) {
  13546. // Interval to next recovery tick
  13547. rate = (int32)(battle_config.natural_healsp_interval / (regen->rate.sp/100. * multi));
  13548. // Homun SP regen fix (4 seconds instead of 8 seconds)
  13549. if(bl->type==BL_HOM)
  13550. rate /= 2;
  13551. // Mercenary SP regen fix (6 seconds instead of 8 seconds)
  13552. if (bl->type == BL_MER)
  13553. rate = (rate * 3) / 4;
  13554. #ifdef RENEWAL
  13555. if (sd && (sd->class_&MAPID_UPPERMASK) == MAPID_MONK &&
  13556. sc && sc->getSCE(SC_EXPLOSIONSPIRITS) && (!sc->getSCE(SC_SPIRIT) || sc->getSCE(SC_SPIRIT)->val2 != SL_MONK))
  13557. rate *= 2; // Tick is doubled in Fury state
  13558. #endif
  13559. // Our timer system isn't 100% accurate so make sure we use the closest interval
  13560. rate -= NATURAL_HEAL_INTERVAL / 2;
  13561. if(regen->tick.sp + rate <= natural_heal_prev_tick) {
  13562. regen->tick.sp = natural_heal_prev_tick;
  13563. if (status->sp >= status->max_sp)
  13564. flag &= ~(RGN_SP | RGN_SSP);
  13565. else if (status_heal(bl, 0, regen->sp, 1) < regen->sp)
  13566. flag &= ~RGN_SSP; // Full
  13567. }
  13568. }
  13569. else {
  13570. regen->tick.sp = natural_heal_prev_tick;
  13571. }
  13572. if (!regen->sregen)
  13573. return flag;
  13574. // Skill regen
  13575. sregen = regen->sregen;
  13576. if(flag&RGN_SHP) { // Skill HP regen
  13577. sregen->tick.hp += (int32)(natural_heal_diff_tick * (sregen->rate.hp / 100.));
  13578. while(sregen->tick.hp >= (uint32)battle_config.natural_heal_skill_interval) {
  13579. sregen->tick.hp -= battle_config.natural_heal_skill_interval;
  13580. if(status_heal(bl, sregen->hp, 0, 3) < sregen->hp)
  13581. break; // Full
  13582. }
  13583. }
  13584. if(flag&RGN_SSP) { // Skill SP regen
  13585. sregen->tick.sp += (int32)(natural_heal_diff_tick * (sregen->rate.sp /100.));
  13586. while(sregen->tick.sp >= (uint32)battle_config.natural_heal_skill_interval) {
  13587. int32 val = sregen->sp;
  13588. if (sd && sd->state.doridori) {
  13589. val *= 2;
  13590. sd->state.doridori = 0;
  13591. if ((rate = pc_checkskill(sd,TK_SPTIME)))
  13592. sc_start(bl,bl,skill_get_sc(TK_SPTIME),
  13593. 100,rate,skill_get_time(TK_SPTIME, rate));
  13594. if (
  13595. (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR &&
  13596. rnd()%10000 < battle_config.sg_angel_skill_ratio
  13597. ) { // Angel of the Sun/Moon/Star
  13598. clif_feel_hate_reset(sd);
  13599. pc_resethate(sd);
  13600. pc_resetfeel(sd);
  13601. }
  13602. }
  13603. sregen->tick.sp -= battle_config.natural_heal_skill_interval;
  13604. if(status_heal(bl, 0, val, 3) < val)
  13605. break; // Full
  13606. }
  13607. }
  13608. return flag;
  13609. }
  13610. /**
  13611. * Natural heal main timer
  13612. * @param tid: Timer ID
  13613. * @param tick: Current tick (time)
  13614. * @param id: Object ID to heal
  13615. * @param data: data pushed through timer function
  13616. * @return 0
  13617. */
  13618. static TIMER_FUNC(status_natural_heal_timer){
  13619. natural_heal_diff_tick = DIFF_TICK(tick,natural_heal_prev_tick);
  13620. natural_heal_prev_tick = tick;
  13621. map_foreachregen(status_natural_heal);
  13622. return 0;
  13623. }
  13624. /**
  13625. * Clears the lastEffect value from a target
  13626. * @param tid: Timer ID
  13627. * @param tick: Current tick (time)
  13628. * @param id: Object ID
  13629. * @param data: data pushed through timer function
  13630. * @return 0
  13631. */
  13632. TIMER_FUNC(status_clear_lastEffect_timer) {
  13633. block_list *bl = map_id2bl(id);
  13634. if (bl != nullptr) {
  13635. status_change *sc = status_get_sc(bl);
  13636. if (sc != nullptr) {
  13637. sc->lastEffect = SC_NONE;
  13638. sc->lastEffectTimer = INVALID_TIMER;
  13639. }
  13640. }
  13641. return 0;
  13642. }
  13643. /**
  13644. * Check if status is disabled on a map
  13645. * @param type: Status Change data
  13646. * @param mapIsVS: If the map is a map_flag_vs type
  13647. * @param mapisPVP: If the map is a PvP type
  13648. * @param mapIsGVG: If the map is a map_flag_gvg type
  13649. * @param mapIsBG: If the map is a Battleground type
  13650. * @param mapZone: Map Zone type
  13651. * @param mapIsTE: If the map us WOE TE
  13652. * @return True - SC disabled on map; False - SC not disabled on map/Invalid SC
  13653. */
  13654. static bool status_change_isDisabledOnMap_(sc_type type, bool mapIsVS, bool mapIsPVP, bool mapIsGVG, bool mapIsBG, uint32 mapZone, bool mapIsTE)
  13655. {
  13656. if (!status_db.validateStatus(type))
  13657. return false;
  13658. if ((!mapIsVS && SCDisabled[type]&1) ||
  13659. (mapIsPVP && SCDisabled[type]&2) ||
  13660. (mapIsGVG && SCDisabled[type]&4) ||
  13661. (mapIsBG && SCDisabled[type]&8) ||
  13662. (mapIsTE && SCDisabled[type]&16) ||
  13663. (SCDisabled[type]&(mapZone)))
  13664. {
  13665. return true;
  13666. }
  13667. return false;
  13668. }
  13669. /**
  13670. * Clear a status if it is disabled on a map
  13671. * @param bl: Block list data
  13672. * @param sc: Status Change data
  13673. */
  13674. void status_change_clear_onChangeMap(struct block_list *bl, status_change *sc)
  13675. {
  13676. nullpo_retv(bl);
  13677. if (sc != nullptr && !sc->empty()) {
  13678. struct map_data *mapdata = map_getmapdata(bl->m);
  13679. bool mapIsVS = mapdata_flag_vs2(mapdata);
  13680. bool mapIsPVP = mapdata->getMapFlag(MF_PVP) != 0;
  13681. bool mapIsGVG = mapdata_flag_gvg2_no_te(mapdata);
  13682. bool mapIsBG = mapdata->getMapFlag(MF_BATTLEGROUND) != 0;
  13683. bool mapIsTE = mapdata_flag_gvg2_te(mapdata);
  13684. for (const auto &it : status_db) {
  13685. sc_type type = static_cast<sc_type>(it.first);
  13686. if (!sc->getSCE(type) || !SCDisabled[type])
  13687. continue;
  13688. if (status_change_isDisabledOnMap_(type, mapIsVS, mapIsPVP, mapIsGVG, mapIsBG, mapdata->zone, mapIsTE))
  13689. status_change_end(bl, type);
  13690. }
  13691. }
  13692. }
  13693. /**
  13694. * Read status_disabled.txt file
  13695. * @param str: Fields passed from sv_readdb
  13696. * @param columns: Columns passed from sv_readdb function call
  13697. * @param current: Current row being read into SCDisabled array
  13698. * @return True - Successfully stored, False - Invalid SC
  13699. */
  13700. static bool status_readdb_status_disabled( char **str, size_t columns, size_t current ){
  13701. int64 type = SC_NONE;
  13702. if (ISDIGIT(str[0][0]))
  13703. type = atoi(str[0]);
  13704. else {
  13705. if (!script_get_constant(str[0],&type))
  13706. type = SC_NONE;
  13707. }
  13708. if (type <= SC_NONE || type >= SC_MAX) {
  13709. ShowError("status_readdb_status_disabled: Invalid SC with type %s.\n", str[0]);
  13710. return false;
  13711. }
  13712. SCDisabled[type] = (uint32)atol(str[1]);
  13713. return true;
  13714. }
  13715. const std::string AttributeDatabase::getDefaultLocation() {
  13716. return std::string(db_path) + "/attr_fix.yml";
  13717. }
  13718. /**
  13719. * Reads and parses an entry from the attr_fix.
  13720. * @param node: YAML node containing the entry.
  13721. * @return count of successfully parsed rows
  13722. */
  13723. uint64 AttributeDatabase::parseBodyNode(const ryml::NodeRef& node) {
  13724. uint16 level;
  13725. if (!this->asUInt16(node, "Level", level))
  13726. return 0;
  13727. if (!CHK_ELEMENT_LEVEL(level)) {
  13728. this->invalidWarning(node["Level"], "Invalid element level %hu.\n", level);
  13729. return 0;
  13730. }
  13731. for (const auto &itatk : um_eleid2elename) {
  13732. if (!this->nodeExists(node, itatk.first))
  13733. continue;
  13734. const auto& eleNode = node[c4::to_csubstr(itatk.first)];
  13735. for (const auto &itdef : um_eleid2elename) {
  13736. if (!this->nodeExists(eleNode, itdef.first))
  13737. continue;
  13738. int16 val;
  13739. if (!this->asInt16(eleNode, itdef.first, val))
  13740. return 0;
  13741. if (val < -100) {
  13742. this->invalidWarning(eleNode[c4::to_csubstr(itdef.first)], "%s %h is out of range %d~%d. Setting to -100.\n", itdef.first.c_str(), val, -100, 200);
  13743. val = -100;
  13744. }
  13745. else if (val > 200) {
  13746. this->invalidWarning(eleNode[c4::to_csubstr(itdef.first)], "%s %h is out of range %d~%d. Setting to 200.\n", itdef.first.c_str(), val, -100, 200);
  13747. val = 200;
  13748. }
  13749. this->attr_fix_table[level-1][itatk.second][itdef.second] = val;
  13750. }
  13751. }
  13752. return 1;
  13753. }
  13754. AttributeDatabase elemental_attribute_db;
  13755. /**
  13756. * Get attribute ratio
  13757. * @param atk_ele Attack element enum e_element
  13758. * @param def_ele Defense element enum e_element
  13759. * @param level Element level 1 ~ MAX_ELE_LEVEL
  13760. */
  13761. int16 AttributeDatabase::getAttribute(uint16 level, uint16 atk_ele, uint16 def_ele) {
  13762. if (!CHK_ELEMENT(atk_ele) || !CHK_ELEMENT(def_ele) || !CHK_ELEMENT_LEVEL(level))
  13763. return 100;
  13764. return this->attr_fix_table[level-1][atk_ele][def_ele];
  13765. }
  13766. s_status_change_db::s_status_change_db(){
  13767. this->type = SC_NONE;
  13768. this->icon = EFST_BLANK;
  13769. this->state = {};
  13770. this->calc_flag = {};
  13771. this->opt1 = OPT1_NONE;
  13772. this->opt2 = OPT2_NONE;
  13773. this->opt3 = OPT3_NORMAL;
  13774. this->look = OPTION_NOTHING;
  13775. this->flag = {};
  13776. this->skill_id = 0;
  13777. this->endonstart = {};
  13778. this->fail = {};
  13779. this->endreturn = {};
  13780. this->endonend = {};
  13781. this->min_duration = 1;
  13782. this->min_rate = 0;
  13783. this->script = nullptr;
  13784. }
  13785. s_status_change_db::~s_status_change_db(){
  13786. if( this->script != nullptr ){
  13787. script_free_code( this->script );
  13788. this->script = nullptr;
  13789. }
  13790. }
  13791. const std::string StatusDatabase::getDefaultLocation() {
  13792. return std::string(db_path) + "/status.yml";
  13793. }
  13794. /**
  13795. * Reads and parses an entry from status_db.
  13796. * @param node: YAML node containing the entry.
  13797. * @return count of successfully parsed rows
  13798. */
  13799. uint64 StatusDatabase::parseBodyNode(const ryml::NodeRef& node) {
  13800. std::string status_name;
  13801. if (!this->asString(node, "Status", status_name))
  13802. return 0;
  13803. std::string status_constant = "SC_" + status_name;
  13804. int64 constant;
  13805. if (!script_get_constant(status_constant.c_str(), &constant)) {
  13806. this->invalidWarning(node["Status"], "Invalid Status %s.\n", status_name.c_str());
  13807. return 0;
  13808. }
  13809. if (!this->validateStatus(static_cast<sc_type>(constant))) {
  13810. this->invalidWarning(node["Status"], "Status %s is out of bounds.\n", status_name.c_str());
  13811. return 0;
  13812. }
  13813. int32 status_id = static_cast<int32>(constant);
  13814. std::shared_ptr<s_status_change_db> status = this->find(status_id);
  13815. bool exists = status != nullptr;
  13816. if (!exists) {
  13817. status = std::make_shared<s_status_change_db>();
  13818. status->type = static_cast<sc_type>(status_id);
  13819. }
  13820. if (this->nodeExists(node, "Icon")) {
  13821. std::string icon_name;
  13822. if (!this->asString(node, "Icon", icon_name))
  13823. return 0;
  13824. int64 constant;
  13825. if (!script_get_constant(icon_name.c_str(), &constant)) {
  13826. this->invalidWarning(node["Icon"], "Icon %s is invalid, defaulting to EFST_BLANK.\n", icon_name.c_str());
  13827. constant = EFST_BLANK;
  13828. }
  13829. if (constant < EFST_BLANK || constant >= EFST_MAX) {
  13830. this->invalidWarning(node["Icon"], "Icon %s is out of bounds, defaulting to EFST_BLANK.\n", icon_name.c_str());
  13831. constant = EFST_BLANK;
  13832. }
  13833. status->icon = static_cast<efst_type>(constant);
  13834. } else {
  13835. if (!exists)
  13836. status->icon = EFST_BLANK;
  13837. }
  13838. if (this->nodeExists(node, "DurationLookup")) {
  13839. std::string skill_name;
  13840. if (!this->asString(node, "DurationLookup", skill_name))
  13841. return 0;
  13842. uint16 skill_id = skill_name2id(skill_name.c_str());
  13843. if (skill_id == 0)
  13844. this->invalidWarning(node["DurationLookup"], "DurationLookup skill %s is invalid, defaulting to none.\n", skill_name.c_str());
  13845. status->skill_id = skill_id;
  13846. } else {
  13847. if (!exists)
  13848. status->skill_id = 0;
  13849. }
  13850. if (this->nodeExists(node, "States")) {
  13851. const ryml::NodeRef& stateNode = node["States"];
  13852. for (const auto &it : stateNode) {
  13853. std::string state;
  13854. c4::from_chars(it.key(), &state);
  13855. std::string state_constant = "SCS_" + state;
  13856. int64 constant;
  13857. if (!script_get_constant(state_constant.c_str(), &constant)) {
  13858. this->invalidWarning(stateNode, "State %s is invalid.\n", state.c_str());
  13859. return 0;
  13860. }
  13861. if (constant < SCS_NONE || constant >= SCS_MAX) {
  13862. this->invalidWarning(stateNode, "State %s is out of bounds.\n", state.c_str());
  13863. return 0;
  13864. }
  13865. bool active;
  13866. if (!this->asBool(stateNode, state, active))
  13867. return 0;
  13868. if (active)
  13869. status->state.set(static_cast<e_scs_flag>(constant));
  13870. else
  13871. status->state.reset(static_cast<e_scs_flag>(constant));
  13872. }
  13873. } else {
  13874. if (!exists)
  13875. status->state.reset();
  13876. }
  13877. if (this->nodeExists(node, "CalcFlags")) {
  13878. const ryml::NodeRef& flagNode = node["CalcFlags"];
  13879. if (this->nodeExists(flagNode, "All")) {
  13880. bool active;
  13881. if (!this->asBool(flagNode, "All", active))
  13882. return 0;
  13883. if (active)
  13884. status->calc_flag = this->getSCB_ALL();
  13885. else
  13886. status->calc_flag.reset();
  13887. }
  13888. for (const auto &it : flagNode) {
  13889. std::string flag;
  13890. c4::from_chars(it.key(), &flag);
  13891. std::string flag_constant = "SCB_" + flag;
  13892. int64 constant;
  13893. // Skipped because processed above the loop
  13894. if (flag.compare("All") == 0)
  13895. continue;
  13896. if (!script_get_constant(flag_constant.c_str(), &constant)) {
  13897. this->invalidWarning(flagNode, "CalcFlag %s is invalid.\n", flag.c_str());
  13898. return 0;
  13899. }
  13900. if (constant < SCB_NONE || constant >= SCB_MAX) {
  13901. this->invalidWarning(flagNode, "CalcFlag %s is out of bounds.\n", flag.c_str());
  13902. return 0;
  13903. }
  13904. bool active;
  13905. if (!this->asBool(flagNode, flag, active))
  13906. return 0;
  13907. if (active)
  13908. status->calc_flag.set(static_cast<e_scb_flag>(constant));
  13909. else
  13910. status->calc_flag.reset(static_cast<e_scb_flag>(constant));
  13911. }
  13912. } else {
  13913. if (!exists)
  13914. status->calc_flag.reset();
  13915. }
  13916. if (this->nodeExists(node, "Opt1")) {
  13917. std::string opt;
  13918. if (!this->asString(node, "Opt1", opt))
  13919. return 0;
  13920. std::string opt_constant = "OPT1_" + opt;
  13921. int64 constant;
  13922. if (!script_get_constant(opt_constant.c_str(), &constant)) {
  13923. this->invalidWarning(node["Opt1"], "Opt1 %s is invalid.\n", opt.c_str());
  13924. return 0;
  13925. }
  13926. if (constant < OPT1_NONE || constant >= OPT1_MAX) {
  13927. this->invalidWarning(node["Opt1"], "Opt2 %s is out of bounds.\n", opt.c_str());
  13928. return 0;
  13929. }
  13930. status->opt1 = static_cast<e_sc_opt1>(constant);
  13931. } else {
  13932. if (!exists)
  13933. status->opt1 = OPT1_NONE;
  13934. }
  13935. if (this->nodeExists(node, "Opt2")) {
  13936. const ryml::NodeRef& optNode = node["Opt2"];
  13937. for (const auto &it : optNode) {
  13938. std::string opt;
  13939. c4::from_chars(it.key(), &opt);
  13940. std::string opt_constant = "OPT2_" + opt;
  13941. int64 constant;
  13942. if (!script_get_constant(opt_constant.c_str(), &constant)) {
  13943. this->invalidWarning(optNode, "Opt2 %s is invalid.\n", opt.c_str());
  13944. return 0;
  13945. }
  13946. if (constant < OPT2_NONE || constant >= OPT2_MAX) {
  13947. this->invalidWarning(optNode, "Opt2 %s is out of bounds.\n", opt.c_str());
  13948. return 0;
  13949. }
  13950. bool active;
  13951. if (!this->asBool(optNode, opt, active))
  13952. return 0;
  13953. if (active)
  13954. status->opt2 |= static_cast<e_sc_opt2>(constant);
  13955. else
  13956. status->opt2 &= ~static_cast<e_sc_opt2>(constant);
  13957. }
  13958. } else {
  13959. if (!exists)
  13960. status->opt2 = OPT2_NONE;
  13961. }
  13962. if (this->nodeExists(node, "Opt3")) {
  13963. const ryml::NodeRef& optNode = node["Opt3"];
  13964. for (const auto &it : optNode) {
  13965. std::string opt;
  13966. c4::from_chars(it.key(), &opt);
  13967. std::string opt_constant = "OPT3_" + opt;
  13968. int64 constant;
  13969. if (!script_get_constant(opt_constant.c_str(), &constant)) {
  13970. this->invalidWarning(optNode, "Opt3 %s is invalid.\n", opt.c_str());
  13971. return 0;
  13972. }
  13973. if (constant < OPT3_NORMAL || constant >= OPT3_MAX) {
  13974. this->invalidWarning(optNode, "Opt3 %s is out of bounds.\n", opt.c_str());
  13975. return 0;
  13976. }
  13977. bool active;
  13978. if (!this->asBool(optNode, opt, active))
  13979. return 0;
  13980. if (active)
  13981. status->opt3 |= static_cast<e_sc_opt3>(constant);
  13982. else
  13983. status->opt3 &= ~static_cast<e_sc_opt3>(constant);
  13984. }
  13985. } else {
  13986. if (!exists)
  13987. status->opt3 = OPT3_NORMAL;
  13988. }
  13989. if (this->nodeExists(node, "Options")) {
  13990. const ryml::NodeRef& optionNode = node["Options"];
  13991. for (const auto &it : optionNode) {
  13992. std::string option;
  13993. c4::from_chars(it.key(), &option);
  13994. std::string option_constant = "OPTION_" + option;
  13995. int64 constant;
  13996. if (!script_get_constant(option_constant.c_str(), &constant)) {
  13997. this->invalidWarning(optionNode, "Option %s is invalid.\n", option.c_str());
  13998. return 0;
  13999. }
  14000. if (constant < OPTION_NOTHING || constant >= OPTION_MAX) {
  14001. this->invalidWarning(optionNode, "Option %s is out of bounds.\n", option.c_str());
  14002. return 0;
  14003. }
  14004. bool active;
  14005. if (!this->asBool(optionNode, option, active))
  14006. return 0;
  14007. if (active)
  14008. status->look |= static_cast<e_option>(constant);
  14009. else
  14010. status->look &= ~static_cast<e_option>(constant);
  14011. }
  14012. } else {
  14013. if (!exists)
  14014. status->look = OPTION_NOTHING;
  14015. }
  14016. if (this->nodeExists(node, "Flags")) {
  14017. const ryml::NodeRef& flagNode = node["Flags"];
  14018. for (const auto &it : flagNode) {
  14019. std::string flag;
  14020. c4::from_chars(it.key(), &flag);
  14021. std::string flag_constant = "SCF_" + flag;
  14022. int64 constant;
  14023. if (!script_get_constant(flag_constant.c_str(), &constant)) {
  14024. this->invalidWarning(flagNode, "Flag %s is invalid.\n", flag.c_str());
  14025. return 0;
  14026. }
  14027. if (constant < SCF_NONE || constant >= SCF_MAX) {
  14028. this->invalidWarning(flagNode, "Flag %s is out of bounds.\n", flag.c_str());
  14029. return 0;
  14030. }
  14031. bool active;
  14032. if (!this->asBool(flagNode, flag, active))
  14033. return 0;
  14034. if (active)
  14035. status->flag.set(static_cast<e_status_change_flag>(constant));
  14036. else
  14037. status->flag.reset(static_cast<e_status_change_flag>(constant));
  14038. }
  14039. } else {
  14040. if (!exists)
  14041. status->flag.reset();
  14042. }
  14043. if (this->nodeExists(node, "MinRate")) {
  14044. uint16 rate;
  14045. if (!this->asUInt16(node, "MinRate", rate))
  14046. return 0;
  14047. status->min_rate = rate;
  14048. } else {
  14049. if (!exists)
  14050. status->min_rate = 0;
  14051. }
  14052. if (this->nodeExists(node, "MinDuration")) {
  14053. int64 duration;
  14054. if (!this->asInt64(node, "MinDuration", duration))
  14055. return 0;
  14056. status->min_duration = static_cast<t_tick>(duration);
  14057. } else {
  14058. if (!exists)
  14059. status->min_duration = 1;
  14060. }
  14061. if (this->nodeExists(node, "Fail")) {
  14062. const ryml::NodeRef& failNode = node["Fail"];
  14063. for (const auto &it : failNode) {
  14064. std::string fail;
  14065. c4::from_chars(it.key(), &fail);
  14066. std::string fail_constant = "SC_" + fail;
  14067. int64 constant;
  14068. if (!script_get_constant(fail_constant.c_str(), &constant)) {
  14069. this->invalidWarning(failNode, "Fail status %s is invalid.\n", fail.c_str());
  14070. return 0;
  14071. }
  14072. if (!this->validateStatus(static_cast<sc_type>(constant))) {
  14073. this->invalidWarning(failNode, "Fail status %s is out of bounds.\n", fail.c_str());
  14074. return 0;
  14075. }
  14076. bool active;
  14077. if (!this->asBool(failNode, fail, active))
  14078. return 0;
  14079. if (active)
  14080. status->fail.push_back(static_cast<sc_type>(constant));
  14081. else
  14082. util::vector_erase_if_exists(status->fail, static_cast<sc_type>(constant));
  14083. }
  14084. }
  14085. if (this->nodeExists(node, "EndOnStart")) {
  14086. const ryml::NodeRef& endNode = node["EndOnStart"];
  14087. for (const auto &it : endNode) {
  14088. std::string end;
  14089. c4::from_chars(it.key(), &end);
  14090. std::string end_constant = "SC_" + end;
  14091. int64 constant;
  14092. if (!script_get_constant(end_constant.c_str(), &constant)) {
  14093. this->invalidWarning(endNode, "EndOnStart status %s is invalid.\n", end.c_str());
  14094. return 0;
  14095. }
  14096. if (!this->validateStatus(static_cast<sc_type>(constant))) {
  14097. this->invalidWarning(endNode, "EndOnStart status %s is out of bounds.\n", end.c_str());
  14098. return 0;
  14099. }
  14100. bool active;
  14101. if (!this->asBool(endNode, end, active))
  14102. return 0;
  14103. if (active)
  14104. status->endonstart.push_back(static_cast<sc_type>(constant));
  14105. else
  14106. util::vector_erase_if_exists(status->endonstart, static_cast<sc_type>(constant));
  14107. }
  14108. }
  14109. if (this->nodeExists(node, "EndReturn")) {
  14110. const ryml::NodeRef &endNode = node["EndReturn"];
  14111. for (const auto &it : endNode) {
  14112. std::string end;
  14113. c4::from_chars(it.key(), &end);
  14114. std::string end_constant = "SC_" + end;
  14115. int64 constant;
  14116. if (!script_get_constant(end_constant.c_str(), &constant)) {
  14117. this->invalidWarning(endNode, "EndReturn status %s is invalid.\n", end.c_str());
  14118. return 0;
  14119. }
  14120. if (!this->validateStatus(static_cast<sc_type>(constant))) {
  14121. this->invalidWarning(endNode, "EndReturn status %s is out of bounds.\n", end.c_str());
  14122. return 0;
  14123. }
  14124. bool active;
  14125. if (!this->asBool(endNode, end, active))
  14126. return 0;
  14127. if (active)
  14128. status->endreturn.push_back(static_cast<sc_type>(constant));
  14129. else
  14130. util::vector_erase_if_exists(status->endreturn, static_cast<sc_type>(constant));
  14131. }
  14132. }
  14133. if (this->nodeExists(node, "EndOnEnd")) {
  14134. const ryml::NodeRef &endNode = node["EndOnEnd"];
  14135. for (const auto &it : endNode) {
  14136. std::string end;
  14137. c4::from_chars(it.key(), &end);
  14138. std::string end_constant = "SC_" + end;
  14139. int64 constant;
  14140. if (!script_get_constant(end_constant.c_str(), &constant)) {
  14141. this->invalidWarning(endNode, "EndOnEnd status %s is invalid.\n", end.c_str());
  14142. return 0;
  14143. }
  14144. if (!this->validateStatus(static_cast<sc_type>(constant))) {
  14145. this->invalidWarning(endNode, "EndOnEnd status %s is out of bounds.\n", end.c_str());
  14146. return 0;
  14147. }
  14148. bool active;
  14149. if (!this->asBool(endNode, end, active))
  14150. return 0;
  14151. if (active)
  14152. status->endonend.push_back(static_cast<sc_type>(constant));
  14153. else
  14154. util::vector_erase_if_exists(status->endonend, static_cast<sc_type>(constant));
  14155. }
  14156. }
  14157. if( this->nodeExists( node, "Script" ) ){
  14158. std::string script;
  14159. if( !this->asString( node, "Script", script ) ){
  14160. return 0;
  14161. }
  14162. if( status->script ){
  14163. script_free_code( status->script );
  14164. status->script = nullptr;
  14165. }
  14166. status->script = parse_script( script.c_str(), this->getCurrentFile().c_str(), this->getLineNumber(node["Script"]), SCRIPT_IGNORE_EXTERNAL_BRACKETS );
  14167. }else{
  14168. if( !exists ){
  14169. status->script = nullptr;
  14170. }
  14171. }
  14172. if (!exists) {
  14173. this->put(status_id, status);
  14174. }
  14175. return 1;
  14176. }
  14177. void StatusDatabase::loadingFinished(){
  14178. std::fill( std::begin( this->StatusRelevantBLTypes ), std::end( this->StatusRelevantBLTypes ), BL_PC );
  14179. for( auto& entry : *this ){
  14180. auto& status = entry.second;
  14181. if( status->script != nullptr ){
  14182. // Trigger recalculation for everything for now
  14183. status->calc_flag |= this->SCB_ALL;
  14184. }
  14185. if (status->type == SC_HALLUCINATION && !battle_config.display_hallucination) // Disable Hallucination.
  14186. status->icon = EFST_BLANK;
  14187. if( status->icon == EFST_BLANK ){
  14188. continue;
  14189. }else if( status->flag[SCF_BLEFFECT] ){
  14190. this->StatusRelevantBLTypes[status->icon] |= BL_SCEFFECT;
  14191. }else{
  14192. this->StatusRelevantBLTypes[status->icon] = BL_PC;
  14193. }
  14194. }
  14195. TypesafeCachedYamlDatabase::loadingFinished();
  14196. }
  14197. StatusDatabase status_db;
  14198. /**
  14199. * Sets defaults in tables and starts read db functions
  14200. * sv_readdb reads the file, outputting the information line-by-line to
  14201. * previous functions above, separating information by delimiter
  14202. * DBs being read:
  14203. * attr_fix.yml: Attribute adjustment table for attacks
  14204. * size_fix.yml: Size adjustment table for weapons
  14205. * refine.yml: Refining data table
  14206. * @return 0
  14207. */
  14208. void status_readdb( bool reload ){
  14209. int32 i;
  14210. const char* dbsubpath[] = {
  14211. "",
  14212. "/" DBIMPORT,
  14213. //add other path here
  14214. };
  14215. // read databases
  14216. // path,filename,separator,mincol,maxcol,maxrow,func_parsor
  14217. for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
  14218. size_t n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
  14219. size_t n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
  14220. char* dbsubpath1 = (char*)aMalloc(n1+1);
  14221. char* dbsubpath2 = (char*)aMalloc(n2+1);
  14222. if(i==0) {
  14223. safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]);
  14224. safesnprintf(dbsubpath2,n2,"%s/%s%s",db_path,DBPATH,dbsubpath[i]);
  14225. }
  14226. else {
  14227. safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]);
  14228. safesnprintf(dbsubpath2,n1,"%s%s",db_path,dbsubpath[i]);
  14229. }
  14230. sv_readdb(dbsubpath1, "status_disabled.txt", ',', 2, 2, -1, &status_readdb_status_disabled, i > 0);
  14231. aFree(dbsubpath1);
  14232. aFree(dbsubpath2);
  14233. }
  14234. if( reload ){
  14235. size_fix_db.reload();
  14236. refine_db.reload();
  14237. status_db.reload();
  14238. enchantgrade_db.reload();
  14239. }else{
  14240. size_fix_db.load();
  14241. refine_db.load();
  14242. status_db.load();
  14243. enchantgrade_db.load();
  14244. }
  14245. elemental_attribute_db.load();
  14246. }
  14247. /**
  14248. * Status db init and destroy.
  14249. */
  14250. void do_init_status(void) {
  14251. memset(SCDisabled, 0, sizeof(SCDisabled));
  14252. add_timer_func_list(status_change_timer,"status_change_timer");
  14253. add_timer_func_list(status_natural_heal_timer,"status_natural_heal_timer");
  14254. add_timer_func_list(status_clear_lastEffect_timer, "status_clear_lastEffect_timer");
  14255. initDummyData();
  14256. status_readdb();
  14257. natural_heal_prev_tick = gettick();
  14258. sc_data_ers = ers_new(sizeof(struct status_change_entry),"status.cpp::sc_data_ers",ERS_OPT_NONE);
  14259. add_timer_interval(natural_heal_prev_tick + NATURAL_HEAL_INTERVAL, status_natural_heal_timer, 0, 0, NATURAL_HEAL_INTERVAL);
  14260. }
  14261. /** Destroy status data */
  14262. void do_final_status(void) {
  14263. ers_destroy(sc_data_ers);
  14264. enchantgrade_db.clear();
  14265. size_fix_db.clear();
  14266. refine_db.clear();
  14267. status_db.clear();
  14268. elemental_attribute_db.clear();
  14269. }