status.cpp 460 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223
  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 <functional>
  5. #include <math.h>
  6. #include <stdlib.h>
  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. short current_equip_item_index; /// Contains inventory index of an equipped item. To pass it into the EQUP_SCRIPT [Lupus]
  46. unsigned int current_equip_combo_pos; /// For combo items we need to save the position of all involved items here
  47. int 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. short 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 unsigned short status_calc_str(struct block_list *,struct status_change *,int);
  52. static unsigned short status_calc_agi(struct block_list *,struct status_change *,int);
  53. static unsigned short status_calc_vit(struct block_list *,struct status_change *,int);
  54. static unsigned short status_calc_int(struct block_list *,struct status_change *,int);
  55. static unsigned short status_calc_dex(struct block_list *,struct status_change *,int);
  56. static unsigned short status_calc_luk(struct block_list *,struct status_change *,int);
  57. static unsigned short status_calc_pow(struct block_list *, struct status_change *, int);
  58. static unsigned short status_calc_sta(struct block_list *, struct status_change *, int);
  59. static unsigned short status_calc_wis(struct block_list *, struct status_change *, int);
  60. static unsigned short status_calc_spl(struct block_list *, struct status_change *, int);
  61. static unsigned short status_calc_con(struct block_list *, struct status_change *, int);
  62. static unsigned short status_calc_crt(struct block_list *, struct status_change *, int);
  63. static unsigned short status_calc_batk(struct block_list *,struct status_change *,int);
  64. static unsigned short status_calc_watk(struct block_list *,struct status_change *,int);
  65. static unsigned short status_calc_matk(struct block_list *,struct status_change *,int);
  66. static signed short status_calc_hit(struct block_list *,struct status_change *,int);
  67. static signed short status_calc_critical(struct block_list *,struct status_change *,int);
  68. static signed short status_calc_flee(struct block_list *,struct status_change *,int);
  69. static signed short status_calc_flee2(struct block_list *,struct status_change *,int);
  70. static defType status_calc_def(struct block_list *bl, struct status_change *sc, int);
  71. static signed short status_calc_def2(struct block_list *,struct status_change *,int);
  72. static defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int);
  73. static signed short status_calc_mdef2(struct block_list *,struct status_change *,int);
  74. static unsigned short status_calc_speed(struct block_list *,struct status_change *,int);
  75. static short status_calc_aspd_rate(struct block_list *,struct status_change *,int);
  76. static unsigned short status_calc_dmotion(struct block_list *bl, struct status_change *sc, int dmotion);
  77. #ifdef RENEWAL_ASPD
  78. static short status_calc_aspd(struct block_list *bl, struct status_change *sc, bool fixed);
  79. #endif
  80. static short status_calc_fix_aspd(struct block_list *bl, struct status_change *sc, int);
  81. static signed short status_calc_patk(struct block_list *, struct status_change *, int);
  82. static signed short status_calc_smatk(struct block_list *, struct status_change *, int);
  83. static signed short status_calc_res(struct block_list *, struct status_change *, int);
  84. static signed short status_calc_mres(struct block_list *, struct status_change *, int);
  85. static signed short status_calc_hplus(struct block_list *, struct status_change *, int);
  86. static signed short status_calc_crate(struct block_list *, struct status_change *, int);
  87. static unsigned int status_calc_maxhp(struct block_list *bl, uint64 maxhp);
  88. static unsigned int status_calc_maxsp(struct block_list *bl, uint64 maxsp);
  89. static unsigned int status_calc_maxap(struct block_list *bl, uint64 maxap);
  90. static unsigned char status_calc_element(struct block_list *bl, struct status_change *sc, int element);
  91. static unsigned char status_calc_element_lv(struct block_list *bl, struct status_change *sc, int lv);
  92. static int status_calc_mode(struct block_list *bl, struct status_change *sc, int mode);
  93. #ifdef RENEWAL
  94. static unsigned short status_calc_ematk(struct block_list *,struct status_change *,int);
  95. #endif
  96. static int status_get_hpbonus(struct block_list *bl, enum e_status_bonus type);
  97. static int status_get_spbonus(struct block_list *bl, enum e_status_bonus type);
  98. static int status_get_apbonus(struct block_list *bl, enum e_status_bonus type);
  99. static unsigned int status_calc_maxhpsp_pc(struct map_session_data* sd, unsigned int stat, bool isHP);
  100. static unsigned int status_calc_maxap_pc(struct map_session_data* sd);
  101. static int status_get_sc_interval(enum sc_type type);
  102. static bool status_change_isDisabledOnMap_(sc_type type, bool mapIsVS, bool mapIsPVP, bool mapIsGVG, bool mapIsBG, unsigned int mapZone, bool mapIsTE);
  103. #define status_change_isDisabledOnMap(type, m) ( status_change_isDisabledOnMap_((type), mapdata_flag_vs2((m)), m->flag[MF_PVP] != 0, mapdata_flag_gvg2_no_te((m)), m->flag[MF_BATTLEGROUND] != 0, (m->zone << 3) != 0, mapdata_flag_gvg2_te((m))) )
  104. const std::string RefineDatabase::getDefaultLocation(){
  105. return std::string( db_path ) + "/refine.yml";
  106. }
  107. uint64 RefineDatabase::parseBodyNode( const ryml::NodeRef& node ){
  108. std::string group_name;
  109. if( !this->asString( node, "Group", group_name ) ){
  110. return 0;
  111. }
  112. std::string group_name_constant = "REFINE_TYPE_" + group_name;
  113. int64 constant;
  114. if( !script_get_constant( group_name_constant.c_str(), &constant ) ){
  115. this->invalidWarning(node["Group"], "Unknown refine group %s, skipping.\n", group_name.c_str() );
  116. return 0;
  117. }
  118. uint16 group_id = static_cast<uint16>( constant );
  119. std::shared_ptr<s_refine_info> info = this->find( group_id );
  120. bool exists = info != nullptr;
  121. if( !exists ){
  122. info = std::make_shared<s_refine_info>();
  123. }
  124. if( this->nodeExists( node, "Levels" ) ){
  125. const auto& levelsNode = node["Levels"];
  126. for( const auto& levelNode : levelsNode ){
  127. uint16 level;
  128. if( !this->asUInt16( levelNode, "Level", level ) ){
  129. return 0;
  130. }
  131. std::shared_ptr<s_refine_levels_info> levels_info = util::umap_find( info->levels, level );
  132. bool levels_exists = levels_info != nullptr;
  133. if( !levels_exists ){
  134. levels_info = std::make_shared<s_refine_levels_info>();
  135. levels_info->level = level;
  136. }
  137. if( this->nodeExists( levelNode, "RefineLevels" ) ){
  138. const auto& refineLevelsNode = levelNode["RefineLevels"];
  139. for( const auto& refineLevelNode : refineLevelsNode ){
  140. uint16 refine_level;
  141. if( !this->asUInt16( refineLevelNode, "Level", refine_level ) ){
  142. return 0;
  143. }
  144. if( refine_level == 0 || refine_level > MAX_REFINE ){
  145. this->invalidWarning( refineLevelNode["Level"], "Refine level %hu is invalid, skipping.\n", refine_level );
  146. return 0;
  147. }
  148. // Database is 1 based, code is 0 based
  149. refine_level -= 1;
  150. std::shared_ptr<s_refine_level_info> level_info = util::umap_find( levels_info->levels, refine_level );
  151. bool level_exists = level_info != nullptr;
  152. if( !level_exists ){
  153. level_info = std::make_shared<s_refine_level_info>();
  154. level_info->level = refine_level;
  155. }
  156. if( this->nodeExists( refineLevelNode, "Bonus" ) ){
  157. uint32 bonus;
  158. if( !this->asUInt32( refineLevelNode, "Bonus", bonus ) ){
  159. return 0;
  160. }
  161. level_info->bonus = bonus;
  162. }else{
  163. if( !level_exists ){
  164. level_info->bonus = 0;
  165. }
  166. }
  167. if( this->nodeExists( refineLevelNode, "RandomBonus" ) ){
  168. uint32 bonus;
  169. if( !this->asUInt32( refineLevelNode, "RandomBonus", bonus ) ){
  170. return 0;
  171. }
  172. level_info->randombonus_max = bonus;
  173. }else{
  174. if( !level_exists ){
  175. level_info->randombonus_max = 0;
  176. }
  177. }
  178. if( this->nodeExists( refineLevelNode, "BlacksmithBlessingAmount" ) ){
  179. uint16 amount;
  180. if( !this->asUInt16( refineLevelNode, "BlacksmithBlessingAmount", amount ) ){
  181. return 0;
  182. }
  183. if( amount > MAX_AMOUNT ){
  184. this->invalidWarning( refineLevelNode["BlacksmithBlessingAmount"], "Blacksmith Blessing amount %hu too high, capping to MAX_AMOUNT.\n", amount );
  185. amount = MAX_AMOUNT;
  186. }
  187. level_info->blessing_amount = amount;
  188. }else{
  189. if( !level_exists ){
  190. level_info->blessing_amount = 0;
  191. }
  192. }
  193. if( this->nodeExists( refineLevelNode, "Chances" ) ){
  194. const auto& chancesNode = refineLevelNode["Chances"];
  195. for( const auto& chanceNode : chancesNode ){
  196. std::string cost_name;
  197. if( !this->asString( chanceNode, "Type", cost_name ) ){
  198. return 0;
  199. }
  200. std::string cost_name_constant = "REFINE_COST_" + cost_name;
  201. if( !script_get_constant( cost_name_constant.c_str(), &constant ) ){
  202. this->invalidWarning( chanceNode["Type"], "Unknown refine cost type %s, skipping.\n", cost_name.c_str() );
  203. return 0;
  204. }
  205. if( constant >= REFINE_COST_MAX ){
  206. this->invalidWarning( chanceNode["Type"], "Refine cost type %s is unsupported, skipping.\n", cost_name.c_str() );
  207. return 0;
  208. }
  209. uint16 index = (uint16)constant;
  210. std::shared_ptr<s_refine_cost> cost = util::umap_find( level_info->costs, index );
  211. bool cost_exists = cost != nullptr;
  212. if( !cost_exists ){
  213. cost = std::make_shared<s_refine_cost>();
  214. cost->index = index;
  215. }
  216. if( this->nodeExists( chanceNode, "Rate" ) ){
  217. uint16 rate;
  218. if( !this->asUInt16Rate( chanceNode, "Rate", rate ) ){
  219. return 0;
  220. }
  221. cost->chance = rate;
  222. }else{
  223. if( !cost_exists ){
  224. cost->chance = 0;
  225. }
  226. }
  227. if( this->nodeExists( chanceNode, "Price" ) ){
  228. uint32 price;
  229. if( !this->asUInt32( chanceNode, "Price", price ) ){
  230. return 0;
  231. }
  232. if( price > MAX_ZENY ){
  233. this->invalidWarning( chanceNode["Price"], "Price is above MAX_ZENY, capping...\n" );
  234. price = MAX_ZENY;
  235. }
  236. cost->zeny = price;
  237. }else{
  238. if( !cost_exists ){
  239. cost->zeny = 0;
  240. }
  241. }
  242. if( this->nodeExists( chanceNode, "Material" ) ){
  243. std::string item_name;
  244. if( !this->asString( chanceNode, "Material", item_name ) ){
  245. return 0;
  246. }
  247. std::shared_ptr<item_data> id = item_db.search_aegisname( item_name.c_str() );
  248. if( id == nullptr ){
  249. this->invalidWarning( chanceNode["Material"], "Unknown refine material %s, skipping.\n", item_name.c_str() );
  250. return 0;
  251. }
  252. cost->nameid = id->nameid;
  253. }else{
  254. if( !cost_exists ){
  255. cost->nameid = 0;
  256. }
  257. }
  258. if( this->nodeExists( chanceNode, "BreakingRate" ) ){
  259. uint16 breaking_rate;
  260. if( !this->asUInt16Rate( chanceNode, "BreakingRate", breaking_rate ) ){
  261. return 0;
  262. }
  263. cost->breaking_rate = breaking_rate;
  264. }else{
  265. if( !cost_exists ){
  266. cost->breaking_rate = 0;
  267. }
  268. }
  269. if( this->nodeExists( chanceNode, "DowngradeAmount" ) ){
  270. uint16 downgrade_amount;
  271. if( !this->asUInt16( chanceNode, "DowngradeAmount", downgrade_amount ) ){
  272. return 0;
  273. }
  274. if( downgrade_amount > MAX_REFINE ){
  275. this->invalidWarning( chanceNode["DowngradeAmount"], "Downgrade amount %hu is invalid, skipping.\n", downgrade_amount );
  276. return 0;
  277. }
  278. cost->downgrade_amount = downgrade_amount;
  279. }else{
  280. if( !cost_exists ){
  281. cost->downgrade_amount = 0;
  282. }
  283. }
  284. if( !cost_exists ){
  285. level_info->costs[index] = cost;
  286. }
  287. }
  288. }
  289. if( !level_exists ){
  290. levels_info->levels[refine_level] = level_info;
  291. }
  292. }
  293. }
  294. if( !levels_exists ){
  295. info->levels[level] = levels_info;
  296. }
  297. }
  298. }
  299. if( !exists ){
  300. this->put( group_id, info );
  301. }
  302. return 1;
  303. }
  304. std::shared_ptr<s_refine_level_info> RefineDatabase::findLevelInfoSub( const struct item_data& data, struct item& item, uint16 refine ){
  305. // Check if the item can be refined
  306. if( data.flag.no_refine ){
  307. return nullptr;
  308. }
  309. // Cap the refine level
  310. if( refine > MAX_REFINE ){
  311. refine = MAX_REFINE;
  312. }
  313. e_refine_type type;
  314. uint16 level;
  315. if( !this->calculate_refine_info( data, type, level ) ){
  316. return nullptr;
  317. }
  318. std::shared_ptr<s_refine_info> info = this->find( type );
  319. if( info == nullptr ){
  320. return nullptr;
  321. }
  322. std::shared_ptr<s_refine_levels_info> levels_info = util::umap_find( info->levels, level );
  323. if( levels_info == nullptr ){
  324. return nullptr;
  325. }
  326. return util::umap_find( levels_info->levels, refine );
  327. }
  328. std::shared_ptr<s_refine_level_info> RefineDatabase::findLevelInfo( const struct item_data& data, struct item& item ){
  329. // Check the current refine level
  330. if( item.refine >= MAX_REFINE ){
  331. return nullptr;
  332. }
  333. return this->findLevelInfoSub( data, item, item.refine );
  334. }
  335. std::shared_ptr<s_refine_level_info> RefineDatabase::findCurrentLevelInfo( const struct item_data& data, struct item& item ){
  336. if( item.refine > 0 ){
  337. return this->findLevelInfoSub( data, item, item.refine - 1 );
  338. }else{
  339. return nullptr;
  340. }
  341. }
  342. bool RefineDatabase::calculate_refine_info( const struct item_data& data, e_refine_type& refine_type, uint16& level ){
  343. if( data.type == IT_WEAPON ){
  344. refine_type = REFINE_TYPE_WEAPON;
  345. level = data.weapon_level;
  346. return true;
  347. }else if( data.type == IT_ARMOR ){
  348. refine_type = REFINE_TYPE_ARMOR;
  349. level = data.armor_level;
  350. return true;
  351. }else if( data.type == IT_SHADOWGEAR ){
  352. if( data.equip == EQP_SHADOW_WEAPON ){
  353. refine_type = REFINE_TYPE_SHADOW_WEAPON;
  354. }else{
  355. refine_type = REFINE_TYPE_SHADOW_ARMOR;
  356. }
  357. level = 1;
  358. return true;
  359. }else{
  360. return false;
  361. }
  362. }
  363. RefineDatabase refine_db;
  364. const std::string SizeFixDatabase::getDefaultLocation() {
  365. return std::string(db_path) + "/size_fix.yml";
  366. }
  367. /**
  368. * Reads and parses an entry from size_fix.
  369. * @param node: YAML node containing the entry.
  370. * @return count of successfully parsed rows
  371. */
  372. uint64 SizeFixDatabase::parseBodyNode(const ryml::NodeRef& node) {
  373. std::string weapon_name;
  374. if (!this->asString(node, "Weapon", weapon_name))
  375. return 0;
  376. std::string weapon_name_constant = "W_" + weapon_name;
  377. int64 constant;
  378. if (!script_get_constant(weapon_name_constant.c_str(), &constant)) {
  379. this->invalidWarning(node["Weapon"], "Size Fix unknown weapon %s, skipping.\n", weapon_name.c_str());
  380. return 0;
  381. }
  382. if (constant < W_FIST || constant > W_2HSTAFF) {
  383. this->invalidWarning(node["Weapon"], "Size Fix weapon %s is an invalid weapon, skipping.\n", weapon_name.c_str());
  384. return 0;
  385. }
  386. int weapon_id = static_cast<int>(constant);
  387. std::shared_ptr<s_sizefix_db> size = this->find(weapon_id);
  388. bool exists = size != nullptr;
  389. if (!exists)
  390. size = std::make_shared<s_sizefix_db>();
  391. if (this->nodeExists(node, "Small")) {
  392. uint16 small;
  393. if (!this->asUInt16(node, "Small", small))
  394. return 0;
  395. if (small > 100) {
  396. this->invalidWarning(node["Small"], "Small Size Fix %d for %s is out of bounds, defaulting to 100.\n", small, weapon_name.c_str());
  397. small = 100;
  398. }
  399. size->small = small;
  400. } else {
  401. if (!exists)
  402. size->small = 100;
  403. }
  404. if (this->nodeExists(node, "Medium")) {
  405. uint16 medium;
  406. if (!this->asUInt16(node, "Medium", medium))
  407. return 0;
  408. if (medium > 100) {
  409. this->invalidWarning(node["Medium"], "Medium Size Fix %d for %s is out of bounds, defaulting to 100.\n", medium, weapon_name.c_str());
  410. medium = 100;
  411. }
  412. size->medium = medium;
  413. } else {
  414. if (!exists)
  415. size->medium = 100;
  416. }
  417. if (this->nodeExists(node, "Large")) {
  418. uint16 large;
  419. if (!this->asUInt16(node, "Large", large))
  420. return 0;
  421. if (large > 100) {
  422. this->invalidWarning(node["Large"], "Large Size Fix %d for %s is out of bounds, defaulting to 100.\n", large, weapon_name.c_str());
  423. large = 100;
  424. }
  425. size->large = large;
  426. } else {
  427. if (!exists)
  428. size->large = 100;
  429. }
  430. if (!exists)
  431. this->put(weapon_id, size);
  432. return 1;
  433. }
  434. SizeFixDatabase size_fix_db;
  435. /**
  436. * Get icon ID of SC
  437. * @param type: SC type
  438. * @return EFST ID
  439. **/
  440. efst_type StatusDatabase::getIcon(sc_type type) {
  441. std::shared_ptr<s_status_change_db> status = status_db.find(type);
  442. return status ? status->icon : EFST_BLANK;
  443. }
  444. /**
  445. * Get flag of SC (SCB value) for status_calc_ flag
  446. * @param type: SC type
  447. * @return cal_flag: Calc value
  448. **/
  449. std::bitset<SCB_MAX> StatusDatabase::getCalcFlag(sc_type type) {
  450. std::shared_ptr<s_status_change_db> status = status_db.find(type);
  451. return status ? status->calc_flag : std::bitset<SCB_MAX> {};
  452. }
  453. /**
  454. * Get SC's END list
  455. * @param sc: SC type
  456. * @return End list
  457. **/
  458. std::vector<sc_type> StatusDatabase::getEnd(sc_type type) {
  459. std::shared_ptr<s_status_change_db> status = status_db.find(type);
  460. return status ? status->end : std::vector<sc_type> {};
  461. }
  462. /**
  463. * Get BL type to display proper effect
  464. * @param efst: EFST type
  465. * @return BL types
  466. **/
  467. uint16 status_efst_get_bl_type(enum efst_type efst) {
  468. if (efst <= EFST_BLANK || efst >= EFST_MAX)
  469. return BL_PC;
  470. return status_db.StatusRelevantBLTypes[efst];
  471. }
  472. /**
  473. * Returns the FIRST skill (in order of definition in initChangeTables) to use a given status change.
  474. * Utilized for various duration lookups. Use with caution!
  475. * @param sc The status to look up
  476. * @return A skill associated with the status
  477. **/
  478. uint16 StatusDatabase::getSkill(sc_type type) {
  479. std::shared_ptr<s_status_change_db> status = status_db.find(type);
  480. return status ? status->skill_id : 0;
  481. }
  482. /**
  483. * Returns if a status change flag is active or not for a SC.
  484. * @param sc: Status changes active on target
  485. * @param flag: Flag to check for
  486. * @return True if flag is set or false otherwise
  487. */
  488. bool StatusDatabase::hasSCF(status_change *sc, e_status_change_flag flag) {
  489. if (sc == nullptr || sc->count == 0 || flag == SCF_NONE)
  490. return false;
  491. for (const auto &status_it : *this) {
  492. std::shared_ptr<s_status_change_db> status = status_it.second;
  493. if (sc->data[status->type] && status->flag[flag])
  494. return true;
  495. }
  496. return false;
  497. }
  498. /**
  499. * Returns the SCB_BATTLE constant.
  500. * return SCB_BATTLE
  501. */
  502. std::bitset<SCB_MAX> StatusDatabase::getSCB_BATTLE() {
  503. return this->SCB_BATTLE;
  504. }
  505. /**
  506. * Returns the SCB_ALL constant.
  507. * @return SCB_ALL
  508. */
  509. std::bitset<SCB_MAX> StatusDatabase::getSCB_ALL() {
  510. return this->SCB_ALL;
  511. }
  512. /**
  513. * Removes statuses from skills that aren't part of the new class skill tree.
  514. * @param sd: Player data
  515. */
  516. void StatusDatabase::changeSkillTree(map_session_data *sd, int32 class_) {
  517. if (sd == nullptr)
  518. return;
  519. std::shared_ptr<s_skill_tree> tree = skill_tree_db.find(class_ > 0 ? class_ : sd->status.class_);
  520. if (tree == nullptr)
  521. return;
  522. for (const auto &it : tree->skills) {
  523. uint16 skill_id = it.first;
  524. sc_type sc = skill_get_sc(skill_id);
  525. if (sc > SC_COMMON_MAX && sc < SC_MAX && sd->sc.data[sc])
  526. status_change_end(&sd->bl, sc, INVALID_TIMER);
  527. }
  528. }
  529. /**
  530. * Validates if type is in SC ranges
  531. * @param type: SC type
  532. * @return True if type is in range, false otherwise
  533. */
  534. bool StatusDatabase::validateStatus(sc_type type) {
  535. if (type > SC_NONE && type < SC_MAX)
  536. return true;
  537. return false;
  538. }
  539. /**
  540. * Removes a status based on the provided flag(s).
  541. * @param bl: Target to remove status from
  542. * @param flag: List of flags to check for removing
  543. */
  544. void StatusDatabase::removeByStatusFlag(block_list *bl, std::vector<e_status_change_flag> flag) {
  545. if (bl == nullptr || flag.empty())
  546. return;
  547. status_change *sc = status_get_sc(bl);
  548. if (sc == nullptr || sc->count == 0)
  549. return;
  550. for (const auto &status_it : *this) {
  551. std::shared_ptr<s_status_change_db> status = status_it.second;
  552. sc_type type = status->type;
  553. if (sc->data[type]) {
  554. for (const auto &flag_it : flag) {
  555. if (status->flag[flag_it])
  556. status_change_end(bl, type, INVALID_TIMER);
  557. }
  558. }
  559. }
  560. }
  561. /** Creates dummy status */
  562. static void initDummyData(void) {
  563. memset(&dummy_status, 0, sizeof(dummy_status));
  564. dummy_status.hp =
  565. dummy_status.max_hp =
  566. dummy_status.max_sp =
  567. dummy_status.str =
  568. dummy_status.agi =
  569. dummy_status.vit =
  570. dummy_status.int_ =
  571. dummy_status.dex =
  572. dummy_status.luk =
  573. dummy_status.hit = 1;
  574. dummy_status.speed = 2000;
  575. dummy_status.adelay = 4000;
  576. dummy_status.amotion = 2000;
  577. dummy_status.dmotion = 2000;
  578. dummy_status.ele_lv = 1; // Min elemental level.
  579. dummy_status.mode = MD_CANMOVE;
  580. }
  581. /**
  582. * For copying a status_data structure from b to a, without overwriting current Hp, Sp, and Ap.
  583. * @param a: Status data structure to copy from
  584. * @param b: Status data structure to copy to
  585. */
  586. static inline void status_cpy(struct status_data* a, const struct status_data* b)
  587. {
  588. memcpy((void*)&a->max_hp, (const void*)&b->max_hp, sizeof(struct status_data)-(sizeof(a->hp)+sizeof(a->sp)+sizeof(a->ap)));
  589. }
  590. /**
  591. * Sets HP to a given value
  592. * Will always succeed (overrides heal impediment statuses) but can't kill an object
  593. * @param bl: Object whose HP will be set [PC|MOB|HOM|MER|ELEM|NPC]
  594. * @param hp: What the HP is to be set as
  595. * @param flag: Used in case final value is higher than current
  596. * Use 2 to display healing effect
  597. * @return heal or zapped HP if valid
  598. */
  599. int status_set_hp(struct block_list *bl, unsigned int hp, int flag)
  600. {
  601. struct status_data *status;
  602. if (hp < 1)
  603. return 0;
  604. status = status_get_status_data(bl);
  605. if (status == &dummy_status)
  606. return 0;
  607. if (hp > status->max_hp)
  608. hp = status->max_hp;
  609. if (hp == status->hp)
  610. return 0;
  611. if (hp > status->hp)
  612. return status_heal(bl, hp - status->hp, 0, 1|flag);
  613. return status_zap(bl, status->hp - hp, 0);
  614. }
  615. /**
  616. * Sets Max HP to a given value
  617. * @param bl: Object whose Max HP will be set [PC|MOB|HOM|MER|ELEM|NPC]
  618. * @param maxhp: What the Max HP is to be set as
  619. * @param flag: Used in case final value is higher than current
  620. * Use 2 to display healing effect
  621. * @return heal or zapped HP if valid
  622. */
  623. int status_set_maxhp(struct block_list *bl, unsigned int maxhp, int flag)
  624. {
  625. struct status_data *status;
  626. int64 heal;
  627. if (maxhp < 1)
  628. return 0;
  629. status = status_get_status_data(bl);
  630. if (status == &dummy_status)
  631. return 0;
  632. if (maxhp == status->max_hp)
  633. return 0;
  634. heal = maxhp - status->max_hp;
  635. status->max_hp = maxhp;
  636. if (heal > 0)
  637. status_heal(bl, heal, 0, 1|flag);
  638. else
  639. status_zap(bl, -heal, 0);
  640. return maxhp;
  641. }
  642. /**
  643. * Sets SP to a given value
  644. * @param bl: Object whose SP will be set [PC|HOM|MER|ELEM]
  645. * @param sp: What the SP is to be set as
  646. * @param flag: Used in case final value is higher than current
  647. * Use 2 to display healing effect
  648. * @return heal or zapped SP if valid
  649. */
  650. int status_set_sp(struct block_list *bl, unsigned int sp, int flag)
  651. {
  652. struct status_data *status;
  653. status = status_get_status_data(bl);
  654. if (status == &dummy_status)
  655. return 0;
  656. if (sp > status->max_sp)
  657. sp = status->max_sp;
  658. if (sp == status->sp)
  659. return 0;
  660. if (sp > status->sp)
  661. return status_heal(bl, 0, sp - status->sp, 1|flag);
  662. return status_zap(bl, 0, status->sp - sp);
  663. }
  664. /**
  665. * Sets Max SP to a given value
  666. * @param bl: Object whose Max SP will be set [PC|HOM|MER|ELEM]
  667. * @param maxsp: What the Max SP is to be set as
  668. * @param flag: Used in case final value is higher than current
  669. * Use 2 to display healing effect
  670. * @return heal or zapped HP if valid
  671. */
  672. int status_set_maxsp(struct block_list *bl, unsigned int maxsp, int flag)
  673. {
  674. struct status_data *status;
  675. if (maxsp < 1)
  676. return 0;
  677. status = status_get_status_data(bl);
  678. if (status == &dummy_status)
  679. return 0;
  680. if (maxsp == status->max_sp)
  681. return 0;
  682. if (maxsp > status->max_sp)
  683. status_heal(bl, maxsp - status->max_sp, 0, 1|flag);
  684. else
  685. status_zap(bl, status->max_sp - maxsp, 0);
  686. status->max_sp = maxsp;
  687. return maxsp;
  688. }
  689. /**
  690. * Sets AP to a given value
  691. * @param bl: Object whose AP will be set [PC|HOM|MER|ELEM]
  692. * @param ap: What the AP is to be set as
  693. * @param flag: Used in case final value is higher than current
  694. * Use 2 to display healing effect
  695. * @return heal or zapped AP if valid
  696. */
  697. int status_set_ap(struct block_list *bl, unsigned int ap, int flag)
  698. {
  699. status_data *status = status_get_status_data(bl);
  700. if (status == &dummy_status)
  701. return 0;
  702. if (ap > status->max_ap)
  703. ap = status->max_ap;
  704. if (ap == status->ap)
  705. return 0;
  706. if (ap > status->ap)
  707. return status_heal(bl, 0, 0, ap - status->ap, 1 | flag);
  708. return status_zap(bl, 0, 0, status->ap - ap);
  709. }
  710. /**
  711. * Sets Max AP to a given value
  712. * @param bl: Object whose Max AP will be set [PC|HOM|MER|ELEM]
  713. * @param maxap: What the Max AP is to be set as
  714. * @param flag: Used in case final value is higher than current
  715. * Use 2 to display healing effect
  716. * @return heal or zapped AP if valid
  717. */
  718. int status_set_maxap(struct block_list *bl, unsigned int maxap, int flag)
  719. {
  720. if (maxap < 1)
  721. return 0;
  722. status_data *status = status_get_status_data(bl);
  723. if (status == &dummy_status)
  724. return 0;
  725. if (maxap == status->max_ap)
  726. return 0;
  727. if (maxap > status->max_ap)
  728. status_heal(bl, 0, 0, maxap - status->max_ap, 1 | flag);
  729. else
  730. status_zap(bl, 0, 0, status->max_ap - maxap);
  731. status->max_ap = maxap;
  732. return maxap;
  733. }
  734. /**
  735. * Takes HP/SP from an Object
  736. * @param bl: Object who will have HP/SP taken [PC|MOB|HOM|MER|ELEM]
  737. * @param hp: How much HP to charge
  738. * @param sp: How much SP to charge
  739. * @return hp+sp through status_damage()
  740. * Note: HP/SP are integer values, not percentages. Values should be
  741. * calculated either within function call or before
  742. */
  743. int64 status_charge(struct block_list* bl, int64 hp, int64 sp)
  744. {
  745. if(!(bl->type&BL_CONSUME))
  746. return (int)hp+sp; // Assume all was charged so there are no 'not enough' fails.
  747. return status_damage(NULL, bl, hp, sp, 0, 3, 0);
  748. }
  749. /**
  750. * Inflicts damage on the target with the according walkdelay.
  751. * @param src: Source object giving damage [PC|MOB|PET|HOM|MER|ELEM]
  752. * @param target: Target of the damage
  753. * @param dhp: How much damage to HP
  754. * @param dsp: How much damage to SP
  755. * @param dap: How much damage to AP
  756. * @param walkdelay: Amount of time before object can walk again
  757. * @param flag: Damage flag decides various options
  758. * flag&1: Passive damage - Does not trigger cancelling status changes
  759. * flag&2: Fail if there is not enough to subtract
  760. * flag&4: Mob does not give EXP/Loot if killed
  761. * flag&8: Used to damage SP of a dead character
  762. * @return hp+sp+ap
  763. * Note: HP/SP/AP are integer values, not percentages. Values should be
  764. * calculated either within function call or before
  765. */
  766. int status_damage(struct block_list *src,struct block_list *target,int64 dhp, int64 dsp, int64 dap, t_tick walkdelay, int flag, uint16 skill_id)
  767. {
  768. struct status_data *status;
  769. struct status_change *sc;
  770. int hp = (int)cap_value(dhp,INT_MIN,INT_MAX);
  771. int sp = (int)cap_value(dsp,INT_MIN,INT_MAX);
  772. int ap = (int)cap_value(dap,INT_MIN,INT_MAX);
  773. nullpo_ret(target);
  774. if(sp && !(target->type&BL_CONSUME))
  775. sp = 0; // Not a valid SP target.
  776. if (ap && !(target->type&BL_CONSUME))
  777. ap = 0; // Not a valid AP target.
  778. if (hp < 0) { // Assume absorbed damage.
  779. status_heal(target, -hp, 0, 1);
  780. hp = 0;
  781. }
  782. if (sp < 0) {
  783. status_heal(target, 0, -sp, 1);
  784. sp = 0;
  785. }
  786. if (ap < 0) {
  787. status_heal(target, 0, 0, -ap, 1);
  788. ap = 0;
  789. }
  790. if (target->type == BL_SKILL) {
  791. if (!src || src->type&battle_config.can_damage_skill)
  792. return (int)skill_unit_ondamaged((struct skill_unit *)target, hp);
  793. return 0;
  794. }
  795. status = status_get_status_data(target);
  796. if(!status || status == &dummy_status )
  797. return 0;
  798. if ((unsigned int)hp >= status->hp) {
  799. if (flag&2) return 0;
  800. hp = status->hp;
  801. }
  802. if ((unsigned int)sp > status->sp) {
  803. if (flag&2) return 0;
  804. sp = status->sp;
  805. }
  806. if ((unsigned int)ap > status->ap) {
  807. if (flag & 2) return 0;
  808. ap = status->ap;
  809. }
  810. if (!hp && !sp && !ap)
  811. return 0;
  812. if( !status->hp )
  813. flag |= 8;
  814. sc = status_get_sc(target);
  815. if( hp && battle_config.invincible_nodamage && src && sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
  816. hp = 1;
  817. if( hp && !(flag&1) ) {
  818. if( sc ) {
  819. struct status_change_entry *sce;
  820. for (const auto &it : status_db) {
  821. sc_type type = static_cast<sc_type>(it.first);
  822. if (sc->data[type] && it.second->flag[SCF_REMOVEONDAMAGED]) {
  823. // 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).
  824. // !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.
  825. if (sc->opt1 > OPT1_NONE && sc->lastEffectTimer == INVALID_TIMER) {
  826. sc->lastEffectTimer = add_timer(gettick() + 10, status_clear_lastEffect_timer, target->id, 0);
  827. sc->lastEffect = type;
  828. }
  829. status_change_end(target, type, INVALID_TIMER);
  830. }
  831. }
  832. if ((sce=sc->data[SC_ENDURE]) && !sce->val4) {
  833. /** [Skotlex]
  834. * Endure count is only reduced by non-players on non-gvg maps.
  835. * val4 signals infinite endure.
  836. **/
  837. if (src && src->type != BL_PC && !map_flag_gvg2(target->m) && !map_getmapflag(target->m, MF_BATTLEGROUND) && --(sce->val2) <= 0)
  838. status_change_end(target, SC_ENDURE, INVALID_TIMER);
  839. }
  840. #ifndef RENEWAL
  841. if ((sce=sc->data[SC_GRAVITATION]) && sce->val3 == BCT_SELF) {
  842. std::shared_ptr<s_skill_unit_group> sg = skill_id2group(sce->val4);
  843. if (sg) {
  844. skill_delunitgroup(sg);
  845. sce->val4 = 0;
  846. status_change_end(target, SC_GRAVITATION, INVALID_TIMER);
  847. }
  848. }
  849. #endif
  850. if(sc->data[SC_DANCING] && (unsigned int)hp > status->max_hp>>2)
  851. status_change_end(target, SC_DANCING, INVALID_TIMER);
  852. if(sc->data[SC_CLOAKINGEXCEED] && --(sc->data[SC_CLOAKINGEXCEED]->val2) <= 0)
  853. status_change_end(target, SC_CLOAKINGEXCEED, INVALID_TIMER);
  854. if(sc->data[SC_KAGEMUSYA] && --(sc->data[SC_KAGEMUSYA]->val3) <= 0)
  855. status_change_end(target, SC_KAGEMUSYA, INVALID_TIMER);
  856. }
  857. if (target->type == BL_PC)
  858. pc_bonus_script_clear(BL_CAST(BL_PC,target),BSF_REM_ON_DAMAGED);
  859. unit_skillcastcancel(target, 2);
  860. }
  861. status->hp-= hp;
  862. status->sp-= sp;
  863. status->ap-= ap;
  864. if (sc && hp && status->hp) {
  865. if (sc->data[SC_AUTOBERSERK] &&
  866. (!sc->data[SC_PROVOKE] || !sc->data[SC_PROVOKE]->val4) &&
  867. status->hp < status->max_hp>>2)
  868. sc_start4(src,target,SC_PROVOKE,100,10,0,0,1,0);
  869. if (sc->data[SC_BERSERK] && status->hp <= 100)
  870. status_change_end(target, SC_BERSERK, INVALID_TIMER);
  871. if( sc->data[SC_RAISINGDRAGON] && status->hp <= 1000 )
  872. status_change_end(target, SC_RAISINGDRAGON, INVALID_TIMER);
  873. if (sc->data[SC_SATURDAYNIGHTFEVER] && status->hp <= 100)
  874. status_change_end(target, SC_SATURDAYNIGHTFEVER, INVALID_TIMER);
  875. }
  876. switch (target->type) {
  877. case BL_PC: pc_damage((TBL_PC*)target,src,hp,sp,ap); break;
  878. case BL_MOB: mob_damage((TBL_MOB*)target, src, hp); break;
  879. case BL_HOM: hom_damage((TBL_HOM*)target); break;
  880. case BL_MER: mercenary_heal((TBL_MER*)target,hp,sp); break;
  881. case BL_ELEM: elemental_heal((TBL_ELEM*)target,hp,sp); break;
  882. }
  883. if( src && target->type == BL_PC && ((TBL_PC*)target)->disguise ) { // Stop walking when attacked in disguise to prevent walk-delay bug
  884. unit_stop_walking( target, 1 );
  885. }
  886. if( status->hp || (flag&8) ) { // Still lives or has been dead before this damage.
  887. if (walkdelay)
  888. unit_set_walkdelay(target, gettick(), walkdelay, 0);
  889. return (int)(hp+sp+ap);
  890. }
  891. status->hp = 0;
  892. /** [Skotlex]
  893. * NOTE: These dead functions should return:
  894. * 0: Death cancelled, auto-revived.
  895. * Non-zero: Standard death. Clear status, cancel move/attack, etc
  896. * &2: Remove object from map.
  897. * &4: Delete object from memory. (One time spawn mobs)
  898. **/
  899. switch (target->type) {
  900. case BL_PC: flag = pc_dead((TBL_PC*)target,src); break;
  901. case BL_MOB: flag = mob_dead((TBL_MOB*)target, src, flag&4?3:0); break;
  902. case BL_HOM: flag = hom_dead((TBL_HOM*)target); break;
  903. case BL_MER: flag = mercenary_dead((TBL_MER*)target); break;
  904. case BL_ELEM: flag = elemental_dead((TBL_ELEM*)target); break;
  905. default: // Unhandled case, do nothing to object.
  906. flag = 0;
  907. break;
  908. }
  909. if(!flag) // Death cancelled.
  910. return (int)(hp+sp+ap);
  911. // Normal death
  912. if (battle_config.clear_unit_ondeath &&
  913. battle_config.clear_unit_ondeath&target->type)
  914. skill_clear_unitgroup(target);
  915. if(target->type&BL_REGEN) { // Reset regen ticks.
  916. struct regen_data *regen = status_get_regen_data(target);
  917. if (regen) {
  918. memset(&regen->tick, 0, sizeof(regen->tick));
  919. if (regen->sregen)
  920. memset(&regen->sregen->tick, 0, sizeof(regen->sregen->tick));
  921. if (regen->ssregen)
  922. memset(&regen->ssregen->tick, 0, sizeof(regen->ssregen->tick));
  923. }
  924. }
  925. if( sc && sc->data[SC_KAIZEL] && !map_flag_gvg2(target->m) ) { // flag&8 = disable Kaizel
  926. int time = skill_get_time2(SL_KAIZEL,sc->data[SC_KAIZEL]->val1);
  927. // Look for Osiris Card's bonus effect on the character and revive 100% or revive normally
  928. if ( target->type == BL_PC && BL_CAST(BL_PC,target)->special_state.restart_full_recover )
  929. status_revive(target, 100, 100);
  930. else
  931. status_revive(target, sc->data[SC_KAIZEL]->val2, 0);
  932. status_change_clear(target,0);
  933. clif_skill_nodamage(target,target,ALL_RESURRECTION,1,1);
  934. sc_start(src,target,SC_KYRIE,100,10,time);
  935. if( target->type == BL_MOB )
  936. ((TBL_MOB*)target)->state.rebirth = 1;
  937. return (int)(hp+sp+ap);
  938. }
  939. // Disable Ultimate Sacrifice on GVG maps
  940. if (sc && sc->data[SC_ULTIMATE_S] && !map_flag_gvg2(target->m)) {
  941. status_revive(target, 100, 100);
  942. status_change_clear(target, 0);
  943. clif_skill_nodamage(target, target, ALL_RESURRECTION, 1, 1);
  944. if (target->type == BL_MOB)
  945. ((TBL_MOB*)target)->state.rebirth = 1;
  946. return (int)(hp+sp+ap);
  947. }
  948. if (target->type == BL_MOB && sc && sc->data[SC_REBIRTH] && !((TBL_MOB*) target)->state.rebirth) { // Ensure the monster has not already rebirthed before doing so.
  949. status_revive(target, sc->data[SC_REBIRTH]->val2, 0);
  950. status_change_clear(target,0);
  951. ((TBL_MOB*)target)->state.rebirth = 1;
  952. return (int)(hp+sp+ap);
  953. }
  954. status_change_clear(target,0);
  955. if(flag&4) // Delete from memory. (also invokes map removal code)
  956. unit_free(target,CLR_DEAD);
  957. else if(flag&2) // remove from map
  958. unit_remove_map(target,CLR_DEAD);
  959. else { // Some death states that would normally be handled by unit_remove_map
  960. unit_stop_attack(target);
  961. unit_stop_walking(target,1);
  962. unit_skillcastcancel(target,0);
  963. clif_clearunit_area(target,CLR_DEAD);
  964. skill_unit_move(target,gettick(),4);
  965. skill_cleartimerskill(target);
  966. }
  967. // Always run NPC scripts for players last
  968. //FIXME those ain't always run if a player die if he was resurrect meanwhile
  969. //cf SC_REBIRTH, SC_KAIZEL, pc_dead...
  970. if(target->type == BL_PC) {
  971. TBL_PC *sd = BL_CAST(BL_PC,target);
  972. if( sd->bg_id ) {
  973. std::shared_ptr<s_battleground_data> bg = util::umap_find(bg_team_db, sd->bg_id);
  974. if( bg && !(bg->die_event.empty()) )
  975. npc_event(sd, bg->die_event.c_str(), 0);
  976. }
  977. npc_script_event(sd,NPCE_DIE);
  978. }
  979. return (int)(hp+sp+ap);
  980. }
  981. /**
  982. * Heals an object
  983. * @param bl: Object to heal [PC|MOB|HOM|MER|ELEM]
  984. * @param hhp: How much HP to heal
  985. * @param hsp: How much SP to heal
  986. * @param hap: How much AP to heal
  987. * @param flag: Whether it's Forced(&1), gives HP/SP/AP(&2) heal effect,
  988. * or gives HP(&4) heal effect with 0 heal
  989. * Forced healing overrides heal impedement statuses (Berserk)
  990. * @return hp+sp+ap
  991. */
  992. int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int64 hap, int flag)
  993. {
  994. struct status_data *status;
  995. struct status_change *sc;
  996. int hp = (int)cap_value(hhp,INT_MIN,INT_MAX);
  997. int sp = (int)cap_value(hsp,INT_MIN,INT_MAX);
  998. int ap = (int)cap_value(hap,INT_MIN,INT_MAX);
  999. status = status_get_status_data(bl);
  1000. if (status == &dummy_status || !status->hp)
  1001. return 0;
  1002. sc = status_get_sc(bl);
  1003. if (sc && !sc->count)
  1004. sc = NULL;
  1005. if (hp < 0) {
  1006. if (hp == INT_MIN) // -INT_MIN == INT_MIN in some architectures!
  1007. hp++;
  1008. status_damage(NULL, bl, -hp, 0, 0, 1, 0);
  1009. hp = 0;
  1010. }
  1011. if(hp) {
  1012. if( sc && (sc->data[SC_BERSERK]) ) {
  1013. if( flag&1 )
  1014. flag &= ~2;
  1015. else
  1016. hp = 0;
  1017. }
  1018. if((unsigned int)hp > status->max_hp - status->hp)
  1019. hp = status->max_hp - status->hp;
  1020. }
  1021. if(sp < 0) {
  1022. if (sp == INT_MIN)
  1023. sp++;
  1024. status_damage(NULL, bl, 0, -sp, 0, 1, 0);
  1025. sp = 0;
  1026. }
  1027. if(sp) {
  1028. if((unsigned int)sp > status->max_sp - status->sp)
  1029. sp = status->max_sp - status->sp;
  1030. }
  1031. if (ap < 0) {
  1032. if (ap == INT_MIN)
  1033. ap++;
  1034. status_damage(nullptr, bl, 0, 0, -ap, 0, 1, 0);
  1035. ap = 0;
  1036. }
  1037. if (ap) {
  1038. if ((unsigned int)ap > status->max_ap - status->ap)
  1039. ap = status->max_ap - status->ap;
  1040. }
  1041. if(!ap && !sp && !hp && !(flag&4))
  1042. return 0;
  1043. status->hp += hp;
  1044. status->sp += sp;
  1045. status->ap += ap;
  1046. if(hp && sc &&
  1047. sc->data[SC_AUTOBERSERK] &&
  1048. sc->data[SC_PROVOKE] &&
  1049. sc->data[SC_PROVOKE]->val4==1 &&
  1050. status->hp>=status->max_hp>>2
  1051. ) // End auto berserk.
  1052. status_change_end(bl, SC_PROVOKE, INVALID_TIMER);
  1053. // Send HP update to client
  1054. switch(bl->type) {
  1055. case BL_PC: pc_heal((TBL_PC*)bl,hp,sp,ap,flag); break;
  1056. case BL_MOB: mob_heal((TBL_MOB*)bl,hp); break;
  1057. case BL_HOM: hom_heal((TBL_HOM*)bl); break;
  1058. case BL_MER: mercenary_heal((TBL_MER*)bl,hp,sp); break;
  1059. case BL_ELEM: elemental_heal((TBL_ELEM*)bl,hp,sp); break;
  1060. }
  1061. return (int)hp+sp+ap;
  1062. }
  1063. /**
  1064. * Applies percentage based damage to a unit.
  1065. * If a mob is killed this way and there is no src, no EXP/Drops will be awarded.
  1066. * @param src: Object initiating HP/SP/AP modification [PC|MOB|PET|HOM|MER|ELEM]
  1067. * @param target: Object to modify HP/SP/AP
  1068. * @param hp_rate: Percentage of HP to modify. If > 0:percent is of current HP, if < 0:percent is of max HP
  1069. * @param sp_rate: Percentage of SP to modify. If > 0:percent is of current SP, if < 0:percent is of max SP
  1070. * @param ap_rate: Percentage of AP to modify. If > 0:percent is of current AP, if < 0:percent is of max AP
  1071. * @param flag: \n
  1072. * 0: Heal target \n
  1073. * 1: Use status_damage \n
  1074. * 2: Use status_damage and make sure target must not die from subtraction
  1075. * @return hp+sp+ap through status_heal()
  1076. */
  1077. int status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, int8 ap_rate, uint8 flag)
  1078. {
  1079. struct status_data *status;
  1080. unsigned int hp = 0, sp = 0, ap = 0;
  1081. status = status_get_status_data(target);
  1082. // It's safe now [MarkZD]
  1083. if (hp_rate > 99)
  1084. hp = status->hp;
  1085. else if (hp_rate > 0)
  1086. hp = apply_rate(status->hp, hp_rate);
  1087. else if (hp_rate < -99)
  1088. hp = status->max_hp;
  1089. else if (hp_rate < 0)
  1090. hp = (apply_rate(status->max_hp, -hp_rate));
  1091. if (hp_rate && !hp)
  1092. hp = 1;
  1093. if (flag == 2 && hp >= status->hp)
  1094. hp = status->hp-1; // Must not kill target.
  1095. if (sp_rate > 99)
  1096. sp = status->sp;
  1097. else if (sp_rate > 0)
  1098. sp = apply_rate(status->sp, sp_rate);
  1099. else if (sp_rate < -99)
  1100. sp = status->max_sp;
  1101. else if (sp_rate < 0)
  1102. sp = (apply_rate(status->max_sp, -sp_rate));
  1103. if (sp_rate && !sp)
  1104. sp = 1;
  1105. if (ap_rate > 99)
  1106. ap = status->ap;
  1107. else if (ap_rate > 0)
  1108. ap = apply_rate(status->ap, ap_rate);
  1109. else if (ap_rate < -99)
  1110. ap = status->max_ap;
  1111. else if (ap_rate < 0)
  1112. ap = (apply_rate(status->max_ap, -ap_rate));
  1113. if (ap_rate && !ap)
  1114. ap = 1;
  1115. // Ugly check in case damage dealt is too much for the received args of
  1116. // status_heal / status_damage. [Skotlex]
  1117. if (hp > INT_MAX) {
  1118. hp -= INT_MAX;
  1119. if (flag)
  1120. status_damage(src, target, INT_MAX, 0, 0, (!src||src==target?5:1), 0);
  1121. else
  1122. status_heal(target, INT_MAX, 0, 0);
  1123. }
  1124. if (sp > INT_MAX) {
  1125. sp -= INT_MAX;
  1126. if (flag)
  1127. status_damage(src, target, 0, INT_MAX, 0, (!src||src==target?5:1), 0);
  1128. else
  1129. status_heal(target, 0, INT_MAX, 0);
  1130. }
  1131. if (ap > INT_MAX) {
  1132. ap -= INT_MAX;
  1133. if (flag)
  1134. status_damage(src, target, 0, 0, INT_MAX, 0, (!src || src == target ? 5 : 1), 0);
  1135. else
  1136. status_heal(target, 0, 0, INT_MAX, 0);
  1137. }
  1138. if (flag)
  1139. return status_damage(src, target, hp, sp, ap, 0, (!src||src==target?5:1), 0);
  1140. return status_heal(target, hp, sp, ap, 0);
  1141. }
  1142. /**
  1143. * Revives a unit
  1144. * @param bl: Object to revive [PC|MOB|HOM]
  1145. * @param per_hp: Percentage of HP to revive with
  1146. * @param per_sp: Percentage of SP to revive with
  1147. * @param per_ap: Percentage of AP to revive with
  1148. * @return Successful (1) or Invalid target (0)
  1149. */
  1150. int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp, unsigned char per_ap)
  1151. {
  1152. struct status_data *status;
  1153. unsigned int hp, sp, ap;
  1154. if (!status_isdead(bl)) return 0;
  1155. status = status_get_status_data(bl);
  1156. if (status == &dummy_status)
  1157. return 0; // Invalid target.
  1158. hp = (int64)status->max_hp * per_hp/100;
  1159. sp = (int64)status->max_sp * per_sp/100;
  1160. ap = (int64)status->max_ap * per_ap/100;
  1161. if(hp > status->max_hp - status->hp)
  1162. hp = status->max_hp - status->hp;
  1163. else if (per_hp && !hp)
  1164. hp = 1;
  1165. if(sp > status->max_sp - status->sp)
  1166. sp = status->max_sp - status->sp;
  1167. else if (per_sp && !sp)
  1168. sp = 1;
  1169. if (ap > status->max_ap - status->ap)
  1170. ap = status->max_ap - status->ap;
  1171. else if (per_ap && !ap)
  1172. ap = 1;
  1173. status->hp += hp;
  1174. status->sp += sp;
  1175. status->ap += ap;
  1176. if (bl->prev) // Animation only if character is already on a map.
  1177. clif_resurrection(bl, 1);
  1178. switch (bl->type) {
  1179. case BL_PC: pc_revive((TBL_PC*)bl, hp, sp, ap); break;
  1180. case BL_MOB: mob_revive((TBL_MOB*)bl, hp); break;
  1181. case BL_HOM: hom_revive((TBL_HOM*)bl, hp, sp); break;
  1182. }
  1183. return 1;
  1184. }
  1185. /**
  1186. * Checks whether the src can use the skill on the target,
  1187. * taking into account status/option of both source/target
  1188. * @param src: Object using skill on target [PC|MOB|PET|HOM|MER|ELEM]
  1189. src MAY be NULL to indicate we shouldn't check it, this is a ground-based skill attack
  1190. * @param target: Object being targeted by src [PC|MOB|HOM|MER|ELEM]
  1191. target MAY be NULL, which checks if src can cast skill_id on the ground
  1192. * @param skill_id: Skill ID being used on target
  1193. * @param flag: 0 - Trying to use skill on target
  1194. * 1 - Cast bar is done
  1195. * 2 - Skill already pulled off, check is due to ground-based skills or splash-damage ones
  1196. * @return src can use skill (1) or cannot use skill (0)
  1197. * @author [Skotlex]
  1198. */
  1199. bool status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int flag) {
  1200. struct status_data *status;
  1201. struct status_change *sc = NULL, *tsc;
  1202. int hide_flag;
  1203. status = src ? status_get_status_data(src) : &dummy_status;
  1204. if (src && src->type != BL_PC && status_isdead(src))
  1205. return false;
  1206. if (!skill_id) { // Normal attack checks.
  1207. if (sc && sc->cant.attack)
  1208. return false;
  1209. // This mode is only needed for melee attacking.
  1210. if (!status_has_mode(status,MD_CANATTACK))
  1211. return false;
  1212. // Dead state is not checked for skills as some skills can be used
  1213. // on dead characters, said checks are left to skill.cpp [Skotlex]
  1214. if (target && status_isdead(target))
  1215. return false;
  1216. }
  1217. switch( skill_id ) {
  1218. #ifndef RENEWAL
  1219. case PA_PRESSURE:
  1220. if( flag && target ) {
  1221. // Gloria Avoids pretty much everything....
  1222. tsc = status_get_sc(target);
  1223. if(tsc && tsc->option&OPTION_HIDE)
  1224. return false;
  1225. }
  1226. break;
  1227. #endif
  1228. case GN_WALLOFTHORN:
  1229. if( target && status_isdead(target) )
  1230. return false;
  1231. break;
  1232. case AL_TELEPORT:
  1233. case ALL_ODINS_POWER:
  1234. // Should fail when used on top of Land Protector [Skotlex]
  1235. if (src && map_getcell(src->m, src->x, src->y, CELL_CHKLANDPROTECTOR)
  1236. && !status_has_mode(status,MD_STATUSIMMUNE)
  1237. && (src->type != BL_PC || ((TBL_PC*)src)->skillitem != skill_id))
  1238. return false;
  1239. break;
  1240. case SC_MANHOLE:
  1241. // Skill is disabled against special racial grouped monsters(GvG and Battleground)
  1242. if (target && ( util::vector_exists(status_get_race2(target), RC2_GVG) || util::vector_exists(status_get_race2(target), RC2_BATTLEFIELD) ) )
  1243. return false;
  1244. default:
  1245. break;
  1246. }
  1247. if ( src )
  1248. sc = status_get_sc(src);
  1249. if( sc && sc->count ) {
  1250. if (sc->data[SC_ALL_RIDING])
  1251. return false; //You can't use skills while in the new mounts (The client doesn't let you, this is to make cheat-safe)
  1252. if (flag == 1 && !status_has_mode(status,MD_STATUSIMMUNE) && ( // Applies to after cast completion only and doesn't apply to Boss monsters.
  1253. (sc->data[SC_ASH] && rnd()%2) || // Volcanic Ash has a 50% chance of causing skills to fail.
  1254. (sc->data[SC_KYOMU] && rnd()%100 < 25) // Kyomu has a 25% chance of causing skills fail.
  1255. )) {
  1256. if (src->type == BL_PC)
  1257. clif_skill_fail((TBL_PC*)src,skill_id,USESKILL_FAIL_LEVEL,0);
  1258. return false;
  1259. }
  1260. if (skill_id && sc->cant.cast && skill_id != RK_REFRESH && skill_id != SU_GROOMING && skill_id != SR_GENTLETOUCH_CURE) { // Stuned/Frozen/etc
  1261. if (flag != 1) // Can't cast, casted stuff can't damage.
  1262. return false;
  1263. if (skill_get_casttype(skill_id) == CAST_DAMAGE)
  1264. return false; // Damage spells stop casting.
  1265. }
  1266. if (
  1267. (sc->data[SC_TRICKDEAD] && skill_id != NV_TRICKDEAD)
  1268. || (sc->data[SC_AUTOCOUNTER] && !flag && skill_id)
  1269. || (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF && skill_id != PA_GOSPEL)
  1270. || (sc->data[SC_SUHIDE] && skill_id != SU_HIDE)
  1271. )
  1272. return false;
  1273. if (sc->data[SC_WINKCHARM] && target && !flag) { // Prevents skill usage
  1274. if (unit_bl2ud(src) && (unit_bl2ud(src))->walktimer == INVALID_TIMER)
  1275. unit_walktobl(src, map_id2bl(sc->data[SC_WINKCHARM]->val2), 3, 1);
  1276. clif_emotion(src, ET_THROB);
  1277. return false;
  1278. }
  1279. if (sc->data[SC_BLADESTOP]) {
  1280. switch (sc->data[SC_BLADESTOP]->val1) {
  1281. case 5: if (skill_id == MO_EXTREMITYFIST) break;
  1282. case 4: if (skill_id == MO_CHAINCOMBO) break;
  1283. case 3: if (skill_id == MO_INVESTIGATE) break;
  1284. case 2: if (skill_id == MO_FINGEROFFENSIVE) break;
  1285. default: return false;
  1286. }
  1287. }
  1288. if (sc->data[SC_DANCING] && flag!=2) {
  1289. std::shared_ptr<s_skill_db> skill = skill_db.find(skill_id);
  1290. if (!skill)
  1291. return false;
  1292. if (src->type == BL_PC && ((skill_id >= WA_SWING_DANCE && skill_id <= WM_UNLIMITED_HUMMING_VOICE ) ||
  1293. skill_id == WM_FRIGG_SONG))
  1294. { // Lvl 5 Lesson or higher allow you use 3rd job skills while dancing.
  1295. if( pc_checkskill((TBL_PC*)src,WM_LESSON) < 5 )
  1296. return false;
  1297. #ifndef RENEWAL
  1298. } else if(sc->data[SC_LONGING]) { // Allow everything except dancing/re-dancing. [Skotlex]
  1299. if (skill_id == BD_ENCORE || skill->inf2[INF2_ISSONG] || skill->inf2[INF2_ISENSEMBLE])
  1300. return false;
  1301. #endif
  1302. } else if(!skill->inf2[INF2_ALLOWWHENPERFORMING]) // Skills that can be used in dancing state
  1303. return false;
  1304. #ifndef RENEWAL
  1305. if ((sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE && skill_id == BD_ADAPTATION)
  1306. return false; // Can't amp out of Wand of Hermode :/ [Skotlex]
  1307. #endif
  1308. }
  1309. if (skill_id && // Do not block item-casted skills.
  1310. (src->type != BL_PC || ((TBL_PC*)src)->skillitem != skill_id)
  1311. ) { // Skills blocked through status changes...
  1312. if (!flag && ( // Blocked only from using the skill (stuff like autospell may still go through
  1313. ( sc->cant.cast && skill_id != RK_REFRESH && skill_id != SU_GROOMING && skill_id != SR_GENTLETOUCH_CURE ) ||
  1314. #ifndef RENEWAL
  1315. (sc->data[SC_BASILICA] && (sc->data[SC_BASILICA]->val4 != src->id || skill_id != HP_BASILICA)) || // Only Basilica caster that can cast, and only Basilica to cancel it
  1316. #endif
  1317. (sc->data[SC_MARIONETTE] && skill_id != CG_MARIONETTE) || // Only skill you can use is marionette again to cancel it
  1318. (sc->data[SC_MARIONETTE2] && skill_id == CG_MARIONETTE) || // Cannot use marionette if you are being buffed by another
  1319. (sc->data[SC_ANKLE] && skill_block_check(src, SC_ANKLE, skill_id)) ||
  1320. (sc->data[SC_STASIS] && skill_block_check(src, SC_STASIS, skill_id)) ||
  1321. (sc->data[SC_BITE] && skill_block_check(src, SC_BITE, skill_id)) ||
  1322. (sc->data[SC_NOVAEXPLOSING] && skill_block_check(src, SC_NOVAEXPLOSING, skill_id)) ||
  1323. (sc->data[SC_GRAVITYCONTROL] && skill_block_check(src, SC_GRAVITYCONTROL, skill_id)) ||
  1324. (sc->data[SC_KAGEHUMI] && skill_block_check(src, SC_KAGEHUMI, skill_id))
  1325. #ifdef RENEWAL
  1326. || (sc->data[SC_ENSEMBLEFATIGUE] && skill_id != CG_SPECIALSINGER)
  1327. #endif
  1328. ))
  1329. return false;
  1330. // Skill blocking.
  1331. if (
  1332. (sc->data[SC_VOLCANO] && skill_id == WZ_ICEWALL) ||
  1333. #ifndef RENEWAL
  1334. (sc->data[SC_ROKISWEIL] && skill_id != BD_ADAPTATION) ||
  1335. #endif
  1336. (sc->data[SC_HERMODE] && skill_get_inf(skill_id) & INF_SUPPORT_SKILL) ||
  1337. (sc->data[SC_NOCHAT] && sc->data[SC_NOCHAT]->val1&MANNER_NOSKILL)
  1338. )
  1339. return false;
  1340. }
  1341. if (sc->option) {
  1342. if ((sc->option&OPTION_HIDE) && src->type == BL_PC && (skill_id == 0 || !skill_get_inf2(skill_id, INF2_ALLOWWHENHIDDEN))) {
  1343. // Non players can use all skills while hidden.
  1344. return false;
  1345. }
  1346. if (sc->option&OPTION_CHASEWALK && skill_id != ST_CHASEWALK)
  1347. return false;
  1348. }
  1349. }
  1350. if (target == NULL || target == src) // No further checking needed.
  1351. return true;
  1352. tsc = status_get_sc(target);
  1353. if (tsc && tsc->count) {
  1354. /**
  1355. * Attacks in invincible are capped to 1 damage and handled in battle.cpp.
  1356. * Allow spell break and eske for sealed shrine GDB when in INVINCIBLE state.
  1357. **/
  1358. if( tsc->data[SC_INVINCIBLE] && !tsc->data[SC_INVINCIBLEOFF] && skill_id && !(skill_id&(SA_SPELLBREAKER|SL_SKE)) )
  1359. return false;
  1360. if(!skill_id && tsc->data[SC_TRICKDEAD])
  1361. return false;
  1362. if((skill_id == WZ_STORMGUST || skill_id == WZ_FROSTNOVA || skill_id == NJ_HYOUSYOURAKU || skill_id == NPC_STORMGUST2)
  1363. && tsc->data[SC_FREEZE])
  1364. return false;
  1365. if(skill_id == PR_LEXAETERNA && (tsc->data[SC_FREEZE] || tsc->data[SC_STONE]))
  1366. return false;
  1367. if (tsc->data[SC__MANHOLE] && !skill_get_inf2(skill_id, INF2_TARGETMANHOLE))
  1368. return false;
  1369. }
  1370. // If targetting, cloak+hide protect you, otherwise only hiding does.
  1371. hide_flag = flag?OPTION_HIDE:(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK);
  1372. // Skill that can hit hidden target
  1373. if( skill_get_inf2(skill_id, INF2_TARGETHIDDEN) )
  1374. hide_flag &= ~OPTION_HIDE;
  1375. switch( target->type ) {
  1376. case BL_PC: {
  1377. struct map_session_data *tsd = (TBL_PC*)target;
  1378. bool is_boss = (src && status_get_class_(src) == CLASS_BOSS);
  1379. bool is_detect = status_has_mode(status,MD_DETECTOR);
  1380. if (pc_isinvisible(tsd))
  1381. return false;
  1382. if (tsc) {
  1383. if ((tsc->option&hide_flag) && !is_boss && (tsd->special_state.perfect_hiding || !is_detect))
  1384. return false;
  1385. if ((tsc->data[SC_CLOAKINGEXCEED] || tsc->data[SC_NEWMOON]) && !is_boss && (tsd->special_state.perfect_hiding || is_detect))
  1386. return false; // Works against insect and demon but not against bosses
  1387. if (tsc->data[SC__FEINTBOMB] && (is_boss || is_detect))
  1388. return false; // Works against all
  1389. if ((tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_STEALTHFIELD] || tsc->data[SC_SUHIDE]) && !(is_boss || is_detect) && (!skill_id || (!flag && src)))
  1390. return false; // Insect, demon, and boss can detect
  1391. }
  1392. }
  1393. break;
  1394. case BL_ITEM: // Allow targetting of items to pick'em up (or in the case of mobs, to loot them).
  1395. // !TODO: Would be nice if this could be used to judge whether the player can or not pick up the item it targets. [Skotlex]
  1396. if (status_has_mode(status,MD_LOOTER))
  1397. return true;
  1398. return false;
  1399. case BL_HOM:
  1400. case BL_MER:
  1401. case BL_ELEM:
  1402. 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 )
  1403. return false; // Can't use support skills on Homunculus (only Master/Self)
  1404. if( target->type == BL_MER && (skill_id == PR_ASPERSIO || (skill_id >= SA_FLAMELAUNCHER && skill_id <= SA_SEISMICWEAPON)) && battle_get_master(target) != src )
  1405. return false; // Can't use Weapon endow skills on Mercenary (only Master)
  1406. if( skill_id == AM_POTIONPITCHER && ( target->type == BL_MER || target->type == BL_ELEM) )
  1407. return false; // Can't use Potion Pitcher on Mercenaries
  1408. if (tsc && tsc->data[SC_ELEMENTAL_VEIL] && !(src && status_get_class_(src) == CLASS_BOSS) && !status_has_mode(status, MD_DETECTOR))
  1409. return false;
  1410. default:
  1411. // Check for chase-walk/hiding/cloaking opponents.
  1412. if( tsc ) {
  1413. if( tsc->option&hide_flag && !status_has_mode(status,MD_DETECTOR))
  1414. return false;
  1415. }
  1416. }
  1417. return true;
  1418. }
  1419. /**
  1420. * Checks whether the src can see the target
  1421. * @param src: Object using skill on target [PC|MOB|PET|HOM|MER|ELEM]
  1422. * @param target: Object being targeted by src [PC|MOB|HOM|MER|ELEM]
  1423. * @return src can see (1) or target is invisible (0)
  1424. * @author [Skotlex]
  1425. */
  1426. int status_check_visibility(struct block_list *src, struct block_list *target)
  1427. {
  1428. int view_range;
  1429. struct status_data* status = status_get_status_data(src);
  1430. struct status_change* tsc = status_get_sc(target);
  1431. switch (src->type) {
  1432. case BL_MOB:
  1433. view_range = ((TBL_MOB*)src)->min_chase;
  1434. break;
  1435. case BL_PET:
  1436. view_range = ((TBL_PET*)src)->db->range2;
  1437. break;
  1438. default:
  1439. view_range = AREA_SIZE;
  1440. }
  1441. if (src->m != target->m || !check_distance_bl(src, target, view_range))
  1442. return 0;
  1443. if ( src->type == BL_NPC) // NPCs don't care for the rest
  1444. return 1;
  1445. if (tsc) {
  1446. bool is_boss = (status_get_class_(src) == CLASS_BOSS);
  1447. bool is_detector = status_has_mode(status,MD_DETECTOR);
  1448. switch (target->type) { // Check for chase-walk/hiding/cloaking opponents.
  1449. case BL_PC: {
  1450. struct map_session_data *tsd = (TBL_PC*)target;
  1451. if (((tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_STEALTHFIELD] || tsc->data[SC_SUHIDE]) && !is_boss && (tsd->special_state.perfect_hiding || !is_detector))
  1452. return 0;
  1453. if ((tsc->data[SC_CLOAKINGEXCEED] || tsc->data[SC_NEWMOON]) && !is_boss && ((tsd && tsd->special_state.perfect_hiding) || is_detector))
  1454. return 0;
  1455. if (tsc->data[SC__FEINTBOMB] && !is_boss && !is_detector)
  1456. return 0;
  1457. }
  1458. break;
  1459. case BL_ELEM:
  1460. if (tsc->data[SC_ELEMENTAL_VEIL] && !is_boss && !is_detector)
  1461. return 0;
  1462. break;
  1463. default:
  1464. if (((tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_STEALTHFIELD] || tsc->data[SC_SUHIDE]) && !is_boss && !is_detector)
  1465. return 0;
  1466. }
  1467. }
  1468. return 1;
  1469. }
  1470. /**
  1471. * Base ASPD value taken from the job tables
  1472. * @param sd: Player object
  1473. * @param status: Player status
  1474. * @return base amotion after single/dual weapon and shield adjustments [RENEWAL]
  1475. * base amotion after single/dual weapon and stats adjustments [PRE-RENEWAL]
  1476. */
  1477. int status_base_amotion_pc(struct map_session_data* sd, struct status_data* status)
  1478. {
  1479. std::shared_ptr<s_job_info> job = job_db.find(sd->status.class_);
  1480. if (job == nullptr)
  1481. return 2000;
  1482. int amotion;
  1483. #ifdef RENEWAL_ASPD
  1484. int16 skill_lv, val = 0;
  1485. float temp_aspd = 0;
  1486. amotion = job->aspd_base[sd->weapontype1]; // Single weapon
  1487. if (sd->status.shield)
  1488. amotion += job->aspd_base[MAX_WEAPON_TYPE];
  1489. else if (sd->weapontype2 != W_FIST && sd->equip_index[EQI_HAND_R] != sd->equip_index[EQI_HAND_L])
  1490. amotion += job->aspd_base[sd->weapontype2] / 4; // Dual-wield
  1491. switch(sd->status.weapon) {
  1492. case W_BOW:
  1493. case W_MUSICAL:
  1494. case W_WHIP:
  1495. case W_REVOLVER:
  1496. case W_RIFLE:
  1497. case W_GATLING:
  1498. case W_SHOTGUN:
  1499. case W_GRENADE:
  1500. temp_aspd = status->dex * status->dex / 7.0f + status->agi * status->agi * 0.5f;
  1501. break;
  1502. default:
  1503. temp_aspd = status->dex * status->dex / 5.0f + status->agi * status->agi * 0.5f;
  1504. break;
  1505. }
  1506. temp_aspd = (float)(sqrt(temp_aspd) * 0.25f) + 0xc4;
  1507. if ((skill_lv = pc_checkskill(sd,SA_ADVANCEDBOOK)) > 0 && sd->status.weapon == W_BOOK)
  1508. val += (skill_lv - 1) / 2 + 1;
  1509. if ((skill_lv = pc_checkskill(sd, SG_DEVIL)) > 0 && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd)))
  1510. val += 1 + skill_lv;
  1511. if ((skill_lv = pc_checkskill(sd,GS_SINGLEACTION)) > 0 && (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE))
  1512. val += ((skill_lv + 1) / 2);
  1513. if ((skill_lv = pc_checkskill(sd, RG_PLAGIARISM)) > 0)
  1514. val += skill_lv;
  1515. if (pc_isriding(sd))
  1516. val -= 50 - 10 * pc_checkskill(sd, KN_CAVALIERMASTERY);
  1517. else if (pc_isridingdragon(sd))
  1518. val -= 25 - 5 * pc_checkskill(sd, RK_DRAGONTRAINING);
  1519. amotion = ((int)(temp_aspd + ((float)(status_calc_aspd(&sd->bl, &sd->sc, true) + val) * status->agi / 200)) - min(amotion, 200));
  1520. #else
  1521. // Angra Manyu disregards aspd_base and similar
  1522. if (pc_checkequip2(sd, ITEMID_ANGRA_MANYU, EQI_ACC_L, EQI_MAX))
  1523. return 0;
  1524. // Base weapon delay
  1525. amotion = (sd->status.weapon < MAX_WEAPON_TYPE)
  1526. ? (job->aspd_base[sd->status.weapon]) // Single weapon
  1527. : (job->aspd_base[sd->weapontype1] + job->aspd_base[sd->weapontype2]) * 7 / 10; // Dual-wield
  1528. // Percentual delay reduction from stats
  1529. amotion -= amotion * (4 * status->agi + status->dex) / 1000;
  1530. // Raw delay adjustment from bAspd bonus
  1531. amotion += sd->bonus.aspd_add;
  1532. #endif
  1533. return amotion;
  1534. }
  1535. /**
  1536. * Base attack value calculated for units
  1537. * @param bl: Object to get attack for [BL_CHAR|BL_NPC]
  1538. * @param status: Object status
  1539. * @return base attack
  1540. */
  1541. unsigned short status_base_atk(const struct block_list *bl, const struct status_data *status, int level)
  1542. {
  1543. int flag = 0, str, dex, dstr;
  1544. #ifdef RENEWAL
  1545. if (!(bl->type&battle_config.enable_baseatk_renewal))
  1546. return 0;
  1547. #else
  1548. if (!(bl->type&battle_config.enable_baseatk))
  1549. return 0;
  1550. #endif
  1551. if (bl->type == BL_PC)
  1552. switch(((TBL_PC*)bl)->status.weapon) {
  1553. case W_BOW:
  1554. case W_MUSICAL:
  1555. case W_WHIP:
  1556. case W_REVOLVER:
  1557. case W_RIFLE:
  1558. case W_GATLING:
  1559. case W_SHOTGUN:
  1560. case W_GRENADE:
  1561. flag = 1;
  1562. }
  1563. if (flag) {
  1564. #ifdef RENEWAL
  1565. dstr =
  1566. #endif
  1567. str = status->dex;
  1568. dex = status->str;
  1569. } else {
  1570. #ifdef RENEWAL
  1571. dstr =
  1572. #endif
  1573. str = status->str;
  1574. dex = status->dex;
  1575. }
  1576. /** [Skotlex]
  1577. * Normally only players have base-atk, but homunc have a different batk
  1578. * equation, hinting that perhaps non-players should use this for batk.
  1579. **/
  1580. switch (bl->type) {
  1581. case BL_HOM:
  1582. #ifdef RENEWAL
  1583. str = 2 * level + status_get_homstr(bl);
  1584. #else
  1585. dstr = str / 10;
  1586. str += dstr*dstr;
  1587. #endif
  1588. break;
  1589. case BL_PC:
  1590. #ifdef RENEWAL
  1591. str = (dstr * 10 + dex * 10 / 5 + status->luk * 10 / 3 + level * 10 / 4) / 10 + 5 * status->pow;
  1592. #else
  1593. dstr = str / 10;
  1594. str += dstr*dstr;
  1595. str += dex / 5 + status->luk / 5;
  1596. #endif
  1597. break;
  1598. default:// Others
  1599. #ifdef RENEWAL
  1600. str = dstr + level;
  1601. #else
  1602. dstr = str / 10;
  1603. str += dstr*dstr;
  1604. str += dex / 5 + status->luk / 5;
  1605. #endif
  1606. break;
  1607. }
  1608. return cap_value(str, 0, USHRT_MAX);
  1609. }
  1610. #ifdef RENEWAL
  1611. /**
  1612. * Weapon attack value calculated for Players
  1613. * @param wa: Weapon attack
  1614. * @param status: Player status
  1615. * @return weapon attack
  1616. */
  1617. unsigned int status_weapon_atk(weapon_atk &wa)
  1618. {
  1619. return wa.atk + wa.atk2;
  1620. }
  1621. #endif
  1622. #ifndef RENEWAL
  1623. unsigned short status_base_matk_min(const struct status_data* status) { return status->int_ + (status->int_ / 7) * (status->int_ / 7); }
  1624. unsigned short status_base_matk_max(const struct status_data* status) { return status->int_ + (status->int_ / 5) * (status->int_ / 5); }
  1625. #else
  1626. /*
  1627. * Calculates minimum attack variance 80% from db's ATK1 for non BL_PC
  1628. * status->batk (base attack) will be added in battle_calc_base_damage
  1629. */
  1630. unsigned short status_base_atk_min(struct block_list *bl, const struct status_data* status, int level)
  1631. {
  1632. switch (bl->type) {
  1633. case BL_PET:
  1634. case BL_MOB:
  1635. case BL_MER:
  1636. case BL_ELEM:
  1637. return status->rhw.atk * 80 / 100;
  1638. case BL_HOM:
  1639. return (status_get_homstr(bl) + status_get_homdex(bl)) / 5;
  1640. default:
  1641. return status->rhw.atk;
  1642. }
  1643. }
  1644. /*
  1645. * Calculates maximum attack variance 120% from db's ATK1 for non BL_PC
  1646. * status->batk (base attack) will be added in battle_calc_base_damage
  1647. */
  1648. unsigned short status_base_atk_max(struct block_list *bl, const struct status_data* status, int level)
  1649. {
  1650. switch (bl->type) {
  1651. case BL_PET:
  1652. case BL_MOB:
  1653. case BL_MER:
  1654. case BL_ELEM:
  1655. return status->rhw.atk * 120 / 100;
  1656. case BL_HOM:
  1657. return (status_get_homluk(bl) + status_get_homstr(bl) + status_get_homdex(bl)) / 3;
  1658. default:
  1659. return status->rhw.atk2;
  1660. }
  1661. }
  1662. /*
  1663. * Calculates minimum magic attack
  1664. */
  1665. unsigned short status_base_matk_min(struct block_list *bl, const struct status_data* status, int level)
  1666. {
  1667. switch (bl->type) {
  1668. case BL_PET:
  1669. case BL_MOB:
  1670. case BL_MER:
  1671. case BL_ELEM:
  1672. return status->int_ + level + status->rhw.matk * 70 / 100;
  1673. case BL_HOM:
  1674. return status_get_homint(bl) + level + (status_get_homint(bl) + status_get_homdex(bl)) / 5;
  1675. case BL_PC:
  1676. default:
  1677. return status->int_ + (status->int_ / 2) + (status->dex / 5) + (status->luk / 3) + (level / 4) + 5 * status->spl;
  1678. }
  1679. }
  1680. /*
  1681. * Calculates maximum magic attack
  1682. */
  1683. unsigned short status_base_matk_max(struct block_list *bl, const struct status_data* status, int level)
  1684. {
  1685. switch (bl->type) {
  1686. case BL_PET:
  1687. case BL_MOB:
  1688. case BL_MER:
  1689. case BL_ELEM:
  1690. return status->int_ + level + status->rhw.matk * 130 / 100;
  1691. case BL_HOM:
  1692. return status_get_homint(bl) + level + (status_get_homluk(bl) + status_get_homint(bl) + status_get_homdex(bl)) / 3;
  1693. case BL_PC:
  1694. default:
  1695. return status->int_ + (status->int_ / 2) + (status->dex / 5) + (status->luk / 3) + (level / 4) + 5 * status->spl;
  1696. }
  1697. }
  1698. #endif
  1699. /**
  1700. * Fills in the misc data that can be calculated from the other status info (except for level)
  1701. * @param bl: Object to calculate status on [PC|MOB|PET|HOM|MERC|ELEM]
  1702. * @param status: Player status
  1703. */
  1704. void status_calc_misc(struct block_list *bl, struct status_data *status, int level)
  1705. {
  1706. int stat;
  1707. // Non players get the value set, players need to stack with previous bonuses.
  1708. if( bl->type != BL_PC ){
  1709. status->batk =
  1710. status->hit = status->flee =
  1711. status->def2 = status->mdef2 =
  1712. status->cri = status->flee2 =
  1713. status->patk = status->smatk =
  1714. status->hplus = status->crate = 0;
  1715. if (bl->type != BL_MOB) // BL_MOB has values set when loading mob_db
  1716. status->res = status->mres = 0;
  1717. }
  1718. #ifdef RENEWAL // Renewal formulas
  1719. if (bl->type == BL_HOM) {
  1720. // Def2
  1721. stat = status_get_homvit(bl) + status_get_homagi(bl) / 2;
  1722. status->def2 = cap_value(stat, 0, SHRT_MAX);
  1723. // Mdef2
  1724. stat = (status_get_homvit(bl) + status_get_homint(bl)) / 2;
  1725. status->mdef2 = cap_value(stat, 0, SHRT_MAX);
  1726. // Def
  1727. stat = status->def;
  1728. stat += status_get_homvit(bl) + level / 2;
  1729. status->def = cap_value(stat, 0, SHRT_MAX);
  1730. // Mdef
  1731. stat = (int)(((float)status_get_homvit(bl) + level) / 4 + (float)status_get_homint(bl) / 2);
  1732. status->mdef = cap_value(stat, 0, SHRT_MAX);
  1733. // Hit
  1734. stat = level + status->dex + 150;
  1735. status->hit = cap_value(stat, 1, SHRT_MAX);
  1736. // Flee
  1737. stat = level + status_get_homagi(bl);
  1738. status->flee = cap_value(stat, 1, SHRT_MAX);
  1739. } else {
  1740. // Hit
  1741. stat = status->hit;
  1742. 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
  1743. stat += 2 * status->con;
  1744. status->hit = cap_value(stat, 1, SHRT_MAX);
  1745. // Flee
  1746. stat = status->flee;
  1747. 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
  1748. stat += 2 * status->con;
  1749. status->flee = cap_value(stat, 1, SHRT_MAX);
  1750. // Def2
  1751. if (bl->type == BL_MER)
  1752. stat = (int)(status->vit + ((float)level / 10) + ((float)status->vit / 5));
  1753. else {
  1754. stat = status->def2;
  1755. stat += (int)(((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)
  1756. }
  1757. status->def2 = cap_value(stat, 0, SHRT_MAX);
  1758. // Mdef2
  1759. if (bl->type == BL_MER)
  1760. stat = (int)(((float)level / 10) + ((float)status->int_ / 5));
  1761. else {
  1762. stat = status->mdef2;
  1763. stat += (int)(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 int = +1 mdef) + (every 5 dex = +1 mdef) + (every 5 vit = +1 mdef)
  1764. }
  1765. status->mdef2 = cap_value(stat, 0, SHRT_MAX);
  1766. // PAtk
  1767. stat = status->patk;
  1768. stat += status->pow / 3 + status->con / 5;
  1769. status->patk = cap_value(stat, 0, SHRT_MAX);
  1770. // SMatk
  1771. stat = status->smatk;
  1772. stat += status->spl / 3 + status->con / 5;
  1773. status->smatk = cap_value(stat, 0, SHRT_MAX);
  1774. // Res
  1775. stat = status->res;
  1776. stat += status->sta + status->sta / 3 * 5;
  1777. status->res = cap_value(stat, 0, SHRT_MAX);
  1778. // Mres
  1779. stat = status->mres;
  1780. stat += status->wis + status->wis / 3 * 5;
  1781. status->mres = cap_value(stat, 0, SHRT_MAX);
  1782. // HPlus
  1783. stat = status->hplus;
  1784. stat += status->crt;
  1785. status->hplus = cap_value(stat, 0, SHRT_MAX);
  1786. // CRate
  1787. stat = status->crate;
  1788. stat += status->crt / 3;
  1789. status->crate = cap_value(stat, 0, SHRT_MAX);
  1790. }
  1791. // ATK
  1792. if (bl->type != BL_PC) {
  1793. status->rhw.atk2 = status_base_atk_max(bl, status, level);
  1794. status->rhw.atk = status_base_atk_min(bl, status, level);
  1795. }
  1796. // MAtk
  1797. status->matk_min = status_base_matk_min(bl, status, level);
  1798. status->matk_max = status_base_matk_max(bl, status, level);
  1799. #else
  1800. // Matk
  1801. status->matk_min = status_base_matk_min(status);
  1802. status->matk_max = status_base_matk_max(status);
  1803. // Hit
  1804. stat = status->hit;
  1805. stat += level + status->dex;
  1806. status->hit = cap_value(stat, 1, SHRT_MAX);
  1807. // Flee
  1808. stat = status->flee;
  1809. stat += level + status->agi;
  1810. status->flee = cap_value(stat, 1, SHRT_MAX);
  1811. // Def2
  1812. stat = status->def2;
  1813. stat += status->vit;
  1814. status->def2 = cap_value(stat, 0, SHRT_MAX);
  1815. // Mdef2
  1816. stat = status->mdef2;
  1817. stat += status->int_ + (status->vit>>1);
  1818. status->mdef2 = cap_value(stat, 0, SHRT_MAX);
  1819. #endif
  1820. //Critical
  1821. if( bl->type&battle_config.enable_critical ) {
  1822. stat = status->cri;
  1823. stat += 10 + (status->luk*10/3); // (every 1 luk = +0.3 critical)
  1824. status->cri = cap_value(stat, 1, SHRT_MAX);
  1825. } else
  1826. status->cri = 0;
  1827. if (bl->type&battle_config.enable_perfect_flee) {
  1828. stat = status->flee2;
  1829. stat += status->luk + 10; // (every 10 luk = +1 perfect flee)
  1830. status->flee2 = cap_value(stat, 0, SHRT_MAX);
  1831. } else
  1832. status->flee2 = 0;
  1833. if (status->batk) {
  1834. int temp = status->batk + status_base_atk(bl, status, level);
  1835. status->batk = cap_value(temp, 0, USHRT_MAX);
  1836. } else
  1837. status->batk = status_base_atk(bl, status, level);
  1838. if (status->cri) {
  1839. switch (bl->type) {
  1840. case BL_MOB:
  1841. if(battle_config.mob_critical_rate != 100)
  1842. status->cri = cap_value(status->cri*battle_config.mob_critical_rate/100,1,SHRT_MAX);
  1843. if(!status->cri && battle_config.mob_critical_rate)
  1844. status->cri = 10;
  1845. break;
  1846. case BL_PC:
  1847. // Players don't have a critical adjustment setting as of yet.
  1848. break;
  1849. default:
  1850. if(battle_config.critical_rate != 100)
  1851. status->cri = cap_value(status->cri*battle_config.critical_rate/100,1,SHRT_MAX);
  1852. if (!status->cri && battle_config.critical_rate)
  1853. status->cri = 10;
  1854. }
  1855. }
  1856. if(bl->type&BL_REGEN)
  1857. status_calc_regen(bl, status, status_get_regen_data(bl));
  1858. }
  1859. /**
  1860. * Calculates the initial status for the given mob
  1861. * @param md: Mob object
  1862. * @param opt: Whether or not it is the first calculation
  1863. This will only be false when a mob levels up (Regular and WoE Guardians)
  1864. * @return 1 for calculated special statuses or 0 for none
  1865. * @author [Skotlex]
  1866. */
  1867. int status_calc_mob_(struct mob_data* md, uint8 opt)
  1868. {
  1869. struct status_data *status;
  1870. struct block_list *mbl = NULL;
  1871. int flag=0;
  1872. if (opt&SCO_FIRST) { // Set basic level on respawn.
  1873. if (md->level > 0 && md->level <= MAX_LEVEL && md->level != md->db->lv)
  1874. ;
  1875. else
  1876. md->level = md->db->lv;
  1877. }
  1878. // Check if we need custom base-status
  1879. if (battle_config.mobs_level_up && md->level > md->db->lv)
  1880. flag|=1;
  1881. if (md->special_state.size)
  1882. flag|=2;
  1883. if (md->guardian_data && md->guardian_data->guardup_lv)
  1884. flag|=4;
  1885. if (md->mob_id == MOBID_EMPERIUM)
  1886. flag|=4;
  1887. if (battle_config.slaves_inherit_speed && md->master_id)
  1888. flag|=8;
  1889. if (md->master_id && md->special_state.ai>AI_ATTACK)
  1890. flag|=16;
  1891. if (md->master_id && battle_config.slaves_inherit_mode)
  1892. flag |= 32;
  1893. if (!flag) { // No special status required.
  1894. if (md->base_status) {
  1895. aFree(md->base_status);
  1896. md->base_status = NULL;
  1897. }
  1898. if (opt&SCO_FIRST)
  1899. memcpy(&md->status, &md->db->status, sizeof(struct status_data));
  1900. return 0;
  1901. }
  1902. if (!md->base_status)
  1903. md->base_status = (struct status_data*)aCalloc(1, sizeof(struct status_data));
  1904. status = md->base_status;
  1905. memcpy(status, &md->db->status, sizeof(struct status_data));
  1906. if (flag&(8|16))
  1907. mbl = map_id2bl(md->master_id);
  1908. if (flag&8 && mbl) {
  1909. struct status_data *mstatus = status_get_base_status(mbl);
  1910. if (mstatus &&
  1911. battle_config.slaves_inherit_speed&(status_has_mode(mstatus,MD_CANMOVE)?1:2))
  1912. status->speed = mstatus->speed;
  1913. if( status->speed < 2 ) // Minimum for the unit to function properly
  1914. status->speed = 2;
  1915. }
  1916. if (flag&32)
  1917. status_calc_slave_mode(md, map_id2md(md->master_id));
  1918. if (flag&1) { // Increase from mobs leveling up [Valaris]
  1919. int diff = md->level - md->db->lv;
  1920. status->str += diff;
  1921. status->agi += diff;
  1922. status->vit += diff;
  1923. status->int_ += diff;
  1924. status->dex += diff;
  1925. status->luk += diff;
  1926. status->max_hp += diff * status->vit;
  1927. status->max_sp += diff * status->int_;
  1928. status->hp = status->max_hp;
  1929. status->sp = status->max_sp;
  1930. status->speed -= cap_value(diff, 0, status->speed - 10);
  1931. }
  1932. if (flag&2 && battle_config.mob_size_influence) { // Change for sized monsters [Valaris]
  1933. if (md->special_state.size == SZ_MEDIUM) {
  1934. status->max_hp >>= 1;
  1935. status->max_sp >>= 1;
  1936. if (!status->max_hp) status->max_hp = 1;
  1937. if (!status->max_sp) status->max_sp = 1;
  1938. status->hp = status->max_hp;
  1939. status->sp = status->max_sp;
  1940. status->str >>= 1;
  1941. status->agi >>= 1;
  1942. status->vit >>= 1;
  1943. status->int_ >>= 1;
  1944. status->dex >>= 1;
  1945. status->luk >>= 1;
  1946. if (!status->str) status->str = 1;
  1947. if (!status->agi) status->agi = 1;
  1948. if (!status->vit) status->vit = 1;
  1949. if (!status->int_) status->int_ = 1;
  1950. if (!status->dex) status->dex = 1;
  1951. if (!status->luk) status->luk = 1;
  1952. } else if (md->special_state.size == SZ_BIG) {
  1953. status->max_hp <<= 1;
  1954. status->max_sp <<= 1;
  1955. status->hp = status->max_hp;
  1956. status->sp = status->max_sp;
  1957. status->str <<= 1;
  1958. status->agi <<= 1;
  1959. status->vit <<= 1;
  1960. status->int_ <<= 1;
  1961. status->dex <<= 1;
  1962. status->luk <<= 1;
  1963. }
  1964. }
  1965. status_calc_misc(&md->bl, status, md->level);
  1966. if(flag&4) { // Strengthen Guardians - custom value +10% / lv
  1967. struct map_data *mapdata = map_getmapdata(md->bl.m);
  1968. std::shared_ptr<guild_castle> gc = castle_db.mapname2gc(mapdata->name);
  1969. if (gc == nullptr)
  1970. ShowError("status_calc_mob: No castle set at map %s\n", mapdata->name);
  1971. else if(gc->castle_id < 24 || md->mob_id == MOBID_EMPERIUM) {
  1972. #ifdef RENEWAL
  1973. status->max_hp += 50 * (gc->defense / 5);
  1974. #else
  1975. status->max_hp += 1000 * gc->defense;
  1976. #endif
  1977. status->hp = status->max_hp;
  1978. status->def += (gc->defense+2)/3;
  1979. status->mdef += (gc->defense+2)/3;
  1980. }
  1981. if(md->mob_id != MOBID_EMPERIUM) {
  1982. status->max_hp += 1000 * gc->defense;
  1983. status->hp = status->max_hp;
  1984. status->batk += 2 * md->guardian_data->guardup_lv + 8;
  1985. status->rhw.atk += 2 * md->guardian_data->guardup_lv + 8;
  1986. status->rhw.atk2 += 2 * md->guardian_data->guardup_lv + 8;
  1987. status->aspd_rate -= 2 * md->guardian_data->guardup_lv + 3;
  1988. }
  1989. }
  1990. if (flag&16 && mbl) { // Max HP setting from Summon Flora/marine Sphere
  1991. struct unit_data *ud = unit_bl2ud(mbl);
  1992. // Remove special AI when this is used by regular mobs.
  1993. if (mbl->type == BL_MOB && !((TBL_MOB*)mbl)->special_state.ai)
  1994. md->special_state.ai = AI_NONE;
  1995. if (ud) {
  1996. // Different levels of HP according to skill level
  1997. if(!ud->skill_id) // !FIXME: We lost the unit data for magic decoy in somewhere before this
  1998. ud->skill_id = ((TBL_PC*)mbl)->menuskill_id;
  1999. switch(ud->skill_id) {
  2000. case AM_SPHEREMINE:
  2001. status->max_hp = 2000 + 400*ud->skill_lv;
  2002. break;
  2003. case KO_ZANZOU:
  2004. status->max_hp = 3000 + 3000 * ud->skill_lv;
  2005. break;
  2006. case AM_CANNIBALIZE:
  2007. status->max_hp = 1500 + 200*ud->skill_lv + 10*status_get_lv(mbl);
  2008. status->mode = static_cast<e_mode>(status->mode|MD_CANATTACK|MD_AGGRESSIVE);
  2009. break;
  2010. case MH_SUMMON_LEGION:
  2011. {
  2012. int homblvl = status_get_lv(mbl);
  2013. status->max_hp = 10 * (100 * (ud->skill_lv + 2) + homblvl);
  2014. status->batk = 100 * (ud->skill_lv+5) / 2;
  2015. status->def = 10 * (100 * (ud->skill_lv+2) + homblvl);
  2016. // status->aspd_rate = 10 * (2 * (20 - ud->skill_lv) - homblvl/10);
  2017. // status->aspd_rate = max(100,status->aspd_rate);
  2018. break;
  2019. }
  2020. case NC_SILVERSNIPER:
  2021. {
  2022. struct status_data *mstatus = status_get_status_data(mbl);
  2023. if(!mstatus)
  2024. break;
  2025. status->max_hp = (1000 * ud->skill_lv) + (mstatus->hp / 3) + (status_get_lv(mbl) * 12);
  2026. status->batk = 200 * ud->skill_lv;
  2027. break;
  2028. }
  2029. case NC_MAGICDECOY:
  2030. {
  2031. struct status_data *mstatus = status_get_status_data(mbl);
  2032. if(!mstatus)
  2033. break;
  2034. status->max_hp = (1000 * ((TBL_PC*)mbl)->menuskill_val) + (mstatus->sp * 4) + (status_get_lv(mbl) * 12);
  2035. status->matk_min = status->matk_max = 250 + 50*((TBL_PC*)mbl)->menuskill_val;
  2036. break;
  2037. }
  2038. case MT_SUMMON_ABR_BATTLE_WARIOR:
  2039. case MT_SUMMON_ABR_DUAL_CANNON:
  2040. case MT_SUMMON_ABR_MOTHER_NET:
  2041. case MT_SUMMON_ABR_INFINITY: {
  2042. map_session_data *msd = BL_CAST(BL_PC, mbl);
  2043. status_data *mstatus = status_get_status_data(mbl);
  2044. if (msd == nullptr || mstatus == nullptr)
  2045. break;
  2046. uint8 abr_mastery = pc_checkskill(msd, MT_ABR_M);
  2047. // Custom formulas for ABR's.
  2048. // Its unknown how the summoner's stats affects the ABR's stats.
  2049. // I decided to do something similar to elementals for now until I know.
  2050. // Also added hit increase from ABR-Mastery for balance reasons. [Rytech]
  2051. status->max_hp = (5000 + 2000 * abr_mastery) * mstatus->vit / 100;
  2052. status->rhw.atk = (2 * mstatus->batk + 500 + 200 * abr_mastery) * 70 / 100;
  2053. status->rhw.atk2 = 2 * mstatus->batk + 500 + 200 * abr_mastery;
  2054. status->def = mstatus->def + 20 * abr_mastery;
  2055. status->mdef = mstatus->mdef + 4 * abr_mastery;
  2056. status->hit = mstatus->hit + 5 * abr_mastery / 2;
  2057. status->flee = mstatus->flee + 10 * abr_mastery;
  2058. status->speed = mstatus->speed;
  2059. // The Infinity ABR appears to have a much higher attack then other
  2060. // ABR's and im guessing has a much higher MaxHP due to it being a AP
  2061. // costing summon. [Rytech]
  2062. if (ud->skill_id == MT_SUMMON_ABR_INFINITY) {
  2063. status->max_hp += 20000;
  2064. status->rhw.atk += 1400; // 70% of 2000
  2065. status->rhw.atk2 += 2000;
  2066. }
  2067. }
  2068. break;
  2069. case BO_WOODENWARRIOR:
  2070. case BO_WOODEN_FAIRY:
  2071. case BO_CREEPER:
  2072. case BO_HELLTREE: {
  2073. map_session_data *msd = BL_CAST(BL_PC, mbl);
  2074. status_data *mstatus = status_get_status_data(mbl);
  2075. if (msd == nullptr || mstatus == nullptr)
  2076. break;
  2077. uint8 bionic_mastery = pc_checkskill(msd, BO_BIONICS_M);
  2078. // Custom formulas for bionic's.
  2079. // Its unknown how the summoner's stats affects the bionic's stats.
  2080. // I decided to do something similar to elementals for now until I know.
  2081. // Also added hit increase from Bionic-Mastery for balance reasons. [Rytech]
  2082. status->max_hp = (5000 + 2000 * bionic_mastery) * mstatus->vit / 100;
  2083. //status->max_sp = (50 + 20 * bionic_mastery) * mstatus->int_ / 100;// Wait what??? Bionic Mastery increases MaxSP? They have SP???
  2084. status->rhw.atk = (2 * mstatus->batk + 200 * bionic_mastery) * 70 / 100;
  2085. status->rhw.atk2 = 2 * mstatus->batk + 200 * bionic_mastery;
  2086. status->def = mstatus->def + 20 * bionic_mastery;
  2087. status->mdef = mstatus->mdef + 4 * bionic_mastery;
  2088. status->hit = mstatus->hit + 5 * bionic_mastery / 2;
  2089. status->flee = mstatus->flee + 10 * bionic_mastery;
  2090. status->speed = mstatus->speed;
  2091. // The Hell Tree bionic appears to have a much higher attack then other
  2092. // bionic's and im guessing has a much higher MaxHP due to it being a AP
  2093. // costing summon. [Rytech]
  2094. if (ud->skill_id == BO_HELLTREE) {
  2095. status->max_hp += 20000;
  2096. status->rhw.atk += 1400; // 70% of 2000
  2097. status->rhw.atk2 += 2000;
  2098. }
  2099. }
  2100. break;
  2101. }
  2102. status->hp = status->max_hp;
  2103. }
  2104. }
  2105. if (opt&SCO_FIRST) // Initial battle status
  2106. memcpy(&md->status, status, sizeof(struct status_data));
  2107. return 1;
  2108. }
  2109. /**
  2110. * Calculates the stats of the given pet
  2111. * @param pd: Pet object
  2112. * @param opt: Whether or not it is the first calculation
  2113. This will only be false when a pet levels up
  2114. * @return 1
  2115. * @author [Skotlex]
  2116. */
  2117. void status_calc_pet_(struct pet_data *pd, uint8 opt)
  2118. {
  2119. nullpo_retv(pd);
  2120. if (opt&SCO_FIRST) {
  2121. memcpy(&pd->status, &pd->db->status, sizeof(struct status_data));
  2122. pd->status.mode = MD_CANMOVE; // Pets discard all modes, except walking
  2123. pd->status.class_ = CLASS_NORMAL;
  2124. pd->status.speed = pd->get_pet_walk_speed();
  2125. if(battle_config.pet_attack_support || battle_config.pet_damage_support) {
  2126. // Attack support requires the pet to be able to attack
  2127. pd->status.mode = static_cast<e_mode>(pd->status.mode|MD_CANATTACK);
  2128. }
  2129. }
  2130. if (battle_config.pet_lv_rate && pd->master) {
  2131. struct map_session_data *sd = pd->master;
  2132. int lv;
  2133. lv =sd->status.base_level*battle_config.pet_lv_rate/100;
  2134. if (lv < 0)
  2135. lv = 1;
  2136. if (lv != pd->pet.level || opt&SCO_FIRST) {
  2137. struct status_data *bstat = &pd->db->status, *status = &pd->status;
  2138. pd->pet.level = lv;
  2139. if (!(opt&SCO_FIRST)) // Lv Up animation
  2140. clif_misceffect(&pd->bl, 0);
  2141. status->rhw.atk = (bstat->rhw.atk*lv)/pd->db->lv;
  2142. status->rhw.atk2 = (bstat->rhw.atk2*lv)/pd->db->lv;
  2143. status->str = (bstat->str*lv)/pd->db->lv;
  2144. status->agi = (bstat->agi*lv)/pd->db->lv;
  2145. status->vit = (bstat->vit*lv)/pd->db->lv;
  2146. status->int_ = (bstat->int_*lv)/pd->db->lv;
  2147. status->dex = (bstat->dex*lv)/pd->db->lv;
  2148. status->luk = (bstat->luk*lv)/pd->db->lv;
  2149. status->rhw.atk = cap_value(status->rhw.atk, 1, battle_config.pet_max_atk1);
  2150. status->rhw.atk2 = cap_value(status->rhw.atk2, 2, battle_config.pet_max_atk2);
  2151. status->str = cap_value(status->str,1,battle_config.pet_max_stats);
  2152. status->agi = cap_value(status->agi,1,battle_config.pet_max_stats);
  2153. status->vit = cap_value(status->vit,1,battle_config.pet_max_stats);
  2154. status->int_= cap_value(status->int_,1,battle_config.pet_max_stats);
  2155. status->dex = cap_value(status->dex,1,battle_config.pet_max_stats);
  2156. status->luk = cap_value(status->luk,1,battle_config.pet_max_stats);
  2157. status_calc_misc(&pd->bl, &pd->status, lv);
  2158. if (!(opt&SCO_FIRST)) // Not done the first time because the pet is not visible yet
  2159. clif_send_petstatus(sd);
  2160. }
  2161. } else if (opt&SCO_FIRST) {
  2162. status_calc_misc(&pd->bl, &pd->status, pd->db->lv);
  2163. if (!battle_config.pet_lv_rate && pd->pet.level != pd->db->lv)
  2164. pd->pet.level = pd->db->lv;
  2165. }
  2166. // Support rate modifier (1000 = 100%)
  2167. pd->rate_fix = min(1000 * (pd->pet.intimate - battle_config.pet_support_min_friendly) / (1000 - battle_config.pet_support_min_friendly) + 500, USHRT_MAX);
  2168. pd->rate_fix = min(apply_rate(pd->rate_fix, battle_config.pet_support_rate), USHRT_MAX);
  2169. }
  2170. /**
  2171. * Get HP bonus modifiers
  2172. * @param bl: block_list that will be checked
  2173. * @param type: type of e_status_bonus (STATUS_BONUS_FIX or STATUS_BONUS_RATE)
  2174. * @return bonus: total bonus for HP
  2175. * @author [Cydh]
  2176. */
  2177. static int status_get_hpbonus(struct block_list *bl, enum e_status_bonus type) {
  2178. int bonus = 0;
  2179. if (type == STATUS_BONUS_FIX) {
  2180. struct status_change *sc = status_get_sc(bl);
  2181. //Only for BL_PC
  2182. if (bl->type == BL_PC) {
  2183. struct map_session_data *sd = map_id2sd(bl->id);
  2184. uint16 skill_lv;
  2185. bonus += sd->bonus.hp;
  2186. if ((skill_lv = pc_checkskill(sd,CR_TRUST)) > 0)
  2187. bonus += skill_lv * 200;
  2188. if (pc_checkskill(sd,SU_SPRITEMABLE) > 0)
  2189. bonus += 1000;
  2190. if (pc_checkskill(sd, SU_POWEROFSEA) > 0) {
  2191. bonus += 1000;
  2192. if (pc_checkskill_summoner(sd, SUMMONER_POWER_SEA) >= 20)
  2193. bonus += 3000;
  2194. }
  2195. if ((skill_lv = pc_checkskill(sd, NV_BREAKTHROUGH)) > 0)
  2196. bonus += 350 * skill_lv + (skill_lv > 4 ? 250 : 0);
  2197. if ((skill_lv = pc_checkskill(sd, NV_TRANSCENDENCE)) > 0)
  2198. bonus += 350 * skill_lv + (skill_lv > 4 ? 250 : 0);
  2199. #ifndef HP_SP_TABLES
  2200. if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.base_level >= 99)
  2201. bonus += 2000; // Supernovice lvl99 hp bonus.
  2202. if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.base_level >= 150)
  2203. bonus += 2000; // Supernovice lvl150 hp bonus.
  2204. #endif
  2205. }
  2206. //Bonus by SC
  2207. if (sc) {
  2208. if(sc->data[SC_INCMHP])
  2209. bonus += sc->data[SC_INCMHP]->val1;
  2210. if(sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2)
  2211. bonus += 500;
  2212. if (sc->data[SC_PROMOTE_HEALTH_RESERCH])
  2213. bonus += sc->data[SC_PROMOTE_HEALTH_RESERCH]->val3;
  2214. if(sc->data[SC_SOLID_SKIN_OPTION])
  2215. bonus += 2000;
  2216. if(sc->data[SC_MARIONETTE])
  2217. bonus -= 1000;
  2218. if(sc->data[SC_SWORDCLAN])
  2219. bonus += 30;
  2220. if(sc->data[SC_ARCWANDCLAN])
  2221. bonus += 30;
  2222. if(sc->data[SC_GOLDENMACECLAN])
  2223. bonus += 30;
  2224. if(sc->data[SC_CROSSBOWCLAN])
  2225. bonus += 30;
  2226. if(sc->data[SC_GLASTHEIM_HPSP])
  2227. bonus += sc->data[SC_GLASTHEIM_HPSP]->val1;
  2228. #ifdef RENEWAL
  2229. if (sc->data[SC_ANGELUS])
  2230. bonus += sc->data[SC_ANGELUS]->val1 * 50;
  2231. #endif
  2232. }
  2233. } else if (type == STATUS_BONUS_RATE) {
  2234. struct status_change *sc = status_get_sc(bl);
  2235. //Bonus by SC
  2236. if (sc) {
  2237. //Increasing
  2238. if(sc->data[SC_INCMHPRATE])
  2239. bonus += sc->data[SC_INCMHPRATE]->val1;
  2240. if(sc->data[SC_APPLEIDUN])
  2241. bonus += sc->data[SC_APPLEIDUN]->val2;
  2242. if(sc->data[SC_DELUGE])
  2243. bonus += sc->data[SC_DELUGE]->val2;
  2244. if(sc->data[SC_BERSERK])
  2245. bonus += 200; //+200%
  2246. if(sc->data[SC_MERC_HPUP])
  2247. bonus += sc->data[SC_MERC_HPUP]->val2;
  2248. if(sc->data[SC_EPICLESIS])
  2249. bonus += sc->data[SC_EPICLESIS]->val2;
  2250. if(sc->data[SC_FRIGG_SONG])
  2251. bonus += sc->data[SC_FRIGG_SONG]->val2;
  2252. if(sc->data[SC_LERADSDEW])
  2253. bonus += sc->data[SC_LERADSDEW]->val3;
  2254. if(sc->data[SC_FORCEOFVANGUARD])
  2255. bonus += (3 * sc->data[SC_FORCEOFVANGUARD]->val1);
  2256. if(sc->data[SC_INSPIRATION])
  2257. bonus += (4 * sc->data[SC_INSPIRATION]->val1);
  2258. if(sc->data[SC_RAISINGDRAGON])
  2259. bonus += sc->data[SC_RAISINGDRAGON]->val1;
  2260. if(sc->data[SC_GT_REVITALIZE])
  2261. bonus += sc->data[SC_GT_REVITALIZE]->val2;
  2262. if(sc->data[SC_ANGRIFFS_MODUS])
  2263. bonus += (5 * sc->data[SC_ANGRIFFS_MODUS]->val1);
  2264. if(sc->data[SC_PETROLOGY_OPTION])
  2265. bonus += sc->data[SC_PETROLOGY_OPTION]->val2;
  2266. if(sc->data[SC_POWER_OF_GAIA])
  2267. bonus += sc->data[SC_POWER_OF_GAIA]->val3;
  2268. if(sc->data[SC_CURSED_SOIL_OPTION])
  2269. bonus += sc->data[SC_CURSED_SOIL_OPTION]->val2;
  2270. if(sc->data[SC_UPHEAVAL_OPTION])
  2271. bonus += sc->data[SC_UPHEAVAL_OPTION]->val2;
  2272. if(sc->data[SC_LAUDAAGNUS])
  2273. bonus += 2 + (sc->data[SC_LAUDAAGNUS]->val1 * 2);
  2274. #ifdef RENEWAL
  2275. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_HPRATE)
  2276. bonus += 30;
  2277. #endif
  2278. if(sc->data[SC_LUNARSTANCE])
  2279. bonus += sc->data[SC_LUNARSTANCE]->val2;
  2280. if (sc->data[SC_LUXANIMA])
  2281. bonus += sc->data[SC_LUXANIMA]->val3;
  2282. if (sc->data[SC_MTF_MHP])
  2283. bonus += sc->data[SC_MTF_MHP]->val1;
  2284. if (sc->data[SC_FIRM_FAITH])
  2285. bonus += sc->data[SC_FIRM_FAITH]->val2;
  2286. //Decreasing
  2287. if (sc->data[SC_VENOMBLEED] && sc->data[SC_VENOMBLEED]->val3 == 1)
  2288. bonus -= 15;
  2289. if(sc->data[SC_BEYONDOFWARCRY])
  2290. bonus -= sc->data[SC_BEYONDOFWARCRY]->val3;
  2291. if(sc->data[SC__WEAKNESS])
  2292. bonus -= sc->data[SC__WEAKNESS]->val2;
  2293. if(sc->data[SC_EQC])
  2294. bonus -= sc->data[SC_EQC]->val3;
  2295. if(sc->data[SC_PACKING_ENVELOPE3])
  2296. bonus += sc->data[SC_PACKING_ENVELOPE3]->val1;
  2297. }
  2298. // Max rate reduce is -100%
  2299. bonus = cap_value(bonus,-100,INT_MAX);
  2300. }
  2301. return min(bonus,INT_MAX);
  2302. }
  2303. /**
  2304. * HP bonus rate from equipment
  2305. */
  2306. static int status_get_hpbonus_equip(TBL_PC *sd) {
  2307. int bonus = 0;
  2308. bonus += sd->hprate;
  2309. return bonus -= 100; //Default hprate is 100, so it should be add 0%
  2310. }
  2311. /**
  2312. * HP bonus rate from usable items
  2313. */
  2314. static int status_get_hpbonus_item(block_list *bl) {
  2315. int bonus = 0;
  2316. struct status_change *sc = status_get_sc(bl);
  2317. //Bonus by SC
  2318. if (sc) {
  2319. if (sc->data[SC_INCREASE_MAXHP])
  2320. bonus += sc->data[SC_INCREASE_MAXHP]->val1;
  2321. if (sc->data[SC_MUSTLE_M])
  2322. bonus += sc->data[SC_MUSTLE_M]->val1;
  2323. if (sc->data[SC_MYSTERIOUS_POWDER])
  2324. bonus -= sc->data[SC_MYSTERIOUS_POWDER]->val1;
  2325. }
  2326. // Max rate reduce is -100%
  2327. return cap_value(bonus, -100, INT_MAX);
  2328. }
  2329. /**
  2330. * Get SP bonus modifiers
  2331. * @param bl: block_list that will be checked
  2332. * @param type: type of e_status_bonus (STATUS_BONUS_FIX or STATUS_BONUS_RATE)
  2333. * @return bonus: total bonus for SP
  2334. * @author [Cydh]
  2335. */
  2336. static int status_get_spbonus(struct block_list *bl, enum e_status_bonus type) {
  2337. int bonus = 0;
  2338. if (type == STATUS_BONUS_FIX) {
  2339. struct status_change *sc = status_get_sc(bl);
  2340. //Only for BL_PC
  2341. if (bl->type == BL_PC) {
  2342. struct map_session_data *sd = map_id2sd(bl->id);
  2343. uint16 skill_lv;
  2344. bonus += sd->bonus.sp;
  2345. if ((skill_lv = pc_checkskill(sd,SL_KAINA)) > 0)
  2346. bonus += 30 * skill_lv;
  2347. if ((skill_lv = pc_checkskill(sd,RA_RESEARCHTRAP)) > 0)
  2348. bonus += 200 + 20 * skill_lv;
  2349. if ((skill_lv = pc_checkskill(sd,WM_LESSON)) > 0)
  2350. bonus += 30 * skill_lv;
  2351. if (pc_checkskill(sd,SU_SPRITEMABLE) > 0)
  2352. bonus += 100;
  2353. if (pc_checkskill(sd, SU_POWEROFSEA) > 0) {
  2354. bonus += 100;
  2355. if (pc_checkskill_summoner(sd, SUMMONER_POWER_SEA) >= 20)
  2356. bonus += 300;
  2357. }
  2358. if ((skill_lv = pc_checkskill(sd, NV_BREAKTHROUGH)) > 0)
  2359. bonus += 30 * skill_lv + (skill_lv > 4 ? 50 : 0);
  2360. if ((skill_lv = pc_checkskill(sd, NV_TRANSCENDENCE)) > 0)
  2361. bonus += 30 * skill_lv + (skill_lv > 4 ? 50 : 0);
  2362. }
  2363. //Bonus by SC
  2364. if (sc) {
  2365. if(sc->data[SC_INCMSP])
  2366. bonus += sc->data[SC_INCMSP]->val1;
  2367. if(sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 3)
  2368. bonus += 50;
  2369. if(sc->data[SC_SWORDCLAN])
  2370. bonus += 10;
  2371. if(sc->data[SC_ARCWANDCLAN])
  2372. bonus += 10;
  2373. if(sc->data[SC_GOLDENMACECLAN])
  2374. bonus += 10;
  2375. if(sc->data[SC_CROSSBOWCLAN])
  2376. bonus += 10;
  2377. if(sc->data[SC_GLASTHEIM_HPSP])
  2378. bonus += sc->data[SC_GLASTHEIM_HPSP]->val2;
  2379. }
  2380. } else if (type == STATUS_BONUS_RATE) {
  2381. struct status_change *sc = status_get_sc(bl);
  2382. //Only for BL_PC
  2383. if (bl->type == BL_PC) {
  2384. struct map_session_data *sd = map_id2sd(bl->id);
  2385. uint8 i;
  2386. if((i = pc_checkskill(sd,HP_MEDITATIO)) > 0)
  2387. bonus += i;
  2388. if((i = pc_checkskill(sd,HW_SOULDRAIN)) > 0)
  2389. bonus += 2 * i;
  2390. #ifdef RENEWAL
  2391. if ((i = pc_checkskill(sd, (sd->status.sex ? BA_MUSICALLESSON : DC_DANCINGLESSON))) > 0)
  2392. bonus += i;
  2393. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_SPRATE)
  2394. bonus += 30;
  2395. #endif
  2396. }
  2397. //Bonus by SC
  2398. if (sc) {
  2399. //Increasing
  2400. if(sc->data[SC_INCMSPRATE])
  2401. bonus += sc->data[SC_INCMSPRATE]->val1;
  2402. if(sc->data[SC_RAISINGDRAGON])
  2403. bonus += sc->data[SC_RAISINGDRAGON]->val1;
  2404. if(sc->data[SC_SERVICE4U])
  2405. bonus += sc->data[SC_SERVICE4U]->val2;
  2406. if(sc->data[SC_MERC_SPUP])
  2407. bonus += sc->data[SC_MERC_SPUP]->val2;
  2408. if (sc->data[SC_LUXANIMA])
  2409. bonus += sc->data[SC_LUXANIMA]->val3;
  2410. if (sc->data[SC_MTF_MSP])
  2411. bonus += sc->data[SC_MTF_MSP]->val1;
  2412. if(sc->data[SC_PACKING_ENVELOPE4])
  2413. bonus += sc->data[SC_PACKING_ENVELOPE4]->val1;
  2414. //Decreasing
  2415. if (sc->data[SC_MELODYOFSINK])
  2416. bonus -= sc->data[SC_MELODYOFSINK]->val3;
  2417. }
  2418. // Max rate reduce is -100%
  2419. bonus = cap_value(bonus,-100,INT_MAX);
  2420. }
  2421. return min(bonus,INT_MAX);
  2422. }
  2423. /**
  2424. * SP bonus rate from equipment
  2425. */
  2426. static int status_get_spbonus_equip(TBL_PC *sd) {
  2427. int bonus = 0;
  2428. bonus += sd->sprate;
  2429. return bonus -= 100; //Default sprate is 100, so it should be add 0%
  2430. }
  2431. /**
  2432. * SP bonus rate from usable items
  2433. */
  2434. static int status_get_spbonus_item(block_list *bl) {
  2435. int bonus = 0;
  2436. struct status_change *sc = status_get_sc(bl);
  2437. //Bonus by SC
  2438. if (sc) {
  2439. if (sc->data[SC_INCREASE_MAXSP])
  2440. bonus += sc->data[SC_INCREASE_MAXSP]->val1;
  2441. if (sc->data[SC_LIFE_FORCE_F])
  2442. bonus += sc->data[SC_LIFE_FORCE_F]->val1;
  2443. if (sc->data[SC_VITATA_500])
  2444. bonus += sc->data[SC_VITATA_500]->val2;
  2445. if (sc->data[SC_ENERGY_DRINK_RESERCH])
  2446. bonus += sc->data[SC_ENERGY_DRINK_RESERCH]->val3;
  2447. }
  2448. // Max rate reduce is -100%
  2449. return cap_value(bonus, -100, INT_MAX);
  2450. }
  2451. /**
  2452. * Get AP bonus modifiers
  2453. * @param bl: block_list that will be checked
  2454. * @param type: type of e_status_bonus (STATUS_BONUS_FIX or STATUS_BONUS_RATE)
  2455. * @return bonus: total bonus for AP
  2456. */
  2457. static int status_get_apbonus(struct block_list *bl, enum e_status_bonus type) {
  2458. int bonus = 0;
  2459. if (type == STATUS_BONUS_FIX) {
  2460. struct status_change *sc = status_get_sc(bl);
  2461. //Only for BL_PC
  2462. if (bl->type == BL_PC) {
  2463. struct map_session_data *sd = map_id2sd(bl->id);
  2464. //uint16 skill_lv;
  2465. bonus += sd->bonus.ap;
  2466. //if ((skill_lv = pc_checkskill(sd, NV_BASIC)) > 0)
  2467. // bonus += 100 * skill_lv;
  2468. }
  2469. //Bonus by SC
  2470. if (sc) {
  2471. //if (sc->data[SC_NONE])
  2472. // bonus += sc->data[SC_NONE]->val1;
  2473. }
  2474. } else if (type == STATUS_BONUS_RATE) {
  2475. struct status_change *sc = status_get_sc(bl);
  2476. //Only for BL_PC
  2477. if (bl->type == BL_PC) {
  2478. struct map_session_data *sd = map_id2sd(bl->id);
  2479. //uint8 i;
  2480. //if ((i = pc_checkskill(sd, NV_BASIC)) > 0)
  2481. // bonus += 100 * i;
  2482. }
  2483. //Bonus by SC
  2484. if (sc) {
  2485. //if (sc->data[SC_NONE])
  2486. // bonus += sc->data[SC_NONE]->val1;
  2487. }
  2488. // Max rate reduce is -100%
  2489. bonus = cap_value(bonus, -100, INT_MAX);
  2490. }
  2491. return min(bonus, INT_MAX);
  2492. }
  2493. /**
  2494. * AP bonus rate from equipment
  2495. * @param sd: Player data
  2496. * @return AP rate
  2497. */
  2498. static int status_get_apbonus_equip(TBL_PC *sd) {
  2499. int bonus = 0;
  2500. bonus += sd->aprate;
  2501. return bonus -= 100; //Default aprate is 100, so it should be add 0%
  2502. }
  2503. /**
  2504. * AP bonus rate from usable items
  2505. * @param bl: Object to check against
  2506. * @return AP bonus
  2507. */
  2508. static int status_get_apbonus_item(block_list *bl) {
  2509. int bonus = 0;
  2510. struct status_change *sc = status_get_sc(bl);
  2511. //Bonus by SC
  2512. if (sc) {
  2513. //if (sc->data[SC_NONE])
  2514. // bonus += sc->data[SC_NONE]->val1;
  2515. }
  2516. // Max rate reduce is -100%
  2517. return cap_value(bonus, -100, INT_MAX);
  2518. }
  2519. /**
  2520. * Get final MaxHP or MaxSP for player. References: http://irowiki.org/wiki/Max_HP and http://irowiki.org/wiki/Max_SP
  2521. * The calculation needs base_level, base_status/battle_status (vit or int), additive modifier, and multiplicative modifier
  2522. * @param sd Player
  2523. * @param stat Vit/Int of player as param modifier
  2524. * @param isHP true - calculates Max HP, false - calculated Max SP
  2525. * @return max The max value of HP or SP
  2526. */
  2527. static unsigned int status_calc_maxhpsp_pc(struct map_session_data* sd, unsigned int stat, bool isHP) {
  2528. nullpo_ret(sd);
  2529. double dmax = 0;
  2530. uint32 level = umax(sd->status.base_level,1);
  2531. std::shared_ptr<s_job_info> job = job_db.find(pc_mapid2jobid(sd->class_, sd->status.sex));
  2532. if (job == nullptr)
  2533. return 1;
  2534. if (isHP) { //Calculates MaxHP
  2535. double equip_bonus = 0, item_bonus = 0;
  2536. 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);
  2537. dmax += sd->indexed_bonus.param_equip[PARAM_VIT]; //Vit from equip gives +1 additional HP
  2538. dmax += status_get_hpbonus(&sd->bl,STATUS_BONUS_FIX);
  2539. equip_bonus = (dmax * status_get_hpbonus_equip(sd) / 100);
  2540. item_bonus = (dmax * status_get_hpbonus_item(&sd->bl) / 100);
  2541. dmax += equip_bonus + item_bonus;
  2542. dmax += (int64)(dmax * status_get_hpbonus(&sd->bl,STATUS_BONUS_RATE) / 100); //Aegis accuracy
  2543. }
  2544. else { //Calculates MaxSP
  2545. double equip_bonus = 0, item_bonus = 0;
  2546. 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);
  2547. dmax += sd->indexed_bonus.param_equip[PARAM_INT]; //Int from equip gives +1 additional SP
  2548. dmax += status_get_spbonus(&sd->bl,STATUS_BONUS_FIX);
  2549. equip_bonus = (dmax * status_get_spbonus_equip(sd) / 100);
  2550. item_bonus = (dmax * status_get_spbonus_item(&sd->bl) / 100);
  2551. dmax += equip_bonus + item_bonus;
  2552. dmax += (int64)(dmax * status_get_spbonus(&sd->bl,STATUS_BONUS_RATE) / 100); //Aegis accuracy
  2553. }
  2554. //Make sure it's not negative before casting to unsigned int
  2555. if(dmax < 1) dmax = 1;
  2556. return cap_value((unsigned int)dmax,1,UINT_MAX);
  2557. }
  2558. /**
  2559. * Get final MaxAP for player.
  2560. * @param sd: Player data
  2561. * @return AP amount
  2562. */
  2563. static unsigned int status_calc_maxap_pc(struct map_session_data* sd) {
  2564. double dmax = 0, equip_bonus = 0, item_bonus = 0;
  2565. nullpo_ret(sd);
  2566. dmax = (sd->class_&JOBL_FOURTH) ? 200 : 0;
  2567. dmax += status_get_apbonus(&sd->bl, STATUS_BONUS_FIX);
  2568. equip_bonus = (dmax * status_get_apbonus_equip(sd) / 100);
  2569. item_bonus = (dmax * status_get_apbonus_item(&sd->bl) / 100);
  2570. dmax += equip_bonus + item_bonus;
  2571. dmax += (int64)(dmax * status_get_apbonus(&sd->bl, STATUS_BONUS_RATE) / 100);// Aegis accuracy
  2572. //Make sure it's not negative before casting to unsigned int
  2573. if (dmax < 0) dmax = 0;
  2574. return cap_value((unsigned int)dmax, 0, UINT_MAX);
  2575. }
  2576. /**
  2577. * Calculates player's weight
  2578. * @param sd: Player object
  2579. * @param flag: Calculation type
  2580. * CALCWT_ITEM - Item weight
  2581. * CALCWT_MAXBONUS - Skill/Status/Configuration max weight bonus
  2582. * @return false - failed, true - success
  2583. */
  2584. bool status_calc_weight(struct map_session_data *sd, enum e_status_calc_weight_opt flag)
  2585. {
  2586. int b_weight, b_max_weight, skill, i;
  2587. struct status_change *sc;
  2588. nullpo_retr(false, sd);
  2589. sc = &sd->sc;
  2590. b_max_weight = sd->max_weight; // Store max weight for later comparison
  2591. b_weight = sd->weight; // Store current weight for later comparison
  2592. sd->max_weight = job_db.get_maxWeight(pc_mapid2jobid(sd->class_, sd->status.sex)) + sd->status.str * 300; // Recalculate max weight
  2593. if (flag&CALCWT_ITEM) {
  2594. sd->weight = 0; // Reset current weight
  2595. for(i = 0; i < MAX_INVENTORY; i++) {
  2596. if (!sd->inventory.u.items_inventory[i].nameid || sd->inventory_data[i] == NULL)
  2597. continue;
  2598. sd->weight += sd->inventory_data[i]->weight * sd->inventory.u.items_inventory[i].amount;
  2599. }
  2600. }
  2601. if (flag&CALCWT_MAXBONUS) {
  2602. // Skill/Status bonus weight increases
  2603. sd->max_weight += sd->add_max_weight; // From bAddMaxWeight
  2604. if ((skill = pc_checkskill(sd, MC_INCCARRY)) > 0)
  2605. sd->max_weight += 2000 * skill;
  2606. if (pc_isriding(sd) && pc_checkskill(sd, KN_RIDING) > 0)
  2607. sd->max_weight += 10000;
  2608. else if (pc_isridingdragon(sd))
  2609. sd->max_weight += 5000 + 2000 * pc_checkskill(sd, RK_DRAGONTRAINING);
  2610. if (sc->data[SC_KNOWLEDGE])
  2611. sd->max_weight += sd->max_weight * sc->data[SC_KNOWLEDGE]->val1 / 10;
  2612. if ((skill = pc_checkskill(sd, ALL_INCCARRY)) > 0)
  2613. sd->max_weight += 2000 * skill;
  2614. if (pc_ismadogear(sd))
  2615. sd->max_weight += 15000;
  2616. }
  2617. // Update the client if the new weight calculations don't match
  2618. if (b_weight != sd->weight)
  2619. clif_updatestatus(sd, SP_WEIGHT);
  2620. if (b_max_weight != sd->max_weight) {
  2621. clif_updatestatus(sd, SP_MAXWEIGHT);
  2622. pc_updateweightstatus(sd);
  2623. }
  2624. return true;
  2625. }
  2626. /**
  2627. * Calculates player's cart weight
  2628. * @param sd: Player object
  2629. * @param flag: Calculation type
  2630. * CALCWT_ITEM - Cart item weight
  2631. * CALCWT_MAXBONUS - Skill/Status/Configuration max weight bonus
  2632. * CALCWT_CARTSTATE - Whether to check for cart state
  2633. * @return false - failed, true - success
  2634. */
  2635. bool status_calc_cart_weight(struct map_session_data *sd, enum e_status_calc_weight_opt flag)
  2636. {
  2637. int b_cart_weight_max, i;
  2638. nullpo_retr(false, sd);
  2639. if (!pc_iscarton(sd) && !(flag&CALCWT_CARTSTATE))
  2640. return false;
  2641. b_cart_weight_max = sd->cart_weight_max; // Store cart max weight for later comparison
  2642. sd->cart_weight_max = battle_config.max_cart_weight; // Recalculate max weight
  2643. if (flag&CALCWT_ITEM) {
  2644. sd->cart_weight = 0; // Reset current cart weight
  2645. sd->cart_num = 0; // Reset current cart item count
  2646. for(i = 0; i < MAX_CART; i++) {
  2647. if (!sd->cart.u.items_cart[i].nameid)
  2648. continue;
  2649. sd->cart_weight += itemdb_weight(sd->cart.u.items_cart[i].nameid) * sd->cart.u.items_cart[i].amount; // Recalculate current cart weight
  2650. sd->cart_num++; // Recalculate current cart item count
  2651. }
  2652. }
  2653. // Skill bonus max weight increases
  2654. if (flag&CALCWT_MAXBONUS)
  2655. sd->cart_weight_max += (pc_checkskill(sd, GN_REMODELING_CART) * 5000);
  2656. // Update the client if the new weight calculations don't match
  2657. if (b_cart_weight_max != sd->cart_weight_max)
  2658. clif_updatestatus(sd, SP_CARTINFO);
  2659. return true;
  2660. }
  2661. /**
  2662. * Calculates player data from scratch without counting SC adjustments
  2663. * Should be invoked whenever players raise stats, learn passive skills or change equipment
  2664. * @param sd: Player object
  2665. * @param opt: Whether it is first calc (login) or not
  2666. * @return (-1) for too many recursive calls, (1) recursive call, (0) success
  2667. */
  2668. int status_calc_pc_sub(struct map_session_data* sd, uint8 opt)
  2669. {
  2670. static int calculating = 0; ///< Check for recursive call preemption. [Skotlex]
  2671. struct status_data *base_status; ///< Pointer to the player's base status
  2672. const struct status_change *sc = &sd->sc;
  2673. struct s_skill b_skill[MAX_SKILL]; ///< Previous skill tree
  2674. int i, skill, refinedef = 0;
  2675. short index = -1;
  2676. if (++calculating > 10) // Too many recursive calls!
  2677. return -1;
  2678. // Remember player-specific values that are currently being shown to the client (for refresh purposes)
  2679. memcpy(b_skill, &sd->status.skill, sizeof(b_skill));
  2680. pc_calc_skilltree(sd); // SkillTree calculation
  2681. if (opt&SCO_FIRST) {
  2682. // Load Hp/SP from char-received data.
  2683. sd->battle_status.hp = sd->status.hp;
  2684. sd->battle_status.sp = sd->status.sp;
  2685. if (battle_config.keep_ap_on_logout == 1)
  2686. sd->battle_status.ap = sd->status.ap;
  2687. sd->regen.sregen = &sd->sregen;
  2688. sd->regen.ssregen = &sd->ssregen;
  2689. }
  2690. base_status = &sd->base_status;
  2691. // These are not zeroed. [zzo]
  2692. sd->hprate = 100;
  2693. sd->sprate = 100;
  2694. sd->aprate = 100;
  2695. sd->castrate = 100;
  2696. sd->dsprate = 100;
  2697. sd->hprecov_rate = 100;
  2698. sd->sprecov_rate = 100;
  2699. sd->matk_rate = 100;
  2700. sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100;
  2701. sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100;
  2702. sd->patk_rate = sd->smatk_rate = 100;
  2703. sd->res_rate = sd->mres_rate = 100;
  2704. sd->hplus_rate = sd->crate_rate = 100;
  2705. sd->regen.state.block = 0;
  2706. sd->add_max_weight = 0;
  2707. sd->indexed_bonus = {};
  2708. memset (&sd->right_weapon.overrefine, 0, sizeof(sd->right_weapon) - sizeof(sd->right_weapon.atkmods));
  2709. memset (&sd->left_weapon.overrefine, 0, sizeof(sd->left_weapon) - sizeof(sd->left_weapon.atkmods));
  2710. if (sd->special_state.intravision)
  2711. clif_status_load(&sd->bl, EFST_CLAIRVOYANCE, 0);
  2712. if (sd->special_state.no_walk_delay)
  2713. clif_status_load(&sd->bl, EFST_ENDURE, 0);
  2714. if (sd->special_state.movehaste)
  2715. clif_status_load(&sd->bl, EFST_MOVHASTE_INFINITY, 0);
  2716. memset(&sd->special_state,0,sizeof(sd->special_state));
  2717. if (pc_isvip(sd)) // Magic Stone requirement avoidance for VIP.
  2718. sd->special_state.no_gemstone = battle_config.vip_gemstone;
  2719. if (!sd->state.permanent_speed) {
  2720. memset(&base_status->max_hp, 0, sizeof(struct status_data)-(sizeof(base_status->hp)+sizeof(base_status->sp)+sizeof(base_status->ap)));
  2721. base_status->speed = DEFAULT_WALK_SPEED;
  2722. } else {
  2723. int pSpeed = base_status->speed;
  2724. memset(&base_status->max_hp, 0, sizeof(struct status_data)-(sizeof(base_status->hp)+sizeof(base_status->sp)+sizeof(base_status->ap)));
  2725. base_status->speed = pSpeed;
  2726. }
  2727. // !FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex]
  2728. // Give them all modes except these (useful for clones)
  2729. 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));
  2730. base_status->size = (sd->class_&JOBL_BABY) ? SZ_SMALL : (((sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) ? battle_config.summoner_size : SZ_MEDIUM);
  2731. if (battle_config.character_size && pc_isriding(sd)) { // [Lupus]
  2732. if (sd->class_&JOBL_BABY) {
  2733. if (battle_config.character_size&SZ_BIG)
  2734. base_status->size++;
  2735. } else
  2736. if(battle_config.character_size&SZ_MEDIUM)
  2737. base_status->size++;
  2738. }
  2739. base_status->aspd_rate = 1000;
  2740. base_status->ele_lv = 1;
  2741. base_status->race = ((sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) ? battle_config.summoner_race : RC_PLAYER_HUMAN;
  2742. base_status->class_ = CLASS_NORMAL;
  2743. sd->autospell.clear();
  2744. sd->autospell2.clear();
  2745. sd->autospell3.clear();
  2746. sd->addeff.clear();
  2747. sd->addeff_atked.clear();
  2748. sd->addeff_onskill.clear();
  2749. sd->skillatk.clear();
  2750. sd->skillusesprate.clear();
  2751. sd->skillusesp.clear();
  2752. sd->skillheal.clear();
  2753. sd->skillheal2.clear();
  2754. sd->skillblown.clear();
  2755. sd->skillcastrate.clear();
  2756. sd->skillfixcastrate.clear();
  2757. sd->subskill.clear();
  2758. sd->skillcooldown.clear();
  2759. sd->skillfixcast.clear();
  2760. sd->skillvarcast.clear();
  2761. sd->add_def.clear();
  2762. sd->add_mdef.clear();
  2763. sd->add_mdmg.clear();
  2764. sd->reseff.clear();
  2765. sd->itemgrouphealrate.clear();
  2766. sd->add_drop.clear();
  2767. sd->itemhealrate.clear();
  2768. sd->subele2.clear();
  2769. sd->subrace3.clear();
  2770. sd->skilldelay.clear();
  2771. sd->sp_vanish.clear();
  2772. sd->hp_vanish.clear();
  2773. sd->itemsphealrate.clear();
  2774. sd->itemgroupsphealrate.clear();
  2775. // Zero up structures...
  2776. memset(&sd->hp_loss, 0, sizeof(sd->hp_loss)
  2777. + sizeof(sd->sp_loss)
  2778. + sizeof(sd->hp_regen)
  2779. + sizeof(sd->sp_regen)
  2780. + sizeof(sd->percent_hp_regen)
  2781. + sizeof(sd->percent_sp_regen)
  2782. + sizeof(sd->def_set_race)
  2783. + sizeof(sd->mdef_set_race)
  2784. + sizeof(sd->norecover_state_race)
  2785. + sizeof(sd->hp_vanish_race)
  2786. + sizeof(sd->sp_vanish_race)
  2787. );
  2788. memset(&sd->bonus, 0, sizeof(sd->bonus));
  2789. // Autobonus
  2790. pc_delautobonus(*sd, sd->autobonus, true);
  2791. pc_delautobonus(*sd, sd->autobonus2, true);
  2792. pc_delautobonus(*sd, sd->autobonus3, true);
  2793. // Parse equipment
  2794. for (i = 0; i < EQI_MAX; i++) {
  2795. current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
  2796. current_equip_combo_pos = 0;
  2797. if (index < 0)
  2798. continue;
  2799. if (i == EQI_AMMO)
  2800. continue;
  2801. if (pc_is_same_equip_index((enum equip_index)i, sd->equip_index, index))
  2802. continue;
  2803. if (!sd->inventory_data[index])
  2804. continue;
  2805. base_status->def += sd->inventory_data[index]->def;
  2806. // Items may be equipped, their effects however are nullified.
  2807. if (opt&SCO_FIRST && sd->inventory_data[index]->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT)
  2808. || !itemdb_isNoEquip(sd->inventory_data[index],sd->bl.m))) { // Execute equip-script on login
  2809. run_script(sd->inventory_data[index]->equip_script,0,sd->bl.id,0);
  2810. if (!calculating)
  2811. return 1;
  2812. }
  2813. // Sanitize the refine level in case someone decreased the value inbetween
  2814. if (sd->inventory.u.items_inventory[index].refine > MAX_REFINE)
  2815. sd->inventory.u.items_inventory[index].refine = MAX_REFINE;
  2816. std::shared_ptr<s_refine_level_info> info = refine_db.findCurrentLevelInfo( *sd->inventory_data[index], sd->inventory.u.items_inventory[index] );
  2817. if (sd->inventory_data[index]->type == IT_WEAPON) {
  2818. int wlv = sd->inventory_data[index]->weapon_level;
  2819. struct weapon_data *wd;
  2820. struct weapon_atk *wa;
  2821. if(wlv >= MAX_WEAPON_LEVEL)
  2822. wlv = MAX_WEAPON_LEVEL;
  2823. if(i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) {
  2824. wd = &sd->left_weapon; // Left-hand weapon
  2825. wa = &base_status->lhw;
  2826. } else {
  2827. wd = &sd->right_weapon;
  2828. wa = &base_status->rhw;
  2829. }
  2830. wa->atk += sd->inventory_data[index]->atk;
  2831. if( info != nullptr ){
  2832. wa->atk2 += info->bonus / 100;
  2833. #ifdef RENEWAL
  2834. // TODO: additional grade bonus
  2835. if( wlv == 5 ){
  2836. base_status->patk += sd->inventory.u.items_inventory[index].refine * 2;
  2837. base_status->smatk += sd->inventory.u.items_inventory[index].refine * 2;
  2838. }
  2839. #endif
  2840. }
  2841. #ifdef RENEWAL
  2842. if (sd->bonus.weapon_atk_rate)
  2843. wa->atk += wa->atk * sd->bonus.weapon_atk_rate / 100;
  2844. wa->matk += sd->inventory_data[index]->matk;
  2845. wa->wlv = wlv;
  2846. // Renewal magic attack refine bonus
  2847. if( info != nullptr && sd->weapontype1 != W_BOW ){
  2848. wa->matk += info->bonus / 100;
  2849. // TODO: additional grade bonus
  2850. }
  2851. #endif
  2852. // Overrefine bonus.
  2853. if( info != nullptr ){
  2854. wd->overrefine = info->randombonus_max / 100;
  2855. }
  2856. wa->range += sd->inventory_data[index]->range;
  2857. if(sd->inventory_data[index]->script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(sd->inventory_data[index],sd->bl.m))) {
  2858. if (wd == &sd->left_weapon) {
  2859. sd->state.lr_flag = 1;
  2860. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  2861. sd->state.lr_flag = 0;
  2862. } else
  2863. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  2864. if (!calculating) // Abort, run_script retriggered this. [Skotlex]
  2865. return 1;
  2866. }
  2867. #ifdef RENEWAL
  2868. if (sd->bonus.weapon_matk_rate)
  2869. wa->matk += wa->matk * sd->bonus.weapon_matk_rate / 100;
  2870. #endif
  2871. if(sd->inventory.u.items_inventory[index].card[0] == CARD0_FORGE) { // Forged weapon
  2872. wd->star += (sd->inventory.u.items_inventory[index].card[1]>>8);
  2873. if(wd->star >= 15) wd->star = 40; // 3 Star Crumbs now give +40 dmg
  2874. if(pc_famerank(MakeDWord(sd->inventory.u.items_inventory[index].card[2],sd->inventory.u.items_inventory[index].card[3]) ,MAPID_BLACKSMITH))
  2875. wd->star += 10;
  2876. if (!wa->ele) // Do not overwrite element from previous bonuses.
  2877. wa->ele = (sd->inventory.u.items_inventory[index].card[1]&0x0f);
  2878. }
  2879. } else if(sd->inventory_data[index]->type == IT_ARMOR) {
  2880. if( info != nullptr ){
  2881. refinedef += info->bonus;
  2882. #ifdef RENEWAL
  2883. if( sd->inventory_data[index]->armor_level == 2 ){
  2884. base_status->res += sd->inventory.u.items_inventory[index].refine * 2;
  2885. base_status->mres += sd->inventory.u.items_inventory[index].refine * 2;
  2886. }
  2887. #endif
  2888. }
  2889. if(sd->inventory_data[index]->script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(sd->inventory_data[index],sd->bl.m))) {
  2890. if( i == EQI_HAND_L ) // Shield
  2891. sd->state.lr_flag = 3;
  2892. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  2893. if( i == EQI_HAND_L ) // Shield
  2894. sd->state.lr_flag = 0;
  2895. if (!calculating) // Abort, run_script retriggered this. [Skotlex]
  2896. return 1;
  2897. }
  2898. } else if( sd->inventory_data[index]->type == IT_SHADOWGEAR ) { // Shadow System
  2899. if (sd->inventory_data[index]->script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(sd->inventory_data[index],sd->bl.m))) {
  2900. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  2901. if( !calculating )
  2902. return 1;
  2903. }
  2904. }
  2905. }
  2906. if(sd->equip_index[EQI_AMMO] >= 0) {
  2907. index = sd->equip_index[EQI_AMMO];
  2908. if(sd->inventory_data[index]) { // Arrows
  2909. sd->bonus.arrow_atk += sd->inventory_data[index]->atk;
  2910. sd->state.lr_flag = 2;
  2911. if( !itemdb_group.item_exists(IG_THROWABLE, sd->inventory_data[index]->nameid) ) // Don't run scripts on throwable items
  2912. run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
  2913. sd->state.lr_flag = 0;
  2914. if (!calculating) // Abort, run_script retriggered status_calc_pc. [Skotlex]
  2915. return 1;
  2916. }
  2917. }
  2918. // Process and check item combos
  2919. if (!sd->combos.empty()) {
  2920. for (const auto &combo : sd->combos) {
  2921. std::shared_ptr<s_item_combo> item_combo;
  2922. current_equip_item_index = -1;
  2923. current_equip_combo_pos = combo->pos;
  2924. if (combo->bonus == nullptr || !(item_combo = itemdb_combo.find(combo->id)))
  2925. continue;
  2926. bool no_run = false;
  2927. size_t j = 0;
  2928. // Check combo items
  2929. while (j < item_combo->nameid.size()) {
  2930. item_data *id = itemdb_exists(item_combo->nameid[j]);
  2931. // Don't run the script if at least one of combo's pair has restriction
  2932. if (id && !pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(id, sd->bl.m)) {
  2933. no_run = true;
  2934. break;
  2935. }
  2936. j++;
  2937. }
  2938. if (no_run)
  2939. continue;
  2940. run_script(combo->bonus, 0, sd->bl.id, 0);
  2941. if (!calculating) // Abort, run_script retriggered this
  2942. return 1;
  2943. }
  2944. }
  2945. // Store equipment script bonuses
  2946. memcpy(sd->indexed_bonus.param_equip,sd->indexed_bonus.param_bonus,sizeof(sd->indexed_bonus.param_equip));
  2947. memset(sd->indexed_bonus.param_bonus, 0, sizeof(sd->indexed_bonus.param_bonus));
  2948. base_status->def += (refinedef+50)/100;
  2949. // Parse Cards
  2950. for (i = 0; i < EQI_MAX; i++) {
  2951. current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
  2952. current_equip_combo_pos = 0;
  2953. if (index < 0)
  2954. continue;
  2955. if (i == EQI_AMMO)
  2956. continue;
  2957. if (pc_is_same_equip_index((enum equip_index)i, sd->equip_index, index))
  2958. continue;
  2959. if (sd->inventory_data[index]) {
  2960. int j;
  2961. struct item_data *data;
  2962. // Card script execution.
  2963. if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
  2964. continue;
  2965. for (j = 0; j < MAX_SLOTS; j++) { // Uses MAX_SLOTS to support Soul Bound system [Inkfish]
  2966. int c = sd->inventory.u.items_inventory[index].card[j];
  2967. current_equip_card_id= c;
  2968. if(!c)
  2969. continue;
  2970. data = itemdb_exists(c);
  2971. if(!data)
  2972. continue;
  2973. if (opt&SCO_FIRST && data->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(data,sd->bl.m))) {// Execute equip-script on login
  2974. run_script(data->equip_script,0,sd->bl.id,0);
  2975. if (!calculating)
  2976. return 1;
  2977. }
  2978. if(!data->script)
  2979. continue;
  2980. if(!pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(data,sd->bl.m)) // Card restriction checks.
  2981. continue;
  2982. if(i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) { // Left hand status.
  2983. sd->state.lr_flag = 1;
  2984. run_script(data->script,0,sd->bl.id,0);
  2985. sd->state.lr_flag = 0;
  2986. } else
  2987. run_script(data->script,0,sd->bl.id,0);
  2988. if (!calculating) // Abort, run_script his function. [Skotlex]
  2989. return 1;
  2990. }
  2991. }
  2992. }
  2993. current_equip_card_id = 0; // Clear stored card ID [Secret]
  2994. // Parse random options
  2995. for (i = 0; i < EQI_MAX; i++) {
  2996. current_equip_item_index = index = sd->equip_index[i];
  2997. current_equip_combo_pos = 0;
  2998. current_equip_opt_index = -1;
  2999. if (index < 0)
  3000. continue;
  3001. if (i == EQI_AMMO)
  3002. continue;
  3003. if (pc_is_same_equip_index((enum equip_index)i, sd->equip_index, index))
  3004. continue;
  3005. if (sd->inventory_data[index]) {
  3006. for (uint8 j = 0; j < MAX_ITEM_RDM_OPT; j++) {
  3007. short opt_id = sd->inventory.u.items_inventory[index].option[j].id;
  3008. if (!opt_id)
  3009. continue;
  3010. current_equip_opt_index = j;
  3011. std::shared_ptr<s_random_opt_data> data = random_option_db.find(opt_id);
  3012. if (!data || !data->script)
  3013. continue;
  3014. if (!pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(sd->inventory_data[index], sd->bl.m))
  3015. continue;
  3016. if (i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) { // Left hand status.
  3017. sd->state.lr_flag = 1;
  3018. run_script(data->script, 0, sd->bl.id, 0);
  3019. sd->state.lr_flag = 0;
  3020. }
  3021. else
  3022. run_script(data->script, 0, sd->bl.id, 0);
  3023. if (!calculating)
  3024. return 1;
  3025. }
  3026. }
  3027. current_equip_opt_index = -1;
  3028. }
  3029. if (sc->count && sc->data[SC_ITEMSCRIPT]) {
  3030. struct item_data *data = itemdb_exists(sc->data[SC_ITEMSCRIPT]->val1);
  3031. if (data && data->script)
  3032. run_script(data->script, 0, sd->bl.id, 0);
  3033. }
  3034. pc_bonus_script(sd);
  3035. if( sd->pd ) { // Pet Bonus
  3036. struct pet_data *pd = sd->pd;
  3037. std::shared_ptr<s_pet_db> pet_db_ptr = pd->get_pet_db();
  3038. if (pet_db_ptr != nullptr && pet_db_ptr->pet_bonus_script)
  3039. run_script(pet_db_ptr->pet_bonus_script,0,sd->bl.id,0);
  3040. if (pet_db_ptr != nullptr && pd->pet.intimate > 0 && (!battle_config.pet_equip_required || pd->pet.equip > 0) && pd->state.skillbonus == 1 && pd->bonus)
  3041. pc_bonus(sd,pd->bonus->type, pd->bonus->val);
  3042. }
  3043. // param_bonus now holds card bonuses.
  3044. if(base_status->rhw.range < 1) base_status->rhw.range = 1;
  3045. if(base_status->lhw.range < 1) base_status->lhw.range = 1;
  3046. if(base_status->rhw.range < base_status->lhw.range)
  3047. base_status->rhw.range = base_status->lhw.range;
  3048. sd->bonus.double_rate += sd->bonus.double_add_rate;
  3049. sd->bonus.perfect_hit += sd->bonus.perfect_hit_add;
  3050. sd->bonus.splash_range += sd->bonus.splash_add_range;
  3051. // Damage modifiers from weapon type
  3052. std::shared_ptr<s_sizefix_db> right_weapon = size_fix_db.find(sd->weapontype1);
  3053. std::shared_ptr<s_sizefix_db> left_weapon = size_fix_db.find(sd->weapontype2);
  3054. sd->right_weapon.atkmods[SZ_SMALL] = right_weapon->small;
  3055. sd->right_weapon.atkmods[SZ_MEDIUM] = right_weapon->medium;
  3056. sd->right_weapon.atkmods[SZ_BIG] = right_weapon->large;
  3057. sd->left_weapon.atkmods[SZ_SMALL] = left_weapon->small;
  3058. sd->left_weapon.atkmods[SZ_MEDIUM] = left_weapon->medium;
  3059. sd->left_weapon.atkmods[SZ_BIG] = left_weapon->large;
  3060. if((pc_isriding(sd) || pc_isridingdragon(sd)) &&
  3061. (sd->status.weapon==W_1HSPEAR || sd->status.weapon==W_2HSPEAR))
  3062. { // When Riding with spear, damage modifier to mid-class becomes
  3063. // same as versus large size.
  3064. sd->right_weapon.atkmods[SZ_MEDIUM] = sd->right_weapon.atkmods[SZ_BIG];
  3065. sd->left_weapon.atkmods[SZ_MEDIUM] = sd->left_weapon.atkmods[SZ_BIG];
  3066. }
  3067. // ----- STATS CALCULATION -----
  3068. // Job bonuses
  3069. std::shared_ptr<s_job_info> job_info = job_db.find( pc_mapid2jobid( sd->class_, sd->status.sex ) );
  3070. if( job_info != nullptr ){
  3071. const auto& bonus = job_info->job_bonus[sd->status.job_level-1];
  3072. base_status->str += bonus[PARAM_STR];
  3073. base_status->agi += bonus[PARAM_AGI];
  3074. base_status->vit += bonus[PARAM_VIT];
  3075. base_status->int_ += bonus[PARAM_INT];
  3076. base_status->dex += bonus[PARAM_DEX];
  3077. base_status->luk += bonus[PARAM_LUK];
  3078. base_status->pow += bonus[PARAM_POW];
  3079. base_status->sta += bonus[PARAM_STA];
  3080. base_status->wis += bonus[PARAM_WIS];
  3081. base_status->spl += bonus[PARAM_SPL];
  3082. base_status->con += bonus[PARAM_CON];
  3083. base_status->crt += bonus[PARAM_CRT];
  3084. }
  3085. // If a Super Novice has never died and is at least joblv 70, he gets all stats +10
  3086. if(((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && (sd->status.job_level >= 70 || sd->class_&JOBL_THIRD)) && sd->die_counter == 0) {
  3087. base_status->str += 10;
  3088. base_status->agi += 10;
  3089. base_status->vit += 10;
  3090. base_status->int_+= 10;
  3091. base_status->dex += 10;
  3092. base_status->luk += 10;
  3093. }
  3094. // Absolute modifiers from passive skills
  3095. if(pc_checkskill(sd,BS_HILTBINDING)>0)
  3096. base_status->str++;
  3097. if((skill=pc_checkskill(sd,SA_DRAGONOLOGY))>0)
  3098. base_status->int_ += (skill+1)/2; // +1 INT / 2 lv
  3099. if((skill=pc_checkskill(sd,AC_OWL))>0)
  3100. base_status->dex += skill;
  3101. if((skill = pc_checkskill(sd,RA_RESEARCHTRAP))>0)
  3102. base_status->int_ += skill;
  3103. if (pc_checkskill(sd, SU_POWEROFLAND) > 0)
  3104. base_status->int_ += 20;
  3105. // Bonuses from cards and equipment as well as base stat, remember to avoid overflows.
  3106. i = base_status->str + sd->status.str + sd->indexed_bonus.param_bonus[PARAM_STR] + sd->indexed_bonus.param_equip[PARAM_STR];
  3107. base_status->str = cap_value(i,0,USHRT_MAX);
  3108. i = base_status->agi + sd->status.agi + sd->indexed_bonus.param_bonus[PARAM_AGI] + sd->indexed_bonus.param_equip[PARAM_AGI];
  3109. base_status->agi = cap_value(i,0,USHRT_MAX);
  3110. i = base_status->vit + sd->status.vit + sd->indexed_bonus.param_bonus[PARAM_VIT] + sd->indexed_bonus.param_equip[PARAM_VIT];
  3111. base_status->vit = cap_value(i,0,USHRT_MAX);
  3112. i = base_status->int_+ sd->status.int_+ sd->indexed_bonus.param_bonus[PARAM_INT] + sd->indexed_bonus.param_equip[PARAM_INT];
  3113. base_status->int_ = cap_value(i,0,USHRT_MAX);
  3114. i = base_status->dex + sd->status.dex + sd->indexed_bonus.param_bonus[PARAM_DEX] + sd->indexed_bonus.param_equip[PARAM_DEX];
  3115. base_status->dex = cap_value(i,0,USHRT_MAX);
  3116. i = base_status->luk + sd->status.luk + sd->indexed_bonus.param_bonus[PARAM_LUK] + sd->indexed_bonus.param_equip[PARAM_LUK];
  3117. base_status->luk = cap_value(i,0,USHRT_MAX);
  3118. i = base_status->pow + sd->status.pow + sd->indexed_bonus.param_bonus[PARAM_POW] + sd->indexed_bonus.param_equip[PARAM_POW];
  3119. base_status->pow = cap_value(i, 0, USHRT_MAX);
  3120. i = base_status->sta + sd->status.sta + sd->indexed_bonus.param_bonus[PARAM_STA] + sd->indexed_bonus.param_equip[PARAM_STA];
  3121. base_status->sta = cap_value(i, 0, USHRT_MAX);
  3122. i = base_status->wis + sd->status.wis + sd->indexed_bonus.param_bonus[PARAM_WIS] + sd->indexed_bonus.param_equip[PARAM_WIS];
  3123. base_status->wis = cap_value(i, 0, USHRT_MAX);
  3124. i = base_status->spl + sd->status.spl + sd->indexed_bonus.param_bonus[PARAM_SPL] + sd->indexed_bonus.param_equip[PARAM_SPL];
  3125. base_status->spl = cap_value(i, 0, USHRT_MAX);
  3126. i = base_status->con + sd->status.con + sd->indexed_bonus.param_bonus[PARAM_CON] + sd->indexed_bonus.param_equip[PARAM_CON];
  3127. base_status->con = cap_value(i, 0, USHRT_MAX);
  3128. i = base_status->crt + sd->status.crt + sd->indexed_bonus.param_bonus[PARAM_CRT] + sd->indexed_bonus.param_equip[PARAM_CRT];
  3129. base_status->crt = cap_value(i, 0, USHRT_MAX);
  3130. if (sd->special_state.no_walk_delay) {
  3131. if (sc->data[SC_ENDURE]) {
  3132. if (sc->data[SC_ENDURE]->val4)
  3133. sc->data[SC_ENDURE]->val4 = 0;
  3134. status_change_end(&sd->bl, SC_ENDURE, INVALID_TIMER);
  3135. }
  3136. clif_status_load(&sd->bl, EFST_ENDURE, 1);
  3137. base_status->mdef++;
  3138. }
  3139. // ------ ATTACK CALCULATION ------
  3140. // Base batk value is set in status_calc_misc
  3141. #ifndef RENEWAL
  3142. // !FIXME: Weapon-type bonus (Why is the weapon_atk bonus applied to base attack?)
  3143. if (sd->status.weapon < MAX_WEAPON_TYPE && sd->indexed_bonus.weapon_atk[sd->status.weapon])
  3144. base_status->batk += sd->indexed_bonus.weapon_atk[sd->status.weapon];
  3145. // Absolute modifiers from passive skills
  3146. if((skill=pc_checkskill(sd,BS_HILTBINDING))>0)
  3147. base_status->batk += 4;
  3148. #else
  3149. base_status->watk = status_weapon_atk(base_status->rhw);
  3150. base_status->watk2 = status_weapon_atk(base_status->lhw);
  3151. base_status->eatk = sd->bonus.eatk;
  3152. #endif
  3153. // ----- HP MAX CALCULATION -----
  3154. base_status->max_hp = sd->status.max_hp = status_calc_maxhpsp_pc(sd,base_status->vit,true);
  3155. if(battle_config.hp_rate != 100)
  3156. base_status->max_hp = (unsigned int)(battle_config.hp_rate * (base_status->max_hp/100.));
  3157. if (sd->status.base_level < 100)
  3158. base_status->max_hp = cap_value(base_status->max_hp,1,(unsigned int)battle_config.max_hp_lv99);
  3159. else if (sd->status.base_level < 151)
  3160. base_status->max_hp = cap_value(base_status->max_hp,1,(unsigned int)battle_config.max_hp_lv150);
  3161. else
  3162. base_status->max_hp = cap_value(base_status->max_hp,1,(unsigned int)battle_config.max_hp);
  3163. // ----- SP MAX CALCULATION -----
  3164. base_status->max_sp = sd->status.max_sp = status_calc_maxhpsp_pc(sd,base_status->int_,false);
  3165. if(battle_config.sp_rate != 100)
  3166. base_status->max_sp = (unsigned int)(battle_config.sp_rate * (base_status->max_sp/100.));
  3167. base_status->max_sp = cap_value(base_status->max_sp,1,(unsigned int)battle_config.max_sp);
  3168. // ----- AP MAX CALCULATION -----
  3169. base_status->max_ap = sd->status.max_ap = status_calc_maxap_pc(sd);
  3170. if (battle_config.ap_rate != 100)
  3171. base_status->max_ap = (unsigned int)(battle_config.ap_rate * (base_status->max_ap / 100.));
  3172. base_status->max_ap = cap_value(base_status->max_ap, 0, (unsigned int)battle_config.max_ap);
  3173. // ----- RESPAWN HP/SP/AP -----
  3174. // Calc respawn hp and store it on base_status
  3175. if (sd->special_state.restart_full_recover) {
  3176. base_status->hp = base_status->max_hp;
  3177. base_status->sp = base_status->max_sp;
  3178. } else {
  3179. if((sd->class_&MAPID_BASEMASK) == MAPID_NOVICE && !(sd->class_&JOBL_2)
  3180. && battle_config.restart_hp_rate < 50)
  3181. base_status->hp = base_status->max_hp>>1;
  3182. else
  3183. base_status->hp = (int64)base_status->max_hp * battle_config.restart_hp_rate/100;
  3184. if(!base_status->hp)
  3185. base_status->hp = 1;
  3186. base_status->sp = (int64)base_status->max_sp * battle_config.restart_sp_rate /100;
  3187. if( !base_status->sp ) // The minimum for the respawn setting is SP:1
  3188. base_status->sp = 1;
  3189. base_status->ap = (int64)base_status->max_ap * battle_config.restart_ap_rate / 100;
  3190. }
  3191. // ----- MISC CALCULATION -----
  3192. status_calc_misc(&sd->bl, base_status, sd->status.base_level);
  3193. // Equipment modifiers for misc settings
  3194. if(sd->matk_rate < 0)
  3195. sd->matk_rate = 0;
  3196. if(sd->matk_rate != 100) {
  3197. base_status->matk_max = base_status->matk_max * sd->matk_rate/100;
  3198. base_status->matk_min = base_status->matk_min * sd->matk_rate/100;
  3199. }
  3200. if(sd->hit_rate < 0)
  3201. sd->hit_rate = 0;
  3202. if(sd->hit_rate != 100)
  3203. base_status->hit = base_status->hit * sd->hit_rate/100;
  3204. if(sd->flee_rate < 0)
  3205. sd->flee_rate = 0;
  3206. if(sd->flee_rate != 100)
  3207. base_status->flee = base_status->flee * sd->flee_rate/100;
  3208. if(sd->def2_rate < 0)
  3209. sd->def2_rate = 0;
  3210. if(sd->def2_rate != 100)
  3211. base_status->def2 = base_status->def2 * sd->def2_rate/100;
  3212. if(sd->mdef2_rate < 0)
  3213. sd->mdef2_rate = 0;
  3214. if(sd->mdef2_rate != 100)
  3215. base_status->mdef2 = base_status->mdef2 * sd->mdef2_rate/100;
  3216. if(sd->critical_rate < 0)
  3217. sd->critical_rate = 0;
  3218. if(sd->critical_rate != 100)
  3219. base_status->cri = cap_value(base_status->cri * sd->critical_rate/100,SHRT_MIN,SHRT_MAX);
  3220. if (pc_checkskill(sd, SU_POWEROFLIFE) > 0)
  3221. base_status->cri += 200;
  3222. if(sd->flee2_rate < 0)
  3223. sd->flee2_rate = 0;
  3224. if(sd->flee2_rate != 100)
  3225. base_status->flee2 = base_status->flee2 * sd->flee2_rate/100;
  3226. if (sd->patk_rate < 0)
  3227. sd->patk_rate = 0;
  3228. if (sd->patk_rate != 100)
  3229. base_status->patk = base_status->patk * sd->patk_rate / 100;
  3230. if (sd->smatk_rate < 0)
  3231. sd->smatk_rate = 0;
  3232. if (sd->smatk_rate != 100)
  3233. base_status->smatk = base_status->smatk * sd->smatk_rate / 100;
  3234. if (sd->res_rate < 0)
  3235. sd->res_rate = 0;
  3236. if (sd->res_rate != 100)
  3237. base_status->res = base_status->res * sd->res_rate / 100;
  3238. if (sd->mres_rate < 0)
  3239. sd->mres_rate = 0;
  3240. if (sd->mres_rate != 100)
  3241. base_status->mres = base_status->mres * sd->mres_rate / 100;
  3242. if (sd->hplus_rate < 0)
  3243. sd->hplus_rate = 0;
  3244. if (sd->hplus_rate != 100)
  3245. base_status->hplus = base_status->hplus * sd->hplus_rate / 100;
  3246. if (sd->crate_rate < 0)
  3247. sd->crate_rate = 0;
  3248. if (sd->crate_rate != 100)
  3249. base_status->crate = base_status->crate * sd->crate_rate / 100;
  3250. // ----- HIT CALCULATION -----
  3251. // Absolute modifiers from passive skills
  3252. #ifndef RENEWAL
  3253. if((skill=pc_checkskill(sd,BS_WEAPONRESEARCH))>0)
  3254. base_status->hit += skill*2;
  3255. #endif
  3256. if((skill=pc_checkskill(sd,AC_VULTURE))>0) {
  3257. #ifndef RENEWAL
  3258. base_status->hit += skill;
  3259. #endif
  3260. if(sd->status.weapon == W_BOW)
  3261. base_status->rhw.range += skill;
  3262. }
  3263. if(sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE) {
  3264. if((skill=pc_checkskill(sd,GS_SINGLEACTION))>0)
  3265. base_status->hit += 2*skill;
  3266. if((skill=pc_checkskill(sd,GS_SNAKEEYE))>0) {
  3267. base_status->hit += skill;
  3268. base_status->rhw.range += skill;
  3269. }
  3270. }
  3271. if((sd->status.weapon == W_1HAXE || sd->status.weapon == W_2HAXE) && (skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
  3272. base_status->hit += skill * 3;
  3273. if((sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE) && (skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
  3274. base_status->hit += skill * 2;
  3275. if (pc_checkskill(sd, SU_POWEROFLIFE) > 0)
  3276. base_status->hit += 20;
  3277. if ((skill = pc_checkskill_imperial_guard(sd, 2)) > 0)// IG_SPEAR_SWORD_M
  3278. base_status->hit += skill * 3;
  3279. if ((skill = pc_checkskill(sd, SU_SOULATTACK)) > 0)
  3280. base_status->rhw.range += skill_get_range2(&sd->bl, SU_SOULATTACK, skill, true);
  3281. // ----- FLEE CALCULATION -----
  3282. // Absolute modifiers from passive skills
  3283. if((skill=pc_checkskill(sd,TF_MISS))>0)
  3284. base_status->flee += skill*(sd->class_&JOBL_2 && (sd->class_&MAPID_BASEMASK) == MAPID_THIEF? 4 : 3);
  3285. if((skill=pc_checkskill(sd,MO_DODGE))>0)
  3286. base_status->flee += (skill*3)>>1;
  3287. if (pc_checkskill(sd, SU_POWEROFLIFE) > 0)
  3288. base_status->flee += 20;
  3289. if ((skill = pc_checkskill(sd, SHC_SHADOW_SENSE)) > 0)
  3290. base_status->flee += skill * 10;
  3291. // ----- CRITICAL CALCULATION -----
  3292. #ifdef RENEWAL
  3293. if ((skill = pc_checkskill(sd, DC_DANCINGLESSON)) > 0)
  3294. base_status->cri += skill * 10;
  3295. if ((skill = pc_checkskill(sd, PR_MACEMASTERY)) > 0 && (sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE))
  3296. base_status->cri += skill * 10;
  3297. #endif
  3298. if ((skill = pc_checkskill(sd, SHC_SHADOW_SENSE)) > 0)
  3299. {
  3300. if (sd->status.weapon == W_DAGGER || sd->status.weapon == W_DOUBLE_DD ||
  3301. sd->status.weapon == W_DOUBLE_DS || sd->status.weapon == W_DOUBLE_DA)
  3302. base_status->cri += 100 + skill * 40;
  3303. else if (sd->status.weapon == W_KATAR)
  3304. base_status->cri += 50 + skill * 20;
  3305. }
  3306. // ----- P.Atk/S.Matk CALCULATION -----
  3307. if ((skill = pc_checkskill(sd, TR_STAGE_MANNER)) > 0 && (sd->status.weapon == W_BOW || sd->status.weapon == W_MUSICAL || sd->status.weapon == W_WHIP)) {
  3308. base_status->patk += skill * 3;
  3309. base_status->smatk += skill * 3;
  3310. }
  3311. // ----- PHYSICAL RESISTANCE CALCULATION -----
  3312. if ((skill = pc_checkskill_imperial_guard(sd, 1)) > 0)// IG_SHIELD_MASTERY
  3313. base_status->res += skill * 3;
  3314. // ----- EQUIPMENT-DEF CALCULATION -----
  3315. // Apply relative modifiers from equipment
  3316. if(sd->def_rate < 0)
  3317. sd->def_rate = 0;
  3318. if(sd->def_rate != 100) {
  3319. i = base_status->def * sd->def_rate/100;
  3320. base_status->def = cap_value(i, DEFTYPE_MIN, DEFTYPE_MAX);
  3321. }
  3322. if(pc_ismadogear(sd) && pc_checkskill(sd, NC_MAINFRAME) > 0)
  3323. base_status->def += 20 + (pc_checkskill(sd, NC_MAINFRAME) * 20);
  3324. #ifndef RENEWAL
  3325. if (!battle_config.weapon_defense_type && base_status->def > battle_config.max_def) {
  3326. base_status->def2 += battle_config.over_def_bonus*(base_status->def -battle_config.max_def);
  3327. base_status->def = (unsigned char)battle_config.max_def;
  3328. }
  3329. #endif
  3330. // ----- EQUIPMENT-MDEF CALCULATION -----
  3331. // Apply relative modifiers from equipment
  3332. if(sd->mdef_rate < 0)
  3333. sd->mdef_rate = 0;
  3334. if(sd->mdef_rate != 100) {
  3335. i = base_status->mdef * sd->mdef_rate/100;
  3336. base_status->mdef = cap_value(i, DEFTYPE_MIN, DEFTYPE_MAX);
  3337. }
  3338. #ifndef RENEWAL
  3339. if (!battle_config.magic_defense_type && base_status->mdef > battle_config.max_def) {
  3340. base_status->mdef2 += battle_config.over_def_bonus*(base_status->mdef -battle_config.max_def);
  3341. base_status->mdef = (signed char)battle_config.max_def;
  3342. }
  3343. #endif
  3344. // ----- ASPD CALCULATION -----
  3345. /// Unlike other stats, ASPD rate modifiers from skills/SCs/items/etc are first all added together, then the final modifier is applied
  3346. // Basic ASPD value
  3347. i = status_base_amotion_pc(sd,base_status);
  3348. base_status->amotion = cap_value(i,pc_maxaspd(sd),2000);
  3349. // Relative modifiers from passive skills
  3350. // Renewal modifiers are handled in status_base_amotion_pc
  3351. #ifndef RENEWAL_ASPD
  3352. if((skill=pc_checkskill(sd,SA_ADVANCEDBOOK))>0 && sd->status.weapon == W_BOOK)
  3353. base_status->aspd_rate -= 5*skill;
  3354. if ((skill = pc_checkskill(sd,SG_DEVIL)) > 0 && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd)))
  3355. base_status->aspd_rate -= 30*skill;
  3356. if((skill=pc_checkskill(sd,GS_SINGLEACTION))>0 &&
  3357. (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE))
  3358. base_status->aspd_rate -= ((skill+1)/2) * 10;
  3359. if(pc_isriding(sd))
  3360. base_status->aspd_rate += 500-100*pc_checkskill(sd,KN_CAVALIERMASTERY);
  3361. else if(pc_isridingdragon(sd))
  3362. base_status->aspd_rate += 250-50*pc_checkskill(sd,RK_DRAGONTRAINING);
  3363. #endif
  3364. base_status->adelay = 2*base_status->amotion;
  3365. // ----- DMOTION -----
  3366. i = 800-base_status->agi*4;
  3367. base_status->dmotion = cap_value(i, 400, 800);
  3368. if(battle_config.pc_damage_delay_rate != 100)
  3369. base_status->dmotion = base_status->dmotion*battle_config.pc_damage_delay_rate/100;
  3370. // ----- MISC CALCULATIONS -----
  3371. // Weight
  3372. status_calc_weight(sd, CALCWT_MAXBONUS);
  3373. status_calc_cart_weight(sd, CALCWT_MAXBONUS);
  3374. if (pc_checkskill(sd, SM_MOVINGRECOVERY) > 0 || pc_ismadogear(sd))
  3375. sd->regen.state.walk = 1;
  3376. else
  3377. sd->regen.state.walk = 0;
  3378. // Skill SP cost
  3379. if((skill=pc_checkskill(sd,HP_MANARECHARGE))>0 )
  3380. sd->dsprate -= 4*skill;
  3381. if(sc->data[SC_SERVICE4U])
  3382. sd->dsprate -= sc->data[SC_SERVICE4U]->val3;
  3383. if(sc->data[SC_SPCOST_RATE])
  3384. sd->dsprate -= sc->data[SC_SPCOST_RATE]->val1;
  3385. // Underflow protections.
  3386. if(sd->dsprate < 0)
  3387. sd->dsprate = 0;
  3388. if(sd->castrate < 0)
  3389. sd->castrate = 0;
  3390. if(sd->hprecov_rate < 0)
  3391. sd->hprecov_rate = 0;
  3392. if(sd->sprecov_rate < 0)
  3393. sd->sprecov_rate = 0;
  3394. // Anti-element and anti-race
  3395. if((skill=pc_checkskill(sd,CR_TRUST))>0)
  3396. sd->indexed_bonus.subele[ELE_HOLY] += skill*5;
  3397. if((skill=pc_checkskill(sd,BS_SKINTEMPER))>0) {
  3398. sd->indexed_bonus.subele[ELE_NEUTRAL] += skill;
  3399. sd->indexed_bonus.subele[ELE_FIRE] += skill*5;
  3400. }
  3401. if((skill=pc_checkskill(sd,SA_DRAGONOLOGY))>0) {
  3402. #ifdef RENEWAL
  3403. skill = skill * 2;
  3404. #else
  3405. skill = skill * 4;
  3406. #endif
  3407. sd->right_weapon.addrace[RC_DRAGON]+=skill;
  3408. sd->left_weapon.addrace[RC_DRAGON]+=skill;
  3409. sd->indexed_bonus.magic_addrace[RC_DRAGON]+=skill;
  3410. sd->indexed_bonus.subrace[RC_DRAGON]+=skill;
  3411. }
  3412. if ((skill = pc_checkskill(sd, AB_EUCHARISTICA)) > 0) {
  3413. sd->right_weapon.addrace[RC_DEMON] += skill;
  3414. sd->right_weapon.addele[ELE_DARK] += skill;
  3415. sd->left_weapon.addrace[RC_DEMON] += skill;
  3416. sd->left_weapon.addele[ELE_DARK] += skill;
  3417. sd->indexed_bonus.magic_addrace[RC_DEMON] += skill;
  3418. sd->indexed_bonus.magic_addele[ELE_DARK] += skill;
  3419. sd->indexed_bonus.subrace[RC_DEMON] += skill;
  3420. sd->indexed_bonus.subele[ELE_DARK] += skill;
  3421. }
  3422. if ((skill = pc_checkskill(sd, DK_TWOHANDDEF)) > 0 && (sd->status.weapon == W_2HSWORD || sd->status.weapon == W_2HSPEAR || sd->status.weapon == W_2HAXE)) {
  3423. uint8 defense_bonus[SZ_MAX][10] = {
  3424. { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL
  3425. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3426. { 3, 5, 7, 9, 10, 12, 13, 15, 16, 18 }, // SZ_BIG
  3427. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3428. };
  3429. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3430. sd->indexed_bonus.weapon_subsize[size] += defense_bonus[size][skill - 1];
  3431. }
  3432. }
  3433. if ((skill = pc_checkskill(sd, IQ_WILL_OF_FAITH)) > 0 && sd->status.weapon == W_KNUCKLE) {
  3434. uint8 race_atk[10] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
  3435. uint8 race_def[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  3436. sd->right_weapon.addrace[RC_UNDEAD] += race_atk[skill - 1];
  3437. sd->right_weapon.addrace[RC_DEMON] += race_atk[skill - 1];
  3438. sd->left_weapon.addrace[RC_UNDEAD] += race_atk[skill - 1];
  3439. sd->left_weapon.addrace[RC_DEMON] += race_atk[skill - 1];
  3440. sd->indexed_bonus.subrace[RC_UNDEAD] += race_def[skill - 1];
  3441. sd->indexed_bonus.subrace[RC_DEMON] += race_def[skill - 1];
  3442. }
  3443. 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)) {
  3444. uint8 attack_bonus[SZ_MAX][10] = {
  3445. { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL
  3446. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3447. { 3, 5, 7, 9, 10, 12, 13, 15, 16, 18 }, // SZ_BIG
  3448. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3449. };
  3450. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3451. sd->right_weapon.addsize[size] += attack_bonus[size][skill - 1];
  3452. sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1];
  3453. }
  3454. }
  3455. if ((skill = pc_checkskill(sd, CD_FIDUS_ANIMUS)) > 0) {
  3456. uint8 holy_matk[10] = { 1, 3, 4, 6, 7, 9, 10, 12, 13, 15 };
  3457. sd->indexed_bonus.magic_atk_ele[ELE_HOLY] += holy_matk[skill - 1];
  3458. }
  3459. if ((skill = pc_checkskill(sd, MT_TWOAXEDEF)) > 0 && sd->status.weapon == W_2HAXE) {
  3460. uint8 defense_bonus[SZ_MAX][10] = {
  3461. { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL
  3462. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3463. { 3, 5, 7, 9, 10, 12, 13, 15, 16, 18 }, // SZ_BIG
  3464. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3465. };
  3466. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3467. sd->indexed_bonus.weapon_subsize[size] += defense_bonus[size][skill - 1];
  3468. }
  3469. }
  3470. 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)) {
  3471. uint8 attack_bonus[SZ_MAX][10] = {
  3472. { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, // SZ_SMALL
  3473. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3474. { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }, // SZ_BIG
  3475. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3476. };
  3477. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3478. sd->right_weapon.addsize[size] += attack_bonus[size][skill - 1];
  3479. sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1];
  3480. }
  3481. }
  3482. 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)) {
  3483. uint8 attack_bonus[SZ_MAX][10] = {
  3484. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_SMALL
  3485. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_MEDIUM
  3486. { 2, 3, 5, 6, 8, 9, 11, 12, 14, 15 }, // SZ_BIG
  3487. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // SZ_ALL
  3488. };
  3489. for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
  3490. sd->indexed_bonus.magic_addsize[size] += attack_bonus[size][skill - 1];
  3491. }
  3492. }
  3493. if ((skill = pc_checkskill(sd, EM_MAGIC_BOOK_M)) > 0 && sd->status.weapon == W_BOOK) {
  3494. sd->indexed_bonus.magic_atk_ele[ELE_WATER] += skill;
  3495. sd->indexed_bonus.magic_atk_ele[ELE_EARTH] += skill;
  3496. sd->indexed_bonus.magic_atk_ele[ELE_FIRE] += skill;
  3497. sd->indexed_bonus.magic_atk_ele[ELE_WIND] += skill;
  3498. sd->indexed_bonus.magic_atk_ele[ELE_POISON] += skill;
  3499. }
  3500. if(sc->count) {
  3501. if(sc->data[SC_CONCENTRATE]) { // Update the card-bonus data
  3502. sc->data[SC_CONCENTRATE]->val3 = sd->indexed_bonus.param_bonus[1]; // Agi
  3503. sc->data[SC_CONCENTRATE]->val4 = sd->indexed_bonus.param_bonus[4]; // Dex
  3504. }
  3505. if(sc->data[SC_SIEGFRIED]) {
  3506. i = sc->data[SC_SIEGFRIED]->val2;
  3507. sd->indexed_bonus.subele[ELE_WATER] += i;
  3508. sd->indexed_bonus.subele[ELE_EARTH] += i;
  3509. sd->indexed_bonus.subele[ELE_FIRE] += i;
  3510. sd->indexed_bonus.subele[ELE_WIND] += i;
  3511. #ifndef RENEWAL
  3512. sd->indexed_bonus.subele[ELE_POISON] += i;
  3513. sd->indexed_bonus.subele[ELE_HOLY] += i;
  3514. sd->indexed_bonus.subele[ELE_DARK] += i;
  3515. sd->indexed_bonus.subele[ELE_GHOST] += i;
  3516. sd->indexed_bonus.subele[ELE_UNDEAD] += i;
  3517. #endif
  3518. }
  3519. #ifdef RENEWAL
  3520. if (sc->data[SC_BASILICA]) {
  3521. i = sc->data[SC_BASILICA]->val1 * 5;
  3522. sd->right_weapon.addele[ELE_DARK] += i;
  3523. sd->right_weapon.addele[ELE_UNDEAD] += i;
  3524. sd->left_weapon.addele[ELE_DARK] += i;
  3525. sd->left_weapon.addele[ELE_UNDEAD] += i;
  3526. sd->indexed_bonus.magic_atk_ele[ELE_HOLY] += sc->data[SC_BASILICA]->val1 * 3;
  3527. }
  3528. if (sc->data[SC_FIREWEAPON])
  3529. sd->indexed_bonus.magic_atk_ele[ELE_FIRE] += sc->data[SC_FIREWEAPON]->val1;
  3530. if (sc->data[SC_WINDWEAPON])
  3531. sd->indexed_bonus.magic_atk_ele[ELE_WIND] += sc->data[SC_WINDWEAPON]->val1;
  3532. if (sc->data[SC_WATERWEAPON])
  3533. sd->indexed_bonus.magic_atk_ele[ELE_WATER] += sc->data[SC_WATERWEAPON]->val1;
  3534. if (sc->data[SC_EARTHWEAPON])
  3535. sd->indexed_bonus.magic_atk_ele[ELE_EARTH] += sc->data[SC_EARTHWEAPON]->val1;
  3536. #endif
  3537. if(sc->data[SC_PROVIDENCE]) {
  3538. sd->indexed_bonus.subele[ELE_HOLY] += sc->data[SC_PROVIDENCE]->val2;
  3539. sd->indexed_bonus.subrace[RC_DEMON] += sc->data[SC_PROVIDENCE]->val2;
  3540. }
  3541. if (sc->data[SC_GEFFEN_MAGIC1]) {
  3542. sd->right_weapon.addrace[RC_PLAYER_HUMAN] += sc->data[SC_GEFFEN_MAGIC1]->val1;
  3543. sd->right_weapon.addrace[RC_DEMIHUMAN] += sc->data[SC_GEFFEN_MAGIC1]->val1;
  3544. sd->left_weapon.addrace[RC_PLAYER_HUMAN] += sc->data[SC_GEFFEN_MAGIC1]->val1;
  3545. sd->left_weapon.addrace[RC_DEMIHUMAN] += sc->data[SC_GEFFEN_MAGIC1]->val1;
  3546. }
  3547. if (sc->data[SC_GEFFEN_MAGIC2]) {
  3548. sd->indexed_bonus.magic_addrace[RC_PLAYER_HUMAN] += sc->data[SC_GEFFEN_MAGIC2]->val1;
  3549. sd->indexed_bonus.magic_addrace[RC_DEMIHUMAN] += sc->data[SC_GEFFEN_MAGIC2]->val1;
  3550. }
  3551. if(sc->data[SC_GEFFEN_MAGIC3]) {
  3552. sd->indexed_bonus.subrace[RC_PLAYER_HUMAN] += sc->data[SC_GEFFEN_MAGIC3]->val1;
  3553. sd->indexed_bonus.subrace[RC_DEMIHUMAN] += sc->data[SC_GEFFEN_MAGIC3]->val1;
  3554. }
  3555. if(sc->data[SC_ARMOR_ELEMENT_WATER]) { // This status change should grant card-type elemental resist.
  3556. sd->indexed_bonus.subele[ELE_WATER] += sc->data[SC_ARMOR_ELEMENT_WATER]->val1;
  3557. sd->indexed_bonus.subele[ELE_EARTH] += sc->data[SC_ARMOR_ELEMENT_WATER]->val2;
  3558. sd->indexed_bonus.subele[ELE_FIRE] += sc->data[SC_ARMOR_ELEMENT_WATER]->val3;
  3559. sd->indexed_bonus.subele[ELE_WIND] += sc->data[SC_ARMOR_ELEMENT_WATER]->val4;
  3560. }
  3561. if(sc->data[SC_ARMOR_ELEMENT_EARTH]) { // This status change should grant card-type elemental resist.
  3562. sd->indexed_bonus.subele[ELE_WATER] += sc->data[SC_ARMOR_ELEMENT_EARTH]->val1;
  3563. sd->indexed_bonus.subele[ELE_EARTH] += sc->data[SC_ARMOR_ELEMENT_EARTH]->val2;
  3564. sd->indexed_bonus.subele[ELE_FIRE] += sc->data[SC_ARMOR_ELEMENT_EARTH]->val3;
  3565. sd->indexed_bonus.subele[ELE_WIND] += sc->data[SC_ARMOR_ELEMENT_EARTH]->val4;
  3566. }
  3567. if(sc->data[SC_ARMOR_ELEMENT_FIRE]) { // This status change should grant card-type elemental resist.
  3568. sd->indexed_bonus.subele[ELE_WATER] += sc->data[SC_ARMOR_ELEMENT_FIRE]->val1;
  3569. sd->indexed_bonus.subele[ELE_EARTH] += sc->data[SC_ARMOR_ELEMENT_FIRE]->val2;
  3570. sd->indexed_bonus.subele[ELE_FIRE] += sc->data[SC_ARMOR_ELEMENT_FIRE]->val3;
  3571. sd->indexed_bonus.subele[ELE_WIND] += sc->data[SC_ARMOR_ELEMENT_FIRE]->val4;
  3572. }
  3573. if(sc->data[SC_ARMOR_ELEMENT_WIND]) { // This status change should grant card-type elemental resist.
  3574. sd->indexed_bonus.subele[ELE_WATER] += sc->data[SC_ARMOR_ELEMENT_WIND]->val1;
  3575. sd->indexed_bonus.subele[ELE_EARTH] += sc->data[SC_ARMOR_ELEMENT_WIND]->val2;
  3576. sd->indexed_bonus.subele[ELE_FIRE] += sc->data[SC_ARMOR_ELEMENT_WIND]->val3;
  3577. sd->indexed_bonus.subele[ELE_WIND] += sc->data[SC_ARMOR_ELEMENT_WIND]->val4;
  3578. }
  3579. if(sc->data[SC_ARMOR_RESIST]) { // Undead Scroll
  3580. sd->indexed_bonus.subele[ELE_WATER] += sc->data[SC_ARMOR_RESIST]->val1;
  3581. sd->indexed_bonus.subele[ELE_EARTH] += sc->data[SC_ARMOR_RESIST]->val2;
  3582. sd->indexed_bonus.subele[ELE_FIRE] += sc->data[SC_ARMOR_RESIST]->val3;
  3583. sd->indexed_bonus.subele[ELE_WIND] += sc->data[SC_ARMOR_RESIST]->val4;
  3584. }
  3585. if( sc->data[SC_FIRE_CLOAK_OPTION] ) {
  3586. i = sc->data[SC_FIRE_CLOAK_OPTION]->val2;
  3587. sd->indexed_bonus.subele[ELE_FIRE] += i;
  3588. sd->indexed_bonus.subele[ELE_WATER] -= i;
  3589. }
  3590. if( sc->data[SC_WATER_DROP_OPTION] ) {
  3591. i = sc->data[SC_WATER_DROP_OPTION]->val2;
  3592. sd->indexed_bonus.subele[ELE_WATER] += i;
  3593. sd->indexed_bonus.subele[ELE_WIND] -= i;
  3594. }
  3595. if( sc->data[SC_WIND_CURTAIN_OPTION] ) {
  3596. i = sc->data[SC_WIND_CURTAIN_OPTION]->val2;
  3597. sd->indexed_bonus.subele[ELE_WIND] += i;
  3598. sd->indexed_bonus.subele[ELE_EARTH] -= i;
  3599. }
  3600. if( sc->data[SC_STONE_SHIELD_OPTION] ) {
  3601. i = sc->data[SC_STONE_SHIELD_OPTION]->val2;
  3602. sd->indexed_bonus.subele[ELE_EARTH] += i;
  3603. sd->indexed_bonus.subele[ELE_FIRE] -= i;
  3604. }
  3605. if (sc->data[SC_MTF_MLEATKED] )
  3606. sd->indexed_bonus.subele[ELE_NEUTRAL] += sc->data[SC_MTF_MLEATKED]->val3;
  3607. if (sc->data[SC_MTF_CRIDAMAGE])
  3608. sd->bonus.crit_atk_rate += sc->data[SC_MTF_CRIDAMAGE]->val1;
  3609. if (sc->data[SC_GLASTHEIM_ATK]) {
  3610. sd->indexed_bonus.ignore_mdef_by_race[RC_UNDEAD] += sc->data[SC_GLASTHEIM_ATK]->val1;
  3611. sd->indexed_bonus.ignore_mdef_by_race[RC_DEMON] += sc->data[SC_GLASTHEIM_ATK]->val1;
  3612. }
  3613. if (sc->data[SC_LAUDARAMUS])
  3614. sd->bonus.crit_atk_rate += 5 * sc->data[SC_LAUDARAMUS]->val1;
  3615. #ifdef RENEWAL
  3616. if (sc->data[SC_FORTUNE])
  3617. sd->bonus.crit_atk_rate += 2 * sc->data[SC_FORTUNE]->val1;
  3618. #endif
  3619. if (sc->data[SC_SYMPHONYOFLOVER]) {
  3620. sd->indexed_bonus.subele[ELE_GHOST] += sc->data[SC_SYMPHONYOFLOVER]->val1 * 3;
  3621. sd->indexed_bonus.subele[ELE_HOLY] += sc->data[SC_SYMPHONYOFLOVER]->val1 * 3;
  3622. }
  3623. if (sc->data[SC_PYREXIA] && sc->data[SC_PYREXIA]->val3 == 0)
  3624. sd->bonus.crit_atk_rate += sc->data[SC_PYREXIA]->val2;
  3625. if (sc->data[SC_LUXANIMA]) {
  3626. pc_bonus2(sd, SP_ADDSIZE, SZ_ALL, sc->data[SC_LUXANIMA]->val3);
  3627. sd->bonus.crit_atk_rate += sc->data[SC_LUXANIMA]->val3;
  3628. sd->bonus.short_attack_atk_rate += sc->data[SC_LUXANIMA]->val3;
  3629. sd->bonus.long_attack_atk_rate += sc->data[SC_LUXANIMA]->val3;
  3630. }
  3631. if (sc->data[SC_STRIKING])
  3632. sd->bonus.perfect_hit += 20 + 10 * pc_checkskill(sd, SO_STRIKING);
  3633. if (sc->data[SC_VIGOR]) {
  3634. // Skill desc says increases physical damage. Supposed to affect damage from base ATK right???
  3635. // Because this is only boosting the ATK from the equipped weapon and not from base ATK. [Rytech]
  3636. sd->right_weapon.addrace[RC_DEMIHUMAN] += 50;
  3637. sd->left_weapon.addrace[RC_ANGEL] += 50;
  3638. }
  3639. if (sc->data[SC_DEADLY_DEFEASANCE])
  3640. sd->special_state.no_magic_damage = 0;
  3641. if (sc->data[SC_CLIMAX_DES_HU])
  3642. sd->indexed_bonus.magic_atk_ele[ELE_WIND] += 30;
  3643. if (sc->data[SC_CLIMAX_EARTH])
  3644. sd->indexed_bonus.subele[ELE_EARTH] -= 100;
  3645. if (sc->data[SC_CLIMAX_BLOOM])
  3646. sd->indexed_bonus.subele[ELE_FIRE] -= 100;
  3647. if (sc->data[SC_CLIMAX_CRYIMP]) {
  3648. sd->indexed_bonus.subele[ELE_WATER] += 30;
  3649. sd->indexed_bonus.magic_atk_ele[ELE_WATER] += 30;
  3650. }
  3651. if (sc->data[SC_SINCERE_FAITH])
  3652. sd->bonus.perfect_hit += sc->data[SC_SINCERE_FAITH]->val3;
  3653. if (sc->data[SC_HOLY_S]) {
  3654. sd->indexed_bonus.subele[ELE_DARK] += sc->data[SC_HOLY_S]->val2;
  3655. sd->indexed_bonus.subele[ELE_UNDEAD] += sc->data[SC_HOLY_S]->val2;
  3656. sd->indexed_bonus.magic_atk_ele[ELE_HOLY] += sc->data[SC_HOLY_S]->val2;
  3657. }
  3658. if (sc->data[SC_SUMMON_ELEMENTAL_ARDOR])
  3659. sd->indexed_bonus.magic_atk_ele[ELE_FIRE] += 10;
  3660. if (sc->data[SC_SUMMON_ELEMENTAL_DILUVIO])
  3661. sd->indexed_bonus.magic_atk_ele[ELE_WATER] += 10;
  3662. if (sc->data[SC_SUMMON_ELEMENTAL_PROCELLA])
  3663. sd->indexed_bonus.magic_atk_ele[ELE_WIND] += 10;
  3664. if (sc->data[SC_SUMMON_ELEMENTAL_TERREMOTUS])
  3665. sd->indexed_bonus.magic_atk_ele[ELE_EARTH] += 10;
  3666. if (sc->data[SC_SUMMON_ELEMENTAL_SERPENS])
  3667. sd->indexed_bonus.magic_atk_ele[ELE_POISON] += 10;
  3668. if (sc->data[SC_FLAMEARMOR_OPTION]) {
  3669. sd->indexed_bonus.subele[ELE_FIRE] += 100;
  3670. sd->indexed_bonus.subele[ELE_WATER] -= 30;
  3671. }
  3672. if (sc->data[SC_CRYSTAL_ARMOR_OPTION]) {
  3673. sd->indexed_bonus.subele[ELE_WATER] += 100;
  3674. sd->indexed_bonus.subele[ELE_WIND] -= 30;
  3675. }
  3676. if (sc->data[SC_EYES_OF_STORM_OPTION]) {
  3677. sd->indexed_bonus.subele[ELE_WIND] += 100;
  3678. sd->indexed_bonus.subele[ELE_EARTH] -= 30;
  3679. }
  3680. if (sc->data[SC_STRONG_PROTECTION_OPTION]) {
  3681. sd->indexed_bonus.subele[ELE_EARTH] += 100;
  3682. sd->indexed_bonus.subele[ELE_FIRE] -= 30;
  3683. }
  3684. if (sc->data[SC_POISON_SHIELD_OPTION]) {
  3685. sd->indexed_bonus.subele[ELE_POISON] += 100;
  3686. sd->indexed_bonus.subele[ELE_HOLY] -= 30;
  3687. }
  3688. }
  3689. status_cpy(&sd->battle_status, base_status);
  3690. // ----- CLIENT-SIDE REFRESH -----
  3691. if(!sd->bl.prev) {
  3692. // Will update on LoadEndAck
  3693. calculating = 0;
  3694. return 0;
  3695. }
  3696. if(memcmp(b_skill,sd->status.skill,sizeof(sd->status.skill)))
  3697. clif_skillinfoblock(sd);
  3698. // If the skill is learned, the status is infinite.
  3699. if (pc_checkskill(sd, SU_SPRITEMABLE) > 0 && !sd->sc.data[SC_SPRITEMABLE])
  3700. sc_start(&sd->bl, &sd->bl, SC_SPRITEMABLE, 100, 1, INFINITE_TICK);
  3701. if (pc_checkskill(sd, SU_SOULATTACK) > 0 && !sd->sc.data[SC_SOULATTACK])
  3702. sc_start(&sd->bl, &sd->bl, SC_SOULATTACK, 100, 1, INFINITE_TICK);
  3703. calculating = 0;
  3704. return 0;
  3705. }
  3706. /// Intermediate function since C++ does not have a try-finally syntax
  3707. int status_calc_pc_( struct map_session_data* sd, uint8 opt ){
  3708. // Save the old script the player was attached to
  3709. struct script_state* previous_st = sd->st;
  3710. // Store the return value of the original function
  3711. int ret = status_calc_pc_sub( sd, opt );
  3712. // If an old script is present
  3713. if( previous_st ){
  3714. // Reattach the player to it, so that the limitations of that script kick back in
  3715. script_attach_state( previous_st );
  3716. }
  3717. // Return the original return value
  3718. return ret;
  3719. }
  3720. /**
  3721. * Calculates Mercenary data
  3722. * @param md: Mercenary object
  3723. * @param opt: Whether it is first calc or not (0 on level up or status)
  3724. * @return 0
  3725. */
  3726. int status_calc_mercenary_(s_mercenary_data *md, uint8 opt)
  3727. {
  3728. struct status_data *status = &md->base_status;
  3729. s_mercenary *merc = &md->mercenary;
  3730. if (opt&SCO_FIRST) {
  3731. memcpy(status, &md->db->status, sizeof(struct status_data));
  3732. status->class_ = CLASS_NORMAL;
  3733. status->mode = static_cast<e_mode>(MD_CANMOVE|MD_CANATTACK);
  3734. status->hp = status->max_hp;
  3735. status->sp = status->max_sp;
  3736. md->battle_status.hp = merc->hp;
  3737. md->battle_status.sp = merc->sp;
  3738. if (md->master)
  3739. status->speed = status_get_speed(&md->master->bl);
  3740. }
  3741. status_calc_misc(&md->bl, status, md->db->lv);
  3742. status_cpy(&md->battle_status, status);
  3743. return 0;
  3744. }
  3745. /**
  3746. * Calculates Homunculus data
  3747. * @param hd: Homunculus object
  3748. * @param opt: Whether it is first calc or not (0 on level up or status)
  3749. * @return 1
  3750. */
  3751. int status_calc_homunculus_(struct homun_data *hd, uint8 opt)
  3752. {
  3753. struct status_data *status = &hd->base_status;
  3754. struct s_homunculus *hom = &hd->homunculus;
  3755. int skill_lv;
  3756. int amotion;
  3757. status->str = hom->str / 10;
  3758. status->agi = hom->agi / 10;
  3759. status->vit = hom->vit / 10;
  3760. status->dex = hom->dex / 10;
  3761. status->int_ = hom->int_ / 10;
  3762. status->luk = hom->luk / 10;
  3763. APPLY_HOMUN_LEVEL_STATWEIGHT();
  3764. if (opt&SCO_FIRST) {
  3765. const struct s_homunculus_db *db = hd->homunculusDB;
  3766. status->def_ele = db->element;
  3767. status->ele_lv = 1;
  3768. status->race = db->race;
  3769. status->class_ = CLASS_NORMAL;
  3770. status->size = (hom->class_ == db->evo_class) ? db->evo_size : db->base_size;
  3771. status->rhw.range = 1 + status->size;
  3772. status->mode = static_cast<e_mode>(MD_CANMOVE|MD_CANATTACK);
  3773. status->speed = DEFAULT_WALK_SPEED;
  3774. if (battle_config.hom_setting&HOMSET_COPY_SPEED && hd->master)
  3775. status->speed = status_get_speed(&hd->master->bl);
  3776. status->hp = 1;
  3777. status->sp = 1;
  3778. }
  3779. status->aspd_rate = 1000;
  3780. #ifdef RENEWAL
  3781. amotion = hd->homunculusDB->baseASPD;
  3782. amotion = amotion - amotion * (status->dex + hom->dex_value) / 1000 - (status->agi + hom->agi_value) * amotion / 250;
  3783. status->def = status->mdef = 0;
  3784. #else
  3785. skill_lv = hom->level / 10 + status->vit / 5;
  3786. status->def = cap_value(skill_lv, 0, 99);
  3787. skill_lv = hom->level / 10 + status->int_ / 5;
  3788. status->mdef = cap_value(skill_lv, 0, 99);
  3789. amotion = (1000 - 4 * status->agi - status->dex) * hd->homunculusDB->baseASPD / 1000;
  3790. #endif
  3791. status->amotion = cap_value(amotion, battle_config.max_aspd, 2000);
  3792. status->adelay = status->amotion; //It seems adelay = amotion for Homunculus.
  3793. status->max_hp = hom->max_hp;
  3794. status->max_sp = hom->max_sp;
  3795. hom_calc_skilltree(hd, 0);
  3796. if((skill_lv = hom_checkskill(hd, HAMI_SKIN)) > 0)
  3797. status->def += skill_lv * 4;
  3798. if((skill_lv = hom_checkskill(hd, HVAN_INSTRUCT)) > 0) {
  3799. status->int_ += 1 + skill_lv / 2 + skill_lv / 4 + skill_lv / 5;
  3800. status->str += 1 + skill_lv / 3 + skill_lv / 3 + skill_lv / 4;
  3801. }
  3802. if((skill_lv = hom_checkskill(hd, HAMI_SKIN)) > 0)
  3803. status->max_hp += skill_lv * 2 * status->max_hp / 100;
  3804. if((skill_lv = hom_checkskill(hd, HLIF_BRAIN)) > 0)
  3805. status->max_sp += (1 + skill_lv / 2 - skill_lv / 4 + skill_lv / 5) * status->max_sp / 100;
  3806. if (opt&SCO_FIRST) {
  3807. hd->battle_status.hp = hom->hp;
  3808. hd->battle_status.sp = hom->sp;
  3809. if(hom->class_ == 6052) // Eleanor
  3810. sc_start(&hd->bl,&hd->bl, SC_STYLE_CHANGE, 100, MH_MD_FIGHTING, INFINITE_TICK);
  3811. }
  3812. #ifndef RENEWAL
  3813. status->rhw.atk = status->dex;
  3814. status->rhw.atk2 = status->str + hom->level;
  3815. #endif
  3816. status_calc_misc(&hd->bl, status, hom->level);
  3817. status_cpy(&hd->battle_status, status);
  3818. return 1;
  3819. }
  3820. /**
  3821. * Calculates Elemental data
  3822. * @param ed: Elemental object
  3823. * @param opt: Whether it is first calc or not (0 on status change)
  3824. * @return 0
  3825. */
  3826. int status_calc_elemental_(s_elemental_data *ed, uint8 opt)
  3827. {
  3828. struct status_data *status = &ed->base_status;
  3829. s_elemental *ele = &ed->elemental;
  3830. struct map_session_data *sd = ed->master;
  3831. if( !sd )
  3832. return 0;
  3833. if (opt&SCO_FIRST) {
  3834. memcpy(status, &ed->db->status, sizeof(struct status_data));
  3835. if( !ele->mode )
  3836. status->mode = EL_MODE_PASSIVE;
  3837. else
  3838. status->mode = ele->mode;
  3839. status->class_ = CLASS_NORMAL;
  3840. status_calc_misc(&ed->bl, status, 0);
  3841. status->max_hp = ele->max_hp;
  3842. status->max_sp = ele->max_sp;
  3843. status->hp = ele->hp;
  3844. status->sp = ele->sp;
  3845. status->rhw.atk = ele->atk;
  3846. status->rhw.atk2 = ele->atk2;
  3847. status->matk_min += ele->matk;
  3848. status->def += ele->def;
  3849. status->mdef += ele->mdef;
  3850. status->flee = ele->flee;
  3851. status->hit = ele->hit;
  3852. if (ed->master)
  3853. status->speed = status_get_speed(&ed->master->bl);
  3854. memcpy(&ed->battle_status,status,sizeof(struct status_data));
  3855. } else {
  3856. status_calc_misc(&ed->bl, status, 0);
  3857. status_cpy(&ed->battle_status, status);
  3858. }
  3859. return 0;
  3860. }
  3861. /**
  3862. * Calculates NPC data
  3863. * @param nd: NPC object
  3864. * @param opt: Whether it is first calc or not (what?)
  3865. * @return 0
  3866. */
  3867. int status_calc_npc_(struct npc_data *nd, uint8 opt)
  3868. {
  3869. struct status_data *status = &nd->status;
  3870. if (!nd)
  3871. return 0;
  3872. if (opt&SCO_FIRST) {
  3873. status->hp = 1;
  3874. status->sp = 1;
  3875. status->max_hp = 1;
  3876. status->max_sp = 1;
  3877. status->def_ele = ELE_NEUTRAL;
  3878. status->ele_lv = 1;
  3879. status->race = RC_DEMIHUMAN;
  3880. status->class_ = CLASS_NORMAL;
  3881. status->size = nd->size;
  3882. status->rhw.range = 1 + status->size;
  3883. status->mode = static_cast<e_mode>(MD_CANMOVE|MD_CANATTACK);
  3884. status->speed = nd->speed;
  3885. }
  3886. status->str = nd->stat_point + nd->params.str;
  3887. status->agi = nd->stat_point + nd->params.agi;
  3888. status->vit = nd->stat_point + nd->params.vit;
  3889. status->int_= nd->stat_point + nd->params.int_;
  3890. status->dex = nd->stat_point + nd->params.dex;
  3891. status->luk = nd->stat_point + nd->params.luk;
  3892. status_calc_misc(&nd->bl, status, nd->level);
  3893. status_cpy(&nd->status, status);
  3894. return 0;
  3895. }
  3896. /**
  3897. * Calculates regeneration values
  3898. * Applies passive skill regeneration additions
  3899. * @param bl: Object to calculate regen for [PC|HOM|MER|ELEM]
  3900. * @param status: Object's status
  3901. * @param regen: Object's base regeneration data
  3902. */
  3903. void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen)
  3904. {
  3905. struct map_session_data *sd;
  3906. struct status_change *sc;
  3907. int val, skill, reg_flag;
  3908. if( !(bl->type&BL_REGEN) || !regen )
  3909. return;
  3910. sd = BL_CAST(BL_PC,bl);
  3911. sc = status_get_sc(bl);
  3912. val = (status->vit/5) + max(1, status->max_hp/200);
  3913. if( sd && sd->hprecov_rate != 100 )
  3914. val = val*sd->hprecov_rate/100;
  3915. reg_flag = bl->type == BL_PC ? 0 : 1;
  3916. regen->hp = cap_value(val, reg_flag, SHRT_MAX);
  3917. val = 1 + (status->int_/6) + (status->max_sp/100);
  3918. if( status->int_ >= 120 )
  3919. val += ((status->int_-120)>>1) + 4;
  3920. if( sd && sd->sprecov_rate != 100 )
  3921. val = val*sd->sprecov_rate/100;
  3922. regen->sp = cap_value(val, reg_flag, SHRT_MAX);
  3923. if( sd ) {
  3924. struct regen_data_sub *sregen;
  3925. if( (skill=pc_checkskill(sd,HP_MEDITATIO)) > 0 ) {
  3926. val = regen->sp*(100+3*skill)/100;
  3927. regen->sp = cap_value(val, 1, SHRT_MAX);
  3928. }
  3929. // Only players have skill/sitting skill regen for now.
  3930. sregen = regen->sregen;
  3931. val = 0;
  3932. if( (skill=pc_checkskill(sd,SM_RECOVERY)) > 0 )
  3933. val += skill*5 + skill*status->max_hp/500;
  3934. if (sc && sc->count) {
  3935. if (sc->data[SC_INCREASE_MAXHP])
  3936. val += val * sc->data[SC_INCREASE_MAXHP]->val2 / 100;
  3937. }
  3938. sregen->hp = cap_value(val, 0, SHRT_MAX);
  3939. val = 0;
  3940. if( (skill=pc_checkskill(sd,MG_SRECOVERY)) > 0 )
  3941. val += skill*3 + skill*status->max_sp/500;
  3942. if( (skill=pc_checkskill(sd,NJ_NINPOU)) > 0 )
  3943. val += skill*3 + skill*status->max_sp/500;
  3944. if( (skill=pc_checkskill(sd,WM_LESSON)) > 0 )
  3945. val += 3 + 3 * skill;
  3946. if (sc && sc->count) {
  3947. if (sc->data[SC_ANCILLA])
  3948. val += sc->data[SC_ANCILLA]->val2 / 100;
  3949. if (sc->data[SC_INCREASE_MAXSP])
  3950. val += val * sc->data[SC_INCREASE_MAXSP]->val2 / 100;
  3951. }
  3952. sregen->sp = cap_value(val, 0, SHRT_MAX);
  3953. // Skill-related recovery (only when sit)
  3954. sregen = regen->ssregen;
  3955. val = 0;
  3956. if( (skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0 )
  3957. val += skill*4 + skill*status->max_hp/500;
  3958. if( (skill=pc_checkskill(sd,TK_HPTIME)) > 0 && sd->state.rest )
  3959. val += skill*30 + skill*status->max_hp/500;
  3960. sregen->hp = cap_value(val, 0, SHRT_MAX);
  3961. val = 0;
  3962. if( (skill=pc_checkskill(sd,TK_SPTIME)) > 0 && sd->state.rest ) {
  3963. val += skill*3 + skill*status->max_sp/500;
  3964. if ((skill=pc_checkskill(sd,SL_KAINA)) > 0) // Power up Enjoyable Rest
  3965. val += (30+10*skill)*val/100;
  3966. }
  3967. if( (skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0 )
  3968. val += skill*2 + skill*status->max_sp/500;
  3969. sregen->sp = cap_value(val, 0, SHRT_MAX);
  3970. }
  3971. if( bl->type == BL_HOM ) {
  3972. struct homun_data *hd = (TBL_HOM*)bl;
  3973. if( (skill = hom_checkskill(hd,HAMI_SKIN)) > 0 ) {
  3974. val = regen->hp*(100+5*skill)/100;
  3975. regen->hp = cap_value(val, 1, SHRT_MAX);
  3976. }
  3977. if( (skill = hom_checkskill(hd,HLIF_BRAIN)) > 0 ) {
  3978. val = regen->sp*(100+3*skill)/100;
  3979. regen->sp = cap_value(val, 1, SHRT_MAX);
  3980. }
  3981. } else if( bl->type == BL_MER ) {
  3982. val = (status->max_hp * status->vit / 10000 + 1) * 6;
  3983. regen->hp = cap_value(val, 1, SHRT_MAX);
  3984. val = (status->max_sp * (status->int_ + 10) / 750) + 1;
  3985. regen->sp = cap_value(val, 1, SHRT_MAX);
  3986. } else if( bl->type == BL_ELEM ) {
  3987. val = (status->max_hp * status->vit / 10000 + 1) * 6;
  3988. regen->hp = cap_value(val, 1, SHRT_MAX);
  3989. val = (status->max_sp * (status->int_ + 10) / 750) + 1;
  3990. regen->sp = cap_value(val, 1, SHRT_MAX);
  3991. }
  3992. }
  3993. /**
  3994. * Calculates SC (Status Changes) regeneration values
  3995. * @param bl: Object to calculate regen for [PC|HOM|MER|ELEM]
  3996. * @param regen: Object's base regeneration data
  3997. * @param sc: Object's status change data
  3998. */
  3999. void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, struct status_change *sc)
  4000. {
  4001. if (!(bl->type&BL_REGEN) || !regen)
  4002. return;
  4003. regen->flag = RGN_HP|RGN_SP;
  4004. if(regen->sregen) {
  4005. if (regen->sregen->hp)
  4006. regen->flag |= RGN_SHP;
  4007. if (regen->sregen->sp)
  4008. regen->flag |= RGN_SSP;
  4009. regen->sregen->rate.hp = regen->sregen->rate.sp = 100;
  4010. }
  4011. if (regen->ssregen) {
  4012. if (regen->ssregen->hp)
  4013. regen->flag |= RGN_SHP;
  4014. if (regen->ssregen->sp)
  4015. regen->flag |= RGN_SSP;
  4016. regen->ssregen->rate.hp = regen->ssregen->rate.sp = 100;
  4017. }
  4018. regen->rate.hp = regen->rate.sp = 100;
  4019. if (!sc || !sc->count)
  4020. return;
  4021. // No HP or SP regen
  4022. if ((sc->data[SC_POISON] && !sc->data[SC_SLOWPOISON])
  4023. || (sc->data[SC_DPOISON] && !sc->data[SC_SLOWPOISON])
  4024. || sc->data[SC_BERSERK]
  4025. || sc->data[SC_TRICKDEAD]
  4026. || sc->data[SC_BLEEDING]
  4027. || (sc->data[SC_MAGICMUSHROOM] && sc->data[SC_MAGICMUSHROOM]->val3 == 1)
  4028. || sc->data[SC_SATURDAYNIGHTFEVER]
  4029. || sc->data[SC_REBOUND])
  4030. regen->flag = RGN_NONE;
  4031. // No natural SP regen
  4032. if (sc->data[SC_DANCING] ||
  4033. #ifdef RENEWAL
  4034. sc->data[SC_MAXIMIZEPOWER] ||
  4035. #endif
  4036. #ifndef RENEWAL
  4037. (bl->type == BL_PC && (((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK &&
  4038. (sc->data[SC_EXTREMITYFIST] || sc->data[SC_EXPLOSIONSPIRITS]) && (!sc->data[SC_SPIRIT] || sc->data[SC_SPIRIT]->val2 != SL_MONK)) ||
  4039. #else
  4040. (bl->type == BL_PC && (((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK &&
  4041. sc->data[SC_EXTREMITYFIST] && (!sc->data[SC_SPIRIT] || sc->data[SC_SPIRIT]->val2 != SL_MONK)) ||
  4042. #endif
  4043. (sc->data[SC_OBLIVIONCURSE] && sc->data[SC_OBLIVIONCURSE]->val3 == 1))
  4044. regen->flag &= ~RGN_SP;
  4045. if (sc->data[SC_TENSIONRELAX]) {
  4046. if (sc->data[SC_WEIGHT50] || sc->data[SC_WEIGHT90])
  4047. regen->state.overweight = 0; // 1x HP regen
  4048. else {
  4049. regen->rate.hp += 200;
  4050. if (regen->sregen)
  4051. regen->sregen->rate.hp += 200;
  4052. }
  4053. }
  4054. if (sc->data[SC_MAGNIFICAT])
  4055. regen->rate.sp += 100;
  4056. if (sc->data[SC_REGENERATION]) {
  4057. const struct status_change_entry *sce = sc->data[SC_REGENERATION];
  4058. if (!sce->val4) {
  4059. regen->rate.hp += (sce->val2*100);
  4060. regen->rate.sp += (sce->val3*100);
  4061. } else
  4062. regen->flag &= ~sce->val4; // Remove regen as specified by val4
  4063. }
  4064. if(sc->data[SC_GT_REVITALIZE]) {
  4065. regen->hp += cap_value(regen->hp * sc->data[SC_GT_REVITALIZE]->val3/100, 1, SHRT_MAX);
  4066. regen->state.walk = 1;
  4067. }
  4068. if (sc->data[SC_EXTRACT_WHITE_POTION_Z])
  4069. regen->hp += cap_value(regen->hp * sc->data[SC_EXTRACT_WHITE_POTION_Z]->val1 / 100, 1, SHRT_MAX);
  4070. if (sc->data[SC_VITATA_500])
  4071. regen->sp += cap_value(regen->sp * sc->data[SC_VITATA_500]->val1 / 100, 1, SHRT_MAX);
  4072. if (bl->type == BL_ELEM) { // Recovery bonus only applies to the Elementals.
  4073. int ele_class = status_get_class(bl);
  4074. switch (ele_class) {
  4075. case ELEMENTALID_AGNI_S:
  4076. case ELEMENTALID_AGNI_M:
  4077. case ELEMENTALID_AGNI_L:
  4078. case ELEMENTALID_ARDOR:
  4079. if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 1)
  4080. regen->rate.hp += 100;
  4081. break;
  4082. case ELEMENTALID_AQUA_S:
  4083. case ELEMENTALID_AQUA_M:
  4084. case ELEMENTALID_AQUA_L:
  4085. case ELEMENTALID_DILUVIO:
  4086. if (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 1)
  4087. regen->rate.hp += 100;
  4088. break;
  4089. case ELEMENTALID_VENTUS_S:
  4090. case ELEMENTALID_VENTUS_M:
  4091. case ELEMENTALID_VENTUS_L:
  4092. case ELEMENTALID_PROCELLA:
  4093. if (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 1)
  4094. regen->rate.hp += 100;
  4095. break;
  4096. case ELEMENTALID_TERA_S:
  4097. case ELEMENTALID_TERA_M:
  4098. case ELEMENTALID_TERA_L:
  4099. case ELEMENTALID_TERREMOTUS:
  4100. case ELEMENTALID_SERPENS:
  4101. if (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 1)
  4102. regen->rate.hp += 100;
  4103. break;
  4104. }
  4105. }
  4106. if (sc->data[SC_CATNIPPOWDER]) {
  4107. regen->rate.hp *= 2;
  4108. regen->rate.sp *= 2;
  4109. }
  4110. if (sc->data[SC_SHRIMPBLESSING])
  4111. regen->rate.sp += 50;
  4112. #ifdef RENEWAL
  4113. if (sc->data[SC_NIBELUNGEN]) {
  4114. if (sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_HPREGEN)
  4115. regen->rate.hp += 100;
  4116. else if (sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_SPREGEN)
  4117. regen->rate.sp += 100;
  4118. }
  4119. #endif
  4120. if (sc->data[SC_SIRCLEOFNATURE])
  4121. regen->rate.hp += sc->data[SC_SIRCLEOFNATURE]->val2;
  4122. if (sc->data[SC_SONGOFMANA])
  4123. regen->rate.sp += sc->data[SC_SONGOFMANA]->val3;
  4124. }
  4125. /**
  4126. * Applies a state to a unit - See [StatusChangeStateTable]
  4127. * @param bl: Object to change state on [PC|MOB|HOM|MER|ELEM]
  4128. * @param sc: Object's status change data
  4129. * @param flag: Which state to apply to bl
  4130. * @param start: (1) start state, (0) remove state
  4131. */
  4132. void status_calc_state( struct block_list *bl, struct status_change *sc, std::bitset<SCS_MAX> flag, bool start )
  4133. {
  4134. /// No sc at all, we can zero without any extra weight over our conciousness
  4135. if( !sc->count ) {
  4136. sc->cant = {};
  4137. return;
  4138. }
  4139. // Can't move
  4140. if( flag[SCS_NOMOVE] ) {
  4141. if( !flag[SCS_NOMOVECOND] )
  4142. sc->cant.move += (start ? 1 : ((sc->cant.move) ? -1 : 0));
  4143. else if(
  4144. (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) // cannot move while gospel is in effect
  4145. #ifndef RENEWAL
  4146. || (sc->data[SC_BASILICA] && sc->data[SC_BASILICA]->val4 == bl->id) // Basilica caster cannot move
  4147. || (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF)
  4148. #endif
  4149. || (sc->data[SC_CAMOUFLAGE] && sc->data[SC_CAMOUFLAGE]->val1 < 3)
  4150. || (sc->data[SC_MAGNETICFIELD] && sc->data[SC_MAGNETICFIELD]->val2 != bl->id)
  4151. || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val2 > 0)
  4152. || (sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1)
  4153. || (sc->data[SC_HIDING] && (bl->type != BL_PC || (pc_checkskill(BL_CAST(BL_PC,bl),RG_TUNNELDRIVE) <= 0)))
  4154. || (sc->data[SC_DANCING] && sc->data[SC_DANCING]->val4 && (
  4155. #ifndef RENEWAL
  4156. !sc->data[SC_LONGING] ||
  4157. #endif
  4158. (sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT ||
  4159. (sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE
  4160. ))
  4161. || (sc->data[SC_CRYSTALIZE] && bl->type != BL_MOB)
  4162. )
  4163. sc->cant.move += (start ? 1 : ((sc->cant.move) ? -1 : 0));
  4164. }
  4165. // Can't use skills
  4166. if( flag[SCS_NOCAST] ) {
  4167. if( !flag[SCS_NOCASTCOND] )
  4168. sc->cant.cast += (start ? 1 : ((sc->cant.cast) ? -1 : 0));
  4169. else if (sc->data[SC_OBLIVIONCURSE] && sc->data[SC_OBLIVIONCURSE]->val3 == 1)
  4170. sc->cant.cast += (start ? 1 : ((sc->cant.cast) ? -1 : 0));
  4171. }
  4172. // Can't chat
  4173. if( flag[SCS_NOCHAT] ) {
  4174. if( !flag[SCS_NOCHATCOND] )
  4175. sc->cant.chat += (start ? 1 : ((sc->cant.chat) ? -1 : 0));
  4176. else if(sc->data[SC_NOCHAT] && sc->data[SC_NOCHAT]->val1&MANNER_NOCHAT)
  4177. sc->cant.chat += (start ? 1 : ((sc->cant.chat) ? -1 : 0));
  4178. }
  4179. // Can't attack
  4180. if( flag[SCS_NOATTACK] ) {
  4181. if( !flag[SCS_NOATTACKCOND] )
  4182. sc->cant.attack += (start ? 1 : ((sc->cant.attack) ? -1 : 0));
  4183. /*else if( )
  4184. sc->cant.attack += ( start ? 1 : ((sc->cant.attack)? -1:0) );*/
  4185. }
  4186. // Can't warp
  4187. if (flag[SCS_NOWARP]) {
  4188. if (!flag[SCS_NOWARPCOND])
  4189. sc->cant.warp += (start ? 1 : ((sc->cant.warp) ? -1 : 0));
  4190. /*else if (sc->data[])
  4191. sc->cant.warp += ( start ? 1 : ((sc->cant.warp)? -1:0) );*/
  4192. }
  4193. // Player-only states
  4194. if( bl->type == BL_PC ) {
  4195. // Can't pick-up items
  4196. if( flag[SCS_NOPICKITEM] ) {
  4197. if( !flag[SCS_NOPICKITEMCOND] )
  4198. sc->cant.pickup += (start ? 1 : ((sc->cant.pickup) ? -1 : 0));
  4199. else if( (sc->data[SC_NOCHAT] && sc->data[SC_NOCHAT]->val1&MANNER_NOITEM) )
  4200. sc->cant.pickup += (start ? 1 : ((sc->cant.pickup) ? -1 : 0));
  4201. }
  4202. // Can't drop items
  4203. if( flag[SCS_NODROPITEM] ) {
  4204. if( !flag[SCS_NODROPITEMCOND] )
  4205. sc->cant.drop += (start ? 1 : ((sc->cant.drop) ? -1 : 0));
  4206. else if( (sc->data[SC_NOCHAT] && sc->data[SC_NOCHAT]->val1&MANNER_NOITEM) )
  4207. sc->cant.drop += (start ? 1 : ((sc->cant.drop) ? -1 : 0));
  4208. }
  4209. // Can't equip item
  4210. if( flag[SCS_NOEQUIPITEM] ) {
  4211. if( !flag[SCS_NOEQUIPITEMCOND] )
  4212. sc->cant.equip += (start ? 1 : ((sc->cant.equip) ? -1 : 0));
  4213. /*else if( )
  4214. sc->cant.equip += ( start ? 1 : ((sc->cant.equip)? -1:0) );*/
  4215. }
  4216. // Can't unequip item
  4217. if( flag[SCS_NOUNEQUIPITEM]) {
  4218. if( !flag[SCS_NOUNEQUIPITEMCOND] )
  4219. sc->cant.unequip += (start ? 1 : ((sc->cant.unequip) ? -1 : 0));
  4220. /*else if( )
  4221. sc->cant.unequip += ( start ? 1 : ((sc->cant.unequip)? -1:0) );*/
  4222. }
  4223. // Can't consume item
  4224. if( flag[SCS_NOCONSUMEITEM]) {
  4225. if( !flag[SCS_NOCONSUMEITEMCOND] )
  4226. sc->cant.consume += (start ? 1 : ((sc->cant.consume) ? -1 : 0));
  4227. else if( (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF) ||
  4228. (sc->data[SC_NOCHAT] && sc->data[SC_NOCHAT]->val1&MANNER_NOITEM) )
  4229. sc->cant.consume += (start ? 1 : ((sc->cant.consume) ? -1 : 0));
  4230. }
  4231. // Can't lose exp
  4232. if (flag[SCS_NODEATHPENALTY]) {
  4233. if (!flag[SCS_NODEATHPENALTYCOND])
  4234. sc->cant.deathpenalty += (start ? 1 : ((sc->cant.deathpenalty) ? -1 : 0));
  4235. /*else if (sc->data[])
  4236. sc->cant.deathpenalty += ( start ? 1 : ((sc->cant.deathpenalty)? -1:0) );*/
  4237. }
  4238. // Can't sit/stand/talk to NPC
  4239. if (flag[SCS_NOINTERACT]) {
  4240. if (!flag[SCS_NOINTERACTCOND])
  4241. sc->cant.interact += (start ? 1 : ((sc->cant.interact) ? -1 : 0));
  4242. /*else if (sc->data[])
  4243. sc->cant.interact += ( start ? 1 : ((sc->cant.interact)? -1:0) );*/
  4244. }
  4245. }
  4246. return;
  4247. }
  4248. /**
  4249. * Recalculates parts of an objects status according to specified flags
  4250. * See [set_sc] [add_sc]
  4251. * @param bl: Object whose status has changed [PC|MOB|HOM|MER|ELEM]
  4252. * @param flag: Which status has changed on bl
  4253. */
  4254. void status_calc_bl_main(struct block_list *bl, std::bitset<SCB_MAX> flag)
  4255. {
  4256. const struct status_data *b_status = status_get_base_status(bl); // Base Status
  4257. struct status_data *status = status_get_status_data(bl); // Battle Status
  4258. struct status_change *sc = status_get_sc(bl);
  4259. TBL_PC *sd = BL_CAST(BL_PC,bl);
  4260. int temp;
  4261. if (!b_status || !status)
  4262. return;
  4263. /** [Playtester]
  4264. * This needs to be done even if there is currently no status change active, because
  4265. * we need to update the speed on the client when the last status change ends.
  4266. **/
  4267. if(flag[SCB_SPEED]) {
  4268. struct unit_data *ud = unit_bl2ud(bl);
  4269. /** [Skotlex]
  4270. * Re-walk to adjust speed (we do not check if walktimer != INVALID_TIMER
  4271. * because if you step on something while walking, the moment this
  4272. * piece of code triggers the walk-timer is set on INVALID_TIMER)
  4273. **/
  4274. if (ud)
  4275. ud->state.change_walk_target = ud->state.speed_changed = 1;
  4276. }
  4277. if(flag[SCB_STR]) {
  4278. status->str = status_calc_str(bl, sc, b_status->str);
  4279. flag.set(SCB_BATK);
  4280. if( bl->type&BL_HOM )
  4281. flag.set(SCB_WATK);
  4282. }
  4283. if(flag[SCB_AGI]) {
  4284. status->agi = status_calc_agi(bl, sc, b_status->agi);
  4285. flag.set(SCB_FLEE);
  4286. #ifdef RENEWAL
  4287. flag.set(SCB_DEF2);
  4288. #endif
  4289. if( bl->type&(BL_PC|BL_HOM) ) {
  4290. flag.set(SCB_ASPD);
  4291. flag.set(SCB_DSPD);
  4292. }
  4293. }
  4294. if(flag[SCB_VIT]) {
  4295. status->vit = status_calc_vit(bl, sc, b_status->vit);
  4296. flag.set(SCB_DEF2);
  4297. flag.set(SCB_MDEF2);
  4298. if( bl->type&(BL_PC|BL_HOM|BL_MER|BL_ELEM) )
  4299. flag.set(SCB_MAXHP);
  4300. if( bl->type&BL_HOM )
  4301. flag.set(SCB_DEF);
  4302. }
  4303. if(flag[SCB_INT]) {
  4304. status->int_ = status_calc_int(bl, sc, b_status->int_);
  4305. flag.set(SCB_MATK);
  4306. flag.set(SCB_MDEF2);
  4307. if( bl->type&(BL_PC|BL_HOM|BL_MER|BL_ELEM) )
  4308. flag.set(SCB_MAXSP);
  4309. if( bl->type&BL_HOM )
  4310. flag.set(SCB_MDEF);
  4311. }
  4312. if(flag[SCB_DEX]) {
  4313. status->dex = status_calc_dex(bl, sc, b_status->dex);
  4314. flag.set(SCB_BATK);
  4315. flag.set(SCB_HIT);
  4316. #ifdef RENEWAL
  4317. flag.set(SCB_MATK);
  4318. flag.set(SCB_MDEF2);
  4319. #endif
  4320. if( bl->type&(BL_PC|BL_HOM) )
  4321. flag.set(SCB_ASPD);
  4322. if( bl->type&BL_HOM )
  4323. flag.set(SCB_WATK);
  4324. }
  4325. if(flag[SCB_LUK]) {
  4326. status->luk = status_calc_luk(bl, sc, b_status->luk);
  4327. flag.set(SCB_BATK);
  4328. flag.set(SCB_CRI);
  4329. flag.set(SCB_FLEE2);
  4330. #ifdef RENEWAL
  4331. flag.set(SCB_MATK);
  4332. flag.set(SCB_HIT);
  4333. flag.set(SCB_FLEE);
  4334. #endif
  4335. }
  4336. #ifdef RENEWAL
  4337. if (flag[SCB_POW]) {
  4338. status->pow = status_calc_pow(bl, sc, b_status->pow);
  4339. flag.set(SCB_BATK);
  4340. flag.set(SCB_PATK);
  4341. }
  4342. if (flag[SCB_STA]) {
  4343. status->sta = status_calc_sta(bl, sc, b_status->sta);
  4344. flag.set(SCB_RES);
  4345. }
  4346. if (flag[SCB_WIS]) {
  4347. status->wis = status_calc_wis(bl, sc, b_status->wis);
  4348. flag.set(SCB_MRES);
  4349. }
  4350. if (flag[SCB_SPL]) {
  4351. status->spl = status_calc_spl(bl, sc, b_status->spl);
  4352. flag.set(SCB_MATK);
  4353. flag.set(SCB_SMATK);
  4354. }
  4355. if (flag[SCB_CON]) {
  4356. status->con = status_calc_con(bl, sc, b_status->con);
  4357. flag.set(SCB_HIT);
  4358. flag.set(SCB_FLEE);
  4359. flag.set(SCB_PATK);
  4360. flag.set(SCB_SMATK);
  4361. }
  4362. if (flag[SCB_CRT]) {
  4363. status->crt = status_calc_crt(bl, sc, b_status->crt);
  4364. flag.set(SCB_HPLUS);
  4365. flag.set(SCB_CRATE);
  4366. }
  4367. #endif
  4368. if(flag[SCB_BATK] && b_status->batk) {
  4369. int lv = status_get_lv(bl);
  4370. status->batk = status_base_atk(bl, status, lv);
  4371. temp = b_status->batk - status_base_atk(bl, b_status, lv);
  4372. if (temp) {
  4373. temp += status->batk;
  4374. status->batk = cap_value(temp, 0, USHRT_MAX);
  4375. }
  4376. status->batk = status_calc_batk(bl, sc, status->batk);
  4377. }
  4378. if(flag[SCB_WATK]) {
  4379. #ifndef RENEWAL
  4380. status->rhw.atk = status_calc_watk(bl, sc, b_status->rhw.atk);
  4381. if (!sd) // Should not affect weapon refine bonus
  4382. status->rhw.atk2 = status_calc_watk(bl, sc, b_status->rhw.atk2);
  4383. if (sd && sd->bonus.weapon_atk_rate)
  4384. status->rhw.atk += status->rhw.atk * sd->bonus.weapon_atk_rate / 100;
  4385. if(b_status->lhw.atk) {
  4386. if (sd) {
  4387. sd->state.lr_flag = 1;
  4388. status->lhw.atk = status_calc_watk(bl, sc, b_status->lhw.atk);
  4389. sd->state.lr_flag = 0;
  4390. } else {
  4391. status->lhw.atk = status_calc_watk(bl, sc, b_status->lhw.atk);
  4392. status->lhw.atk2= status_calc_watk(bl, sc, b_status->lhw.atk2);
  4393. }
  4394. }
  4395. #else
  4396. if(!b_status->watk) { // We only have left-hand weapon
  4397. status->watk = 0;
  4398. status->watk2 = status_calc_watk(bl, sc, b_status->watk2);
  4399. }
  4400. else status->watk = status_calc_watk(bl, sc, b_status->watk);
  4401. #endif
  4402. }
  4403. if(flag[SCB_HIT]) {
  4404. if (status->dex == b_status->dex
  4405. #ifdef RENEWAL
  4406. && status->luk == b_status->luk && status->con == b_status->con
  4407. #endif
  4408. )
  4409. status->hit = status_calc_hit(bl, sc, b_status->hit);
  4410. else
  4411. status->hit = status_calc_hit(bl, sc, b_status->hit + (status->dex - b_status->dex)
  4412. #ifdef RENEWAL
  4413. + (status->luk/3 - b_status->luk/3) + 2 * (status->con - b_status->con)
  4414. #endif
  4415. );
  4416. }
  4417. if(flag[SCB_FLEE]) {
  4418. if (status->agi == b_status->agi
  4419. #ifdef RENEWAL
  4420. && status->luk == b_status->luk && status->con == b_status->con
  4421. #endif
  4422. )
  4423. status->flee = status_calc_flee(bl, sc, b_status->flee);
  4424. else
  4425. status->flee = status_calc_flee(bl, sc, b_status->flee +(status->agi - b_status->agi)
  4426. #ifdef RENEWAL
  4427. + (status->luk/5 - b_status->luk/5) + 2 * (status->con - b_status->con)
  4428. #endif
  4429. );
  4430. }
  4431. if(flag[SCB_DEF]) {
  4432. status->def = status_calc_def(bl, sc, b_status->def);
  4433. if( bl->type&BL_HOM )
  4434. status->def += (status->vit/5 - b_status->vit/5);
  4435. }
  4436. if(flag[SCB_DEF2]) {
  4437. if (status->vit == b_status->vit
  4438. #ifdef RENEWAL
  4439. && status->agi == b_status->agi
  4440. #endif
  4441. )
  4442. status->def2 = status_calc_def2(bl, sc, b_status->def2);
  4443. else
  4444. status->def2 = status_calc_def2(bl, sc, b_status->def2
  4445. #ifdef RENEWAL
  4446. + (int)( ((float)status->vit/2 - (float)b_status->vit/2) + ((float)status->agi/5 - (float)b_status->agi/5) )
  4447. #else
  4448. + (status->vit - b_status->vit)
  4449. #endif
  4450. );
  4451. }
  4452. if(flag[SCB_MDEF]) {
  4453. status->mdef = status_calc_mdef(bl, sc, b_status->mdef);
  4454. if( bl->type&BL_HOM )
  4455. status->mdef += (status->int_/5 - b_status->int_/5);
  4456. }
  4457. if(flag[SCB_MDEF2]) {
  4458. if (status->int_ == b_status->int_ && status->vit == b_status->vit
  4459. #ifdef RENEWAL
  4460. && status->dex == b_status->dex
  4461. #endif
  4462. )
  4463. status->mdef2 = status_calc_mdef2(bl, sc, b_status->mdef2);
  4464. else
  4465. status->mdef2 = status_calc_mdef2(bl, sc, b_status->mdef2 +(status->int_ - b_status->int_)
  4466. #ifdef RENEWAL
  4467. + (int)( ((float)status->dex/5 - (float)b_status->dex/5) + ((float)status->vit/5 - (float)b_status->vit/5) )
  4468. #else
  4469. + ((status->vit - b_status->vit)>>1)
  4470. #endif
  4471. );
  4472. }
  4473. if(flag[SCB_SPEED]) {
  4474. status->speed = status_calc_speed(bl, sc, b_status->speed);
  4475. if( bl->type&BL_PC && !(sd && sd->state.permanent_speed) && status->speed < battle_config.max_walk_speed )
  4476. status->speed = battle_config.max_walk_speed;
  4477. if( bl->type&BL_PET && ((TBL_PET*)bl)->master)
  4478. status->speed = status_get_speed(&((TBL_PET*)bl)->master->bl);
  4479. if( bl->type&BL_HOM && battle_config.hom_setting&HOMSET_COPY_SPEED && ((TBL_HOM*)bl)->master)
  4480. status->speed = status_get_speed(&((TBL_HOM*)bl)->master->bl);
  4481. if( bl->type&BL_MER && ((TBL_MER*)bl)->master)
  4482. status->speed = status_get_speed(&((TBL_MER*)bl)->master->bl);
  4483. if( bl->type&BL_ELEM && ((TBL_ELEM*)bl)->master)
  4484. status->speed = status_get_speed(&((TBL_ELEM*)bl)->master->bl);
  4485. }
  4486. if(flag[SCB_CRI] && b_status->cri) {
  4487. if (status->luk == b_status->luk)
  4488. status->cri = status_calc_critical(bl, sc, b_status->cri);
  4489. else
  4490. status->cri = status_calc_critical(bl, sc, b_status->cri + 3*(status->luk - b_status->luk));
  4491. /// After status_calc_critical so the bonus is applied despite if you have or not a sc bugreport:5240
  4492. if (sd) {
  4493. if (sd->status.weapon == W_KATAR)
  4494. status->cri <<= 1;
  4495. }
  4496. }
  4497. if(flag[SCB_FLEE2] && b_status->flee2) {
  4498. if (status->luk == b_status->luk)
  4499. status->flee2 = status_calc_flee2(bl, sc, b_status->flee2);
  4500. else
  4501. status->flee2 = status_calc_flee2(bl, sc, b_status->flee2 +(status->luk - b_status->luk));
  4502. }
  4503. if(flag[SCB_ATK_ELE]) {
  4504. status->rhw.ele = status_calc_attack_element(bl, sc, b_status->rhw.ele);
  4505. if (sd) sd->state.lr_flag = 1;
  4506. status->lhw.ele = status_calc_attack_element(bl, sc, b_status->lhw.ele);
  4507. if (sd) sd->state.lr_flag = 0;
  4508. }
  4509. if(flag[SCB_DEF_ELE]) {
  4510. status->def_ele = status_calc_element(bl, sc, b_status->def_ele);
  4511. status->ele_lv = status_calc_element_lv(bl, sc, b_status->ele_lv);
  4512. }
  4513. if(flag[SCB_MODE]) {
  4514. status->mode = status_calc_mode(bl, sc, b_status->mode);
  4515. if (status_has_mode(status, MD_STATUSIMMUNE|MD_SKILLIMMUNE))
  4516. status->class_ = CLASS_BATTLEFIELD;
  4517. else if (status_has_mode(status, MD_STATUSIMMUNE|MD_KNOCKBACKIMMUNE|MD_DETECTOR))
  4518. status->class_ = CLASS_BOSS;
  4519. else if (status_has_mode(status, MD_STATUSIMMUNE))
  4520. status->class_ = CLASS_GUARDIAN;
  4521. else
  4522. status->class_ = CLASS_NORMAL;
  4523. // Since mode changed, reset their state.
  4524. if (!status_has_mode(status,MD_CANATTACK))
  4525. unit_stop_attack(bl);
  4526. if (!status_has_mode(status,MD_CANMOVE))
  4527. unit_stop_walking(bl,1);
  4528. }
  4529. /**
  4530. * No status changes alter these yet.
  4531. * if(flag[SCB_SIZE])
  4532. * if(flag[SCB_RACE])
  4533. * if(flag[SCB_RANGE])
  4534. **/
  4535. if(flag[SCB_MAXHP]) {
  4536. if( bl->type&BL_PC ) {
  4537. status->max_hp = status_calc_maxhpsp_pc(sd,status->vit,true);
  4538. if(battle_config.hp_rate != 100)
  4539. status->max_hp = (unsigned int)(battle_config.hp_rate * (status->max_hp/100.));
  4540. if (sd->status.base_level < 100)
  4541. status->max_hp = umin(status->max_hp,(unsigned int)battle_config.max_hp_lv99);
  4542. else if (sd->status.base_level < 151)
  4543. status->max_hp = umin(status->max_hp,(unsigned int)battle_config.max_hp_lv150);
  4544. else
  4545. status->max_hp = umin(status->max_hp,(unsigned int)battle_config.max_hp);
  4546. }
  4547. else
  4548. status->max_hp = status_calc_maxhp(bl, b_status->max_hp);
  4549. if( status->hp > status->max_hp ) { // !FIXME: Should perhaps a status_zap should be issued?
  4550. status->hp = status->max_hp;
  4551. if( sd ) clif_updatestatus(sd,SP_HP);
  4552. }
  4553. }
  4554. if(flag[SCB_MAXSP]) {
  4555. if( bl->type&BL_PC ) {
  4556. status->max_sp = status_calc_maxhpsp_pc(sd,status->int_,false);
  4557. if(battle_config.sp_rate != 100)
  4558. status->max_sp = (unsigned int)(battle_config.sp_rate * (status->max_sp/100.));
  4559. status->max_sp = umin(status->max_sp,(unsigned int)battle_config.max_sp);
  4560. }
  4561. else
  4562. status->max_sp = status_calc_maxsp(bl, b_status->max_sp);
  4563. if( status->sp > status->max_sp ) {
  4564. status->sp = status->max_sp;
  4565. if( sd ) clif_updatestatus(sd,SP_SP);
  4566. }
  4567. }
  4568. if(flag[SCB_MATK]) {
  4569. #ifndef RENEWAL
  4570. status->matk_min = status_base_matk_min(status) + (sd?sd->bonus.ematk:0);
  4571. status->matk_max = status_base_matk_max(status) + (sd?sd->bonus.ematk:0);
  4572. #else
  4573. /**
  4574. * RE MATK Formula (from irowiki:http:// irowiki.org/wiki/MATK)
  4575. * MATK = (sMATK + wMATK + eMATK) * Multiplicative Modifiers
  4576. **/
  4577. int lv = status_get_lv(bl);
  4578. status->matk_min = status_base_matk_min(bl, status, lv);
  4579. status->matk_max = status_base_matk_max(bl, status, lv);
  4580. switch( bl->type ) {
  4581. case BL_PC: {
  4582. int wMatk = 0;
  4583. int variance = 0;
  4584. // Any +MATK you get from skills and cards, including cards in weapon, is added here.
  4585. if (sd) {
  4586. uint16 skill_lv;
  4587. if (sd->bonus.ematk > 0)
  4588. status->matk_min += sd->bonus.ematk;
  4589. if (pc_checkskill(sd, SU_POWEROFLAND) > 0 && pc_checkskill_summoner(sd, SUMMONER_POWER_LAND) >= 20)
  4590. status->matk_min += status->matk_min * 20 / 100;
  4591. if ((skill_lv = pc_checkskill(sd, NV_TRANSCENDENCE)) > 0)
  4592. status->matk_min += 15 * skill_lv + (skill_lv > 4 ? 25 : 0);
  4593. }
  4594. status->matk_min = status_calc_ematk(bl, sc, status->matk_min);
  4595. status->matk_max = status->matk_min;
  4596. // This is the only portion in MATK that varies depending on the weapon level and refinement rate.
  4597. if (b_status->lhw.matk) {
  4598. if (sd) {
  4599. //sd->state.lr_flag = 1; //?? why was that set here
  4600. status->lhw.matk = b_status->lhw.matk;
  4601. sd->state.lr_flag = 0;
  4602. } else {
  4603. status->lhw.matk = b_status->lhw.matk;
  4604. }
  4605. }
  4606. if (b_status->rhw.matk) {
  4607. status->rhw.matk = b_status->rhw.matk;
  4608. }
  4609. if (status->rhw.matk) {
  4610. wMatk += status->rhw.matk;
  4611. variance += wMatk * status->rhw.wlv / 10;
  4612. }
  4613. if (status->lhw.matk) {
  4614. wMatk += status->lhw.matk;
  4615. variance += status->lhw.matk * status->lhw.wlv / 10;
  4616. }
  4617. status->matk_min += wMatk - variance;
  4618. status->matk_max += wMatk + variance;
  4619. }
  4620. break;
  4621. }
  4622. #endif
  4623. if (bl->type&BL_PC && sd->matk_rate != 100) {
  4624. status->matk_max = status->matk_max * sd->matk_rate/100;
  4625. status->matk_min = status->matk_min * sd->matk_rate/100;
  4626. }
  4627. if ((bl->type&BL_HOM && battle_config.hom_setting&HOMSET_SAME_MATK) /// Hom Min Matk is always the same as Max Matk
  4628. || (sc && sc->data[SC_RECOGNIZEDSPELL]))
  4629. status->matk_min = status->matk_max;
  4630. #ifdef RENEWAL
  4631. if( sd && sd->right_weapon.overrefine > 0) {
  4632. status->matk_min++;
  4633. status->matk_max += sd->right_weapon.overrefine - 1;
  4634. }
  4635. #endif
  4636. status->matk_max = status_calc_matk(bl, sc, status->matk_max);
  4637. status->matk_min = status_calc_matk(bl, sc, status->matk_min);
  4638. }
  4639. if(flag[SCB_ASPD]) {
  4640. int amotion;
  4641. if ( bl->type&BL_HOM ) {
  4642. #ifdef RENEWAL_ASPD
  4643. amotion = ((TBL_HOM*)bl)->homunculusDB->baseASPD;
  4644. amotion = amotion - amotion * status_get_homdex(bl) / 1000 - status_get_homagi(bl) * amotion / 250;
  4645. amotion = (amotion * status_calc_aspd(bl, sc, true) + status_calc_aspd(bl, sc, false)) / - 100 + amotion;
  4646. #else
  4647. amotion = (1000 - 4 * status->agi - status->dex) * ((TBL_HOM*)bl)->homunculusDB->baseASPD / 1000;
  4648. amotion = status_calc_aspd_rate(bl, sc, amotion);
  4649. amotion = amotion * status->aspd_rate / 1000;
  4650. #endif
  4651. amotion = status_calc_fix_aspd(bl, sc, amotion);
  4652. status->amotion = cap_value(amotion, battle_config.max_aspd, 2000);
  4653. status->adelay = status->amotion;
  4654. } else if ( bl->type&BL_PC ) {
  4655. uint16 skill_lv;
  4656. amotion = status_base_amotion_pc(sd,status);
  4657. #ifndef RENEWAL_ASPD
  4658. status->aspd_rate = status_calc_aspd_rate(bl, sc, b_status->aspd_rate);
  4659. #endif
  4660. // Absolute ASPD % modifiers
  4661. amotion = amotion * status->aspd_rate / 1000;
  4662. if (sd->ud.skilltimer != INVALID_TIMER && (skill_lv = pc_checkskill(sd, SA_FREECAST)) > 0)
  4663. #ifdef RENEWAL_ASPD
  4664. amotion = amotion * 5 * (skill_lv + 10) / 100;
  4665. #else
  4666. 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)
  4667. #endif
  4668. #ifdef RENEWAL_ASPD
  4669. // RE ASPD % modifier
  4670. amotion += (max(0xc3 - amotion, 2) * (status->aspd_rate2 + status_calc_aspd(bl, sc, false))) / 100;
  4671. amotion = 10 * (200 - amotion);
  4672. amotion += sd->bonus.aspd_add;
  4673. #endif
  4674. amotion = status_calc_fix_aspd(bl, sc, amotion);
  4675. status->amotion = cap_value(amotion,pc_maxaspd(sd),2000);
  4676. status->adelay = 2 * status->amotion;
  4677. } else { // Mercenary and mobs
  4678. amotion = b_status->amotion;
  4679. status->aspd_rate = status_calc_aspd_rate(bl, sc, b_status->aspd_rate);
  4680. amotion = amotion*status->aspd_rate/1000;
  4681. amotion = status_calc_fix_aspd(bl, sc, amotion);
  4682. status->amotion = cap_value(amotion, battle_config.monster_max_aspd, 2000);
  4683. temp = b_status->adelay*status->aspd_rate/1000;
  4684. status->adelay = cap_value(temp, battle_config.monster_max_aspd*2, 4000);
  4685. }
  4686. }
  4687. if(flag[SCB_DSPD]) {
  4688. int dmotion;
  4689. if( bl->type&BL_PC ) {
  4690. if (b_status->agi == status->agi)
  4691. status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion);
  4692. else {
  4693. dmotion = 800-status->agi*4;
  4694. status->dmotion = cap_value(dmotion, 400, 800);
  4695. if(battle_config.pc_damage_delay_rate != 100)
  4696. status->dmotion = status->dmotion*battle_config.pc_damage_delay_rate/100;
  4697. // It's safe to ignore b_status->dmotion since no bonus affects it.
  4698. status->dmotion = status_calc_dmotion(bl, sc, status->dmotion);
  4699. }
  4700. } else if( bl->type&BL_HOM ) {
  4701. dmotion = 800-status->agi*4;
  4702. status->dmotion = cap_value(dmotion, 400, 800);
  4703. status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion);
  4704. } else { // Mercenary and mobs
  4705. status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion);
  4706. }
  4707. }
  4708. #ifdef RENEWAL
  4709. if (flag[SCB_PATK]) {
  4710. if (status->pow == b_status->pow && status->con == b_status->con)
  4711. status->patk = status_calc_patk(bl, sc, b_status->patk);
  4712. else
  4713. status->patk = status_calc_patk(bl, sc, b_status->patk + (status->pow - b_status->pow) / 3 + (status->con - b_status->con) / 5);
  4714. }
  4715. if (flag[SCB_SMATK]) {
  4716. if (status->spl == b_status->spl && status->con == b_status->con)
  4717. status->smatk = status_calc_smatk(bl, sc, b_status->smatk);
  4718. else
  4719. status->smatk = status_calc_smatk(bl, sc, b_status->smatk) + (status->spl - b_status->spl) / 3 + (status->con - b_status->con) / 5;
  4720. }
  4721. if (flag[SCB_RES]) {
  4722. if (status->sta == b_status->sta)
  4723. status->res = status_calc_res(bl, sc, b_status->res);
  4724. else
  4725. status->res = status_calc_res(bl, sc, b_status->res + (status->sta - b_status->sta) + (status->sta - b_status->sta) / 3 * 5);
  4726. }
  4727. if (flag[SCB_MRES]) {
  4728. if (status->wis == b_status->wis)
  4729. status->mres = status_calc_mres(bl, sc, b_status->mres);
  4730. else
  4731. status->mres = status_calc_mres(bl, sc, b_status->mres + (status->wis - b_status->wis) + (status->wis - b_status->wis) / 3 * 5);
  4732. }
  4733. if (flag[SCB_HPLUS]) {
  4734. if (status->crt == b_status->crt)
  4735. status->hplus = status_calc_hplus(bl, sc, b_status->hplus);
  4736. else
  4737. status->hplus = status_calc_hplus(bl, sc, b_status->hplus + (status->crt - b_status->crt));
  4738. }
  4739. if (flag[SCB_CRATE]) {
  4740. if (status->crt == b_status->crt)
  4741. status->crate = status_calc_crate(bl, sc, b_status->crate);
  4742. else
  4743. status->crate = status_calc_crate(bl, sc, b_status->crate + (status->crt - b_status->crt) / 3);
  4744. }
  4745. if (flag[SCB_MAXAP]) {
  4746. if (bl->type&BL_PC) {
  4747. status->max_ap = status_calc_maxap_pc(sd);
  4748. if (battle_config.ap_rate != 100)
  4749. status->max_ap = (unsigned int)(battle_config.ap_rate * (status->max_ap / 100.));
  4750. status->max_ap = umin(status->max_ap, (unsigned int)battle_config.max_ap);
  4751. } else
  4752. status->max_ap = status_calc_maxap(bl, b_status->max_ap);
  4753. if (status->ap > status->max_ap) {
  4754. status->ap = status->max_ap;
  4755. if (sd) clif_updatestatus(sd, SP_AP);
  4756. }
  4757. }
  4758. #endif
  4759. if((flag[SCB_VIT] || flag[SCB_MAXHP] || flag[SCB_INT] || flag[SCB_MAXSP]) && bl->type &BL_REGEN)
  4760. status_calc_regen(bl, status, status_get_regen_data(bl));
  4761. if(flag[SCB_REGEN] && bl->type&BL_REGEN)
  4762. status_calc_regen_rate(bl, status_get_regen_data(bl), sc);
  4763. }
  4764. /**
  4765. * Recalculates parts of an objects status according to specified flags
  4766. * Also sends updates to the client when necessary
  4767. * See [set_sc] [add_sc]
  4768. * @param bl: Object whose status has changed [PC|MOB|HOM|MER|ELEM]
  4769. * @param flag: Which status has changed on bl
  4770. * @param opt: If true, will cause status_calc_* functions to run their base status initialization code
  4771. */
  4772. void status_calc_bl_(struct block_list* bl, std::bitset<SCB_MAX> flag, uint8 opt)
  4773. {
  4774. struct status_data b_status; // Previous battle status
  4775. struct status_data* status; // Pointer to current battle status
  4776. if (bl->type == BL_PC) {
  4777. struct map_session_data *sd = BL_CAST(BL_PC, bl);
  4778. if (sd->delayed_damage != 0) {
  4779. if (opt&SCO_FORCE)
  4780. sd->state.hold_recalc = false; // Clear and move on
  4781. else {
  4782. sd->state.hold_recalc = true; // Flag and stop
  4783. return;
  4784. }
  4785. }
  4786. }
  4787. // Remember previous values
  4788. status = status_get_status_data(bl);
  4789. memcpy(&b_status, status, sizeof(struct status_data));
  4790. if( flag[SCB_BASE] ) { // Calculate the object's base status too
  4791. switch( bl->type ) {
  4792. case BL_PC: status_calc_pc_(BL_CAST(BL_PC,bl), opt); break;
  4793. case BL_MOB: status_calc_mob_(BL_CAST(BL_MOB,bl), opt); break;
  4794. case BL_PET: status_calc_pet_(BL_CAST(BL_PET,bl), opt); break;
  4795. case BL_HOM: status_calc_homunculus_(BL_CAST(BL_HOM,bl), opt); break;
  4796. case BL_MER: status_calc_mercenary_(BL_CAST(BL_MER,bl), opt); break;
  4797. case BL_ELEM: status_calc_elemental_(BL_CAST(BL_ELEM,bl), opt); break;
  4798. case BL_NPC: status_calc_npc_(BL_CAST(BL_NPC,bl), opt); break;
  4799. }
  4800. }
  4801. if( bl->type == BL_PET )
  4802. return; // Pets are not affected by statuses
  4803. if (opt&SCO_FIRST && bl->type == BL_MOB)
  4804. return; // Assume there will be no statuses active
  4805. status_calc_bl_main(bl, flag);
  4806. if (opt&SCO_FIRST && bl->type == BL_HOM)
  4807. return; // Client update handled by caller
  4808. // Compare against new values and send client updates
  4809. if( bl->type == BL_PC ) {
  4810. TBL_PC* sd = BL_CAST(BL_PC, bl);
  4811. if(b_status.str != status->str)
  4812. clif_updatestatus(sd,SP_STR);
  4813. if(b_status.agi != status->agi)
  4814. clif_updatestatus(sd,SP_AGI);
  4815. if(b_status.vit != status->vit)
  4816. clif_updatestatus(sd,SP_VIT);
  4817. if(b_status.int_ != status->int_)
  4818. clif_updatestatus(sd,SP_INT);
  4819. if(b_status.dex != status->dex)
  4820. clif_updatestatus(sd,SP_DEX);
  4821. if(b_status.luk != status->luk)
  4822. clif_updatestatus(sd,SP_LUK);
  4823. if(b_status.hit != status->hit)
  4824. clif_updatestatus(sd,SP_HIT);
  4825. if(b_status.flee != status->flee)
  4826. clif_updatestatus(sd,SP_FLEE1);
  4827. if(b_status.amotion != status->amotion)
  4828. clif_updatestatus(sd,SP_ASPD);
  4829. if(b_status.speed != status->speed)
  4830. clif_updatestatus(sd,SP_SPEED);
  4831. if(b_status.batk != status->batk
  4832. #ifndef RENEWAL
  4833. || b_status.rhw.atk != status->rhw.atk || b_status.lhw.atk != status->lhw.atk
  4834. #endif
  4835. )
  4836. clif_updatestatus(sd,SP_ATK1);
  4837. if(b_status.def != status->def) {
  4838. clif_updatestatus(sd,SP_DEF1);
  4839. #ifdef RENEWAL
  4840. clif_updatestatus(sd,SP_DEF2);
  4841. #endif
  4842. }
  4843. if(
  4844. #ifdef RENEWAL
  4845. b_status.watk != status->watk || b_status.watk2 != status->watk2 || b_status.eatk != status->eatk
  4846. #else
  4847. b_status.rhw.atk2 != status->rhw.atk2 || b_status.lhw.atk2 != status->lhw.atk2
  4848. #endif
  4849. )
  4850. clif_updatestatus(sd,SP_ATK2);
  4851. if(b_status.def2 != status->def2) {
  4852. clif_updatestatus(sd,SP_DEF2);
  4853. #ifdef RENEWAL
  4854. clif_updatestatus(sd,SP_DEF1);
  4855. #endif
  4856. }
  4857. if(b_status.flee2 != status->flee2)
  4858. clif_updatestatus(sd,SP_FLEE2);
  4859. if(b_status.cri != status->cri)
  4860. clif_updatestatus(sd,SP_CRITICAL);
  4861. #ifndef RENEWAL
  4862. if(b_status.matk_max != status->matk_max)
  4863. clif_updatestatus(sd,SP_MATK1);
  4864. if(b_status.matk_min != status->matk_min)
  4865. clif_updatestatus(sd,SP_MATK2);
  4866. #else
  4867. if(b_status.matk_max != status->matk_max || b_status.matk_min != status->matk_min) {
  4868. clif_updatestatus(sd,SP_MATK2);
  4869. clif_updatestatus(sd,SP_MATK1);
  4870. }
  4871. #endif
  4872. if(b_status.mdef != status->mdef) {
  4873. clif_updatestatus(sd,SP_MDEF1);
  4874. #ifdef RENEWAL
  4875. clif_updatestatus(sd,SP_MDEF2);
  4876. #endif
  4877. }
  4878. if(b_status.mdef2 != status->mdef2) {
  4879. clif_updatestatus(sd,SP_MDEF2);
  4880. #ifdef RENEWAL
  4881. clif_updatestatus(sd,SP_MDEF1);
  4882. #endif
  4883. }
  4884. if(b_status.rhw.range != status->rhw.range)
  4885. clif_updatestatus(sd,SP_ATTACKRANGE);
  4886. if(b_status.max_hp != status->max_hp)
  4887. clif_updatestatus(sd,SP_MAXHP);
  4888. if(b_status.max_sp != status->max_sp)
  4889. clif_updatestatus(sd,SP_MAXSP);
  4890. if(b_status.hp != status->hp)
  4891. clif_updatestatus(sd,SP_HP);
  4892. if(b_status.sp != status->sp)
  4893. clif_updatestatus(sd,SP_SP);
  4894. #ifdef RENEWAL
  4895. if (b_status.pow != status->pow)
  4896. clif_updatestatus(sd,SP_POW);
  4897. if (b_status.sta != status->sta)
  4898. clif_updatestatus(sd,SP_STA);
  4899. if (b_status.wis != status->wis)
  4900. clif_updatestatus(sd,SP_WIS);
  4901. if (b_status.spl != status->spl)
  4902. clif_updatestatus(sd,SP_SPL);
  4903. if (b_status.con != status->con)
  4904. clif_updatestatus(sd,SP_CON);
  4905. if (b_status.crt != status->crt)
  4906. clif_updatestatus(sd,SP_CRT);
  4907. if (b_status.patk != status->patk)
  4908. clif_updatestatus(sd, SP_PATK);
  4909. if (b_status.smatk != status->smatk)
  4910. clif_updatestatus(sd, SP_SMATK);
  4911. if (b_status.res != status->res)
  4912. clif_updatestatus(sd, SP_RES);
  4913. if (b_status.mres != status->mres)
  4914. clif_updatestatus(sd, SP_MRES);
  4915. if (b_status.hplus != status->hplus)
  4916. clif_updatestatus(sd, SP_HPLUS);
  4917. if (b_status.crate != status->crate)
  4918. clif_updatestatus(sd, SP_CRATE);
  4919. if (b_status.max_ap != status->max_ap)
  4920. clif_updatestatus(sd, SP_MAXAP);
  4921. if (b_status.ap != status->ap)
  4922. clif_updatestatus(sd, SP_AP);
  4923. #endif
  4924. } else if( bl->type == BL_HOM ) {
  4925. TBL_HOM* hd = BL_CAST(BL_HOM, bl);
  4926. if( hd->master && memcmp(&b_status, status, sizeof(struct status_data)) != 0 )
  4927. clif_hominfo(hd->master,hd,0);
  4928. } else if( bl->type == BL_MER ) {
  4929. TBL_MER* md = BL_CAST(BL_MER, bl);
  4930. if (!md->master)
  4931. return;
  4932. if( b_status.rhw.atk != status->rhw.atk || b_status.rhw.atk2 != status->rhw.atk2 )
  4933. clif_mercenary_updatestatus(md->master, SP_ATK1);
  4934. if( b_status.matk_max != status->matk_max )
  4935. clif_mercenary_updatestatus(md->master, SP_MATK1);
  4936. if( b_status.hit != status->hit )
  4937. clif_mercenary_updatestatus(md->master, SP_HIT);
  4938. if( b_status.cri != status->cri )
  4939. clif_mercenary_updatestatus(md->master, SP_CRITICAL);
  4940. if( b_status.def != status->def )
  4941. clif_mercenary_updatestatus(md->master, SP_DEF1);
  4942. if( b_status.mdef != status->mdef )
  4943. clif_mercenary_updatestatus(md->master, SP_MDEF1);
  4944. if( b_status.flee != status->flee )
  4945. clif_mercenary_updatestatus(md->master, SP_MERCFLEE);
  4946. if( b_status.amotion != status->amotion )
  4947. clif_mercenary_updatestatus(md->master, SP_ASPD);
  4948. if( b_status.max_hp != status->max_hp )
  4949. clif_mercenary_updatestatus(md->master, SP_MAXHP);
  4950. if( b_status.max_sp != status->max_sp )
  4951. clif_mercenary_updatestatus(md->master, SP_MAXSP);
  4952. if( b_status.hp != status->hp )
  4953. clif_mercenary_updatestatus(md->master, SP_HP);
  4954. if( b_status.sp != status->sp )
  4955. clif_mercenary_updatestatus(md->master, SP_SP);
  4956. } else if( bl->type == BL_ELEM ) {
  4957. TBL_ELEM* ed = BL_CAST(BL_ELEM, bl);
  4958. if (!ed->master)
  4959. return;
  4960. if( b_status.max_hp != status->max_hp )
  4961. clif_elemental_updatestatus(ed->master, SP_MAXHP);
  4962. if( b_status.max_sp != status->max_sp )
  4963. clif_elemental_updatestatus(ed->master, SP_MAXSP);
  4964. if( b_status.hp != status->hp )
  4965. clif_elemental_updatestatus(ed->master, SP_HP);
  4966. if( b_status.sp != status->sp )
  4967. clif_mercenary_updatestatus(ed->master, SP_SP);
  4968. }
  4969. }
  4970. /**
  4971. * Adds strength modifications based on status changes
  4972. * @param bl: Object to change str [PC|MOB|HOM|MER|ELEM]
  4973. * @param sc: Object's status change information
  4974. * @param str: Initial str
  4975. * @return modified str with cap_value(str,0,USHRT_MAX)
  4976. */
  4977. static unsigned short status_calc_str(struct block_list *bl, struct status_change *sc, int str)
  4978. {
  4979. if(!sc || !sc->count)
  4980. return cap_value(str,0,USHRT_MAX);
  4981. if(sc->data[SC_HARMONIZE]) {
  4982. str -= sc->data[SC_HARMONIZE]->val2;
  4983. return (unsigned short)cap_value(str,0,USHRT_MAX);
  4984. }
  4985. if(sc->data[SC_INCALLSTATUS])
  4986. str += sc->data[SC_INCALLSTATUS]->val1;
  4987. if(sc->data[SC_CHASEWALK2])
  4988. str += sc->data[SC_CHASEWALK2]->val1;
  4989. if(sc->data[SC_INCSTR])
  4990. str += sc->data[SC_INCSTR]->val1;
  4991. if(sc->data[SC_STRFOOD])
  4992. str += sc->data[SC_STRFOOD]->val1;
  4993. if(sc->data[SC_FOOD_STR_CASH])
  4994. str += sc->data[SC_FOOD_STR_CASH]->val1;
  4995. if(sc->data[SC_BATTLEORDERS])
  4996. str += 5;
  4997. if(sc->data[SC_LEADERSHIP])
  4998. str += sc->data[SC_LEADERSHIP]->val1;
  4999. if(sc->data[SC_LOUD])
  5000. str += 4;
  5001. if(sc->data[SC_TRUESIGHT])
  5002. str += 5;
  5003. if(sc->data[SC_SPURT])
  5004. str += 10;
  5005. if(sc->data[SC_NEN])
  5006. str += sc->data[SC_NEN]->val1;
  5007. if(sc->data[SC_BLESSING]) {
  5008. if(sc->data[SC_BLESSING]->val2)
  5009. str += sc->data[SC_BLESSING]->val2;
  5010. else
  5011. str -= str / 2;
  5012. }
  5013. if(sc->data[SC_MARIONETTE])
  5014. str -= ((sc->data[SC_MARIONETTE]->val3)>>16)&0xFF;
  5015. if(sc->data[SC_MARIONETTE2])
  5016. str += ((sc->data[SC_MARIONETTE2]->val3)>>16)&0xFF;
  5017. if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH)
  5018. str += ((sc->data[SC_SPIRIT]->val3)>>16)&0xFF;
  5019. if(sc->data[SC_GIANTGROWTH])
  5020. str += sc->data[SC_GIANTGROWTH]->val2;
  5021. if(sc->data[SC_BEYONDOFWARCRY])
  5022. str -= sc->data[SC_BEYONDOFWARCRY]->val2;
  5023. if(sc->data[SC_SAVAGE_STEAK])
  5024. str += sc->data[SC_SAVAGE_STEAK]->val1;
  5025. if(sc->data[SC_INSPIRATION])
  5026. str += sc->data[SC_INSPIRATION]->val3;
  5027. if(sc->data[SC_2011RWC_SCROLL])
  5028. str += sc->data[SC_2011RWC_SCROLL]->val1;
  5029. if(sc->data[SC_STOMACHACHE])
  5030. str -= sc->data[SC_STOMACHACHE]->val1;
  5031. if(sc->data[SC_KYOUGAKU])
  5032. str -= sc->data[SC_KYOUGAKU]->val2;
  5033. if(sc->data[SC_SWORDCLAN])
  5034. str += 1;
  5035. if(sc->data[SC_JUMPINGCLAN])
  5036. str += 1;
  5037. if(sc->data[SC_FULL_THROTTLE])
  5038. str += str * sc->data[SC_FULL_THROTTLE]->val3 / 100;
  5039. if(sc->data[SC_CHEERUP])
  5040. str += 3;
  5041. if(sc->data[SC_GLASTHEIM_STATE])
  5042. str += sc->data[SC_GLASTHEIM_STATE]->val1;
  5043. #ifdef RENEWAL
  5044. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT)
  5045. str += 15;
  5046. #endif
  5047. if (sc->data[SC_UNIVERSESTANCE])
  5048. str += sc->data[SC_UNIVERSESTANCE]->val2;
  5049. return (unsigned short)cap_value(str,0,USHRT_MAX);
  5050. }
  5051. /**
  5052. * Adds agility modifications based on status changes
  5053. * @param bl: Object to change agi [PC|MOB|HOM|MER|ELEM]
  5054. * @param sc: Object's status change information
  5055. * @param agi: Initial agi
  5056. * @return modified agi with cap_value(agi,0,USHRT_MAX)
  5057. */
  5058. static unsigned short status_calc_agi(struct block_list *bl, struct status_change *sc, int agi)
  5059. {
  5060. if(!sc || !sc->count)
  5061. return cap_value(agi,0,USHRT_MAX);
  5062. if(sc->data[SC_HARMONIZE]) {
  5063. agi -= sc->data[SC_HARMONIZE]->val2;
  5064. return (unsigned short)cap_value(agi,0,USHRT_MAX);
  5065. }
  5066. if(sc->data[SC_CONCENTRATE] && !sc->data[SC_QUAGMIRE])
  5067. agi += (agi-sc->data[SC_CONCENTRATE]->val3)*sc->data[SC_CONCENTRATE]->val2/100;
  5068. if(sc->data[SC_INCALLSTATUS])
  5069. agi += sc->data[SC_INCALLSTATUS]->val1;
  5070. if(sc->data[SC_INCAGI])
  5071. agi += sc->data[SC_INCAGI]->val1;
  5072. if(sc->data[SC_AGIFOOD])
  5073. agi += sc->data[SC_AGIFOOD]->val1;
  5074. if(sc->data[SC_FOOD_AGI_CASH])
  5075. agi += sc->data[SC_FOOD_AGI_CASH]->val1;
  5076. if(sc->data[SC_SOULCOLD])
  5077. agi += sc->data[SC_SOULCOLD]->val1;
  5078. if(sc->data[SC_TRUESIGHT])
  5079. agi += 5;
  5080. if(sc->data[SC_INCREASEAGI])
  5081. agi += sc->data[SC_INCREASEAGI]->val2;
  5082. if(sc->data[SC_INCREASING])
  5083. agi += 4; // Added based on skill updates [Reddozen]
  5084. if(sc->data[SC_2011RWC_SCROLL])
  5085. agi += sc->data[SC_2011RWC_SCROLL]->val1;
  5086. if(sc->data[SC_DECREASEAGI])
  5087. agi -= sc->data[SC_DECREASEAGI]->val2;
  5088. if(sc->data[SC_QUAGMIRE])
  5089. agi -= sc->data[SC_QUAGMIRE]->val2;
  5090. if(sc->data[SC_SUITON] && sc->data[SC_SUITON]->val3)
  5091. agi -= sc->data[SC_SUITON]->val2;
  5092. if(sc->data[SC_MARIONETTE])
  5093. agi -= ((sc->data[SC_MARIONETTE]->val3)>>8)&0xFF;
  5094. if(sc->data[SC_MARIONETTE2])
  5095. agi += ((sc->data[SC_MARIONETTE2]->val3)>>8)&0xFF;
  5096. if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH)
  5097. agi += ((sc->data[SC_SPIRIT]->val3)>>8)&0xFF;
  5098. if(sc->data[SC_ADORAMUS])
  5099. agi -= sc->data[SC_ADORAMUS]->val2;
  5100. if(sc->data[SC_MARSHOFABYSS])
  5101. agi -= agi * sc->data[SC_MARSHOFABYSS]->val2 / 100;
  5102. if(sc->data[SC_DROCERA_HERB_STEAMED])
  5103. agi += sc->data[SC_DROCERA_HERB_STEAMED]->val1;
  5104. if(sc->data[SC_INSPIRATION])
  5105. agi += sc->data[SC_INSPIRATION]->val3;
  5106. if(sc->data[SC_STOMACHACHE])
  5107. agi -= sc->data[SC_STOMACHACHE]->val1;
  5108. if(sc->data[SC_KYOUGAKU])
  5109. agi -= sc->data[SC_KYOUGAKU]->val2;
  5110. if(sc->data[SC_CROSSBOWCLAN])
  5111. agi += 1;
  5112. if(sc->data[SC_JUMPINGCLAN])
  5113. agi += 1;
  5114. if(sc->data[SC_FULL_THROTTLE])
  5115. agi += agi * sc->data[SC_FULL_THROTTLE]->val3 / 100;
  5116. if (sc->data[SC_ARCLOUSEDASH])
  5117. agi += sc->data[SC_ARCLOUSEDASH]->val2;
  5118. if(sc->data[SC_CHEERUP])
  5119. agi += 3;
  5120. if(sc->data[SC_GLASTHEIM_STATE])
  5121. agi += sc->data[SC_GLASTHEIM_STATE]->val1;
  5122. #ifdef RENEWAL
  5123. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT)
  5124. agi += 15;
  5125. #endif
  5126. if (sc->data[SC_UNIVERSESTANCE])
  5127. agi += sc->data[SC_UNIVERSESTANCE]->val2;
  5128. return (unsigned short)cap_value(agi,0,USHRT_MAX);
  5129. }
  5130. /**
  5131. * Adds vitality modifications based on status changes
  5132. * @param bl: Object to change vit [PC|MOB|HOM|MER|ELEM]
  5133. * @param sc: Object's status change information
  5134. * @param vit: Initial vit
  5135. * @return modified vit with cap_value(vit,0,USHRT_MAX)
  5136. */
  5137. static unsigned short status_calc_vit(struct block_list *bl, struct status_change *sc, int vit)
  5138. {
  5139. if(!sc || !sc->count)
  5140. return cap_value(vit,0,USHRT_MAX);
  5141. if(sc->data[SC_HARMONIZE]) {
  5142. vit -= sc->data[SC_HARMONIZE]->val2;
  5143. return (unsigned short)cap_value(vit,0,USHRT_MAX);
  5144. }
  5145. if(sc->data[SC_INCALLSTATUS])
  5146. vit += sc->data[SC_INCALLSTATUS]->val1;
  5147. if(sc->data[SC_INCVIT])
  5148. vit += sc->data[SC_INCVIT]->val1;
  5149. if(sc->data[SC_VITFOOD])
  5150. vit += sc->data[SC_VITFOOD]->val1;
  5151. if(sc->data[SC_FOOD_VIT_CASH])
  5152. vit += sc->data[SC_FOOD_VIT_CASH]->val1;
  5153. if(sc->data[SC_CHANGE])
  5154. vit += sc->data[SC_CHANGE]->val2;
  5155. if(sc->data[SC_GLORYWOUNDS])
  5156. vit += sc->data[SC_GLORYWOUNDS]->val1;
  5157. if(sc->data[SC_TRUESIGHT])
  5158. vit += 5;
  5159. if(sc->data[SC_MARIONETTE])
  5160. vit -= sc->data[SC_MARIONETTE]->val3&0xFF;
  5161. if(sc->data[SC_MARIONETTE2])
  5162. vit += sc->data[SC_MARIONETTE2]->val3&0xFF;
  5163. if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH)
  5164. vit += sc->data[SC_SPIRIT]->val3&0xFF;
  5165. if(sc->data[SC_MINOR_BBQ])
  5166. vit += sc->data[SC_MINOR_BBQ]->val1;
  5167. if(sc->data[SC_INSPIRATION])
  5168. vit += sc->data[SC_INSPIRATION]->val3;
  5169. if(sc->data[SC_2011RWC_SCROLL])
  5170. vit += sc->data[SC_2011RWC_SCROLL]->val1;
  5171. if(sc->data[SC_STOMACHACHE])
  5172. vit -= sc->data[SC_STOMACHACHE]->val1;
  5173. if(sc->data[SC_KYOUGAKU])
  5174. vit -= sc->data[SC_KYOUGAKU]->val2;
  5175. if(sc->data[SC_SWORDCLAN])
  5176. vit += 1;
  5177. if(sc->data[SC_JUMPINGCLAN])
  5178. vit += 1;
  5179. if(sc->data[SC_STRIPARMOR] && bl->type != BL_PC)
  5180. vit -= vit * sc->data[SC_STRIPARMOR]->val2/100;
  5181. if(sc->data[SC_FULL_THROTTLE])
  5182. vit += vit * sc->data[SC_FULL_THROTTLE]->val3 / 100;
  5183. #ifdef RENEWAL
  5184. if(sc->data[SC_DEFENCE])
  5185. vit += sc->data[SC_DEFENCE]->val2;
  5186. #endif
  5187. if(sc->data[SC_CHEERUP])
  5188. vit += 3;
  5189. if(sc->data[SC_GLASTHEIM_STATE])
  5190. vit += sc->data[SC_GLASTHEIM_STATE]->val1;
  5191. #ifdef RENEWAL
  5192. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT)
  5193. vit += 15;
  5194. #endif
  5195. if (sc->data[SC_UNIVERSESTANCE])
  5196. vit += sc->data[SC_UNIVERSESTANCE]->val2;
  5197. return (unsigned short)cap_value(vit,0,USHRT_MAX);
  5198. }
  5199. /**
  5200. * Adds intelligence modifications based on status changes
  5201. * @param bl: Object to change int [PC|MOB|HOM|MER|ELEM]
  5202. * @param sc: Object's status change information
  5203. * @param int_: Initial int
  5204. * @return modified int with cap_value(int_,0,USHRT_MAX)
  5205. */
  5206. static unsigned short status_calc_int(struct block_list *bl, struct status_change *sc, int int_)
  5207. {
  5208. if(!sc || !sc->count)
  5209. return cap_value(int_,0,USHRT_MAX);
  5210. if(sc->data[SC_HARMONIZE]) {
  5211. int_ -= sc->data[SC_HARMONIZE]->val2;
  5212. return (unsigned short)cap_value(int_,0,USHRT_MAX);
  5213. }
  5214. if(sc->data[SC_INCALLSTATUS])
  5215. int_ += sc->data[SC_INCALLSTATUS]->val1;
  5216. if(sc->data[SC_INCINT])
  5217. int_ += sc->data[SC_INCINT]->val1;
  5218. if(sc->data[SC_INTFOOD])
  5219. int_ += sc->data[SC_INTFOOD]->val1;
  5220. if(sc->data[SC_FOOD_INT_CASH])
  5221. int_ += sc->data[SC_FOOD_INT_CASH]->val1;
  5222. if(sc->data[SC_CHANGE])
  5223. int_ += sc->data[SC_CHANGE]->val3;
  5224. if(sc->data[SC_BATTLEORDERS])
  5225. int_ += 5;
  5226. if(sc->data[SC_TRUESIGHT])
  5227. int_ += 5;
  5228. if(sc->data[SC_BLESSING]) {
  5229. if (sc->data[SC_BLESSING]->val2)
  5230. int_ += sc->data[SC_BLESSING]->val2;
  5231. else
  5232. int_ -= int_ / 2;
  5233. }
  5234. if(sc->data[SC_NEN])
  5235. int_ += sc->data[SC_NEN]->val1;
  5236. if(sc->data[SC_MARIONETTE])
  5237. int_ -= ((sc->data[SC_MARIONETTE]->val4)>>16)&0xFF;
  5238. if(sc->data[SC_2011RWC_SCROLL])
  5239. int_ += sc->data[SC_2011RWC_SCROLL]->val1;
  5240. if(sc->data[SC_MARIONETTE2])
  5241. int_ += ((sc->data[SC_MARIONETTE2]->val4)>>16)&0xFF;
  5242. if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH)
  5243. int_ += ((sc->data[SC_SPIRIT]->val4)>>16)&0xFF;
  5244. if(sc->data[SC_INSPIRATION])
  5245. int_ += sc->data[SC_INSPIRATION]->val3;
  5246. if(sc->data[SC_MELODYOFSINK])
  5247. int_ -= sc->data[SC_MELODYOFSINK]->val2;
  5248. if(sc->data[SC_MANDRAGORA])
  5249. int_ -= 4 * sc->data[SC_MANDRAGORA]->val1;
  5250. if(sc->data[SC_COCKTAIL_WARG_BLOOD])
  5251. int_ += sc->data[SC_COCKTAIL_WARG_BLOOD]->val1;
  5252. if(sc->data[SC_STOMACHACHE])
  5253. int_ -= sc->data[SC_STOMACHACHE]->val1;
  5254. if(sc->data[SC_KYOUGAKU])
  5255. int_ -= sc->data[SC_KYOUGAKU]->val2;
  5256. if(sc->data[SC_ARCWANDCLAN])
  5257. int_ += 1;
  5258. if(sc->data[SC_GOLDENMACECLAN])
  5259. int_ += 1;
  5260. if(sc->data[SC_JUMPINGCLAN])
  5261. int_ += 1;
  5262. if(sc->data[SC_FULL_THROTTLE])
  5263. int_ += int_ * sc->data[SC_FULL_THROTTLE]->val3 / 100;
  5264. if(sc->data[SC_CHEERUP])
  5265. int_ += 3;
  5266. if(sc->data[SC_GLASTHEIM_STATE])
  5267. int_ += sc->data[SC_GLASTHEIM_STATE]->val1;
  5268. if (sc->data[SC_UNIVERSESTANCE])
  5269. int_ += sc->data[SC_UNIVERSESTANCE]->val2;
  5270. if(bl->type != BL_PC) {
  5271. if(sc->data[SC_STRIPHELM])
  5272. int_ -= int_ * sc->data[SC_STRIPHELM]->val2/100;
  5273. if(sc->data[SC__STRIPACCESSORY])
  5274. int_ -= int_ * sc->data[SC__STRIPACCESSORY]->val2 / 100;
  5275. }
  5276. #ifdef RENEWAL
  5277. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT)
  5278. int_ += 15;
  5279. #endif
  5280. return (unsigned short)cap_value(int_,0,USHRT_MAX);
  5281. }
  5282. /**
  5283. * Adds dexterity modifications based on status changes
  5284. * @param bl: Object to change dex [PC|MOB|HOM|MER|ELEM]
  5285. * @param sc: Object's status change information
  5286. * @param dex: Initial dex
  5287. * @return modified dex with cap_value(dex,0,USHRT_MAX)
  5288. */
  5289. static unsigned short status_calc_dex(struct block_list *bl, struct status_change *sc, int dex)
  5290. {
  5291. if(!sc || !sc->count)
  5292. return cap_value(dex,0,USHRT_MAX);
  5293. if(sc->data[SC_HARMONIZE]) {
  5294. dex -= sc->data[SC_HARMONIZE]->val2;
  5295. return (unsigned short)cap_value(dex,0,USHRT_MAX);
  5296. }
  5297. if(sc->data[SC_CONCENTRATE] && !sc->data[SC_QUAGMIRE])
  5298. dex += (dex-sc->data[SC_CONCENTRATE]->val4)*sc->data[SC_CONCENTRATE]->val2/100;
  5299. if(sc->data[SC_INCALLSTATUS])
  5300. dex += sc->data[SC_INCALLSTATUS]->val1;
  5301. if(sc->data[SC_INCDEX])
  5302. dex += sc->data[SC_INCDEX]->val1;
  5303. if(sc->data[SC_DEXFOOD])
  5304. dex += sc->data[SC_DEXFOOD]->val1;
  5305. if(sc->data[SC_FOOD_DEX_CASH])
  5306. dex += sc->data[SC_FOOD_DEX_CASH]->val1;
  5307. if(sc->data[SC_BATTLEORDERS])
  5308. dex += 5;
  5309. if(sc->data[SC_HAWKEYES])
  5310. dex += sc->data[SC_HAWKEYES]->val1;
  5311. if(sc->data[SC_TRUESIGHT])
  5312. dex += 5;
  5313. if(sc->data[SC_QUAGMIRE])
  5314. dex -= sc->data[SC_QUAGMIRE]->val2;
  5315. if(sc->data[SC_BLESSING]) {
  5316. if (sc->data[SC_BLESSING]->val2)
  5317. dex += sc->data[SC_BLESSING]->val2;
  5318. else
  5319. dex -= dex / 2;
  5320. }
  5321. if(sc->data[SC_INCREASING])
  5322. dex += 4; // Added based on skill updates [Reddozen]
  5323. if(sc->data[SC_MARIONETTE])
  5324. dex -= ((sc->data[SC_MARIONETTE]->val4)>>8)&0xFF;
  5325. if(sc->data[SC_2011RWC_SCROLL])
  5326. dex += sc->data[SC_2011RWC_SCROLL]->val1;
  5327. if(sc->data[SC_MARIONETTE2])
  5328. dex += ((sc->data[SC_MARIONETTE2]->val4)>>8)&0xFF;
  5329. if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH)
  5330. dex += ((sc->data[SC_SPIRIT]->val4)>>8)&0xFF;
  5331. if(sc->data[SC_SIROMA_ICE_TEA])
  5332. dex += sc->data[SC_SIROMA_ICE_TEA]->val1;
  5333. if(sc->data[SC_INSPIRATION])
  5334. dex += sc->data[SC_INSPIRATION]->val3;
  5335. if(sc->data[SC_STOMACHACHE])
  5336. dex -= sc->data[SC_STOMACHACHE]->val1;
  5337. if(sc->data[SC_KYOUGAKU])
  5338. dex -= sc->data[SC_KYOUGAKU]->val2;
  5339. if(sc->data[SC_ARCWANDCLAN])
  5340. dex += 1;
  5341. if(sc->data[SC_CROSSBOWCLAN])
  5342. dex += 1;
  5343. if(sc->data[SC_JUMPINGCLAN])
  5344. dex += 1;
  5345. if(sc->data[SC__STRIPACCESSORY] && bl->type != BL_PC)
  5346. dex -= dex * sc->data[SC__STRIPACCESSORY]->val2 / 100;
  5347. if(sc->data[SC_MARSHOFABYSS])
  5348. dex -= dex * sc->data[SC_MARSHOFABYSS]->val2 / 100;
  5349. if(sc->data[SC_FULL_THROTTLE])
  5350. dex += dex * sc->data[SC_FULL_THROTTLE]->val3 / 100;
  5351. if(sc->data[SC_CHEERUP])
  5352. dex += 3;
  5353. if(sc->data[SC_GLASTHEIM_STATE])
  5354. dex += sc->data[SC_GLASTHEIM_STATE]->val1;
  5355. #ifdef RENEWAL
  5356. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT)
  5357. dex += 15;
  5358. #endif
  5359. if (sc->data[SC_UNIVERSESTANCE])
  5360. dex += sc->data[SC_UNIVERSESTANCE]->val2;
  5361. return (unsigned short)cap_value(dex,0,USHRT_MAX);
  5362. }
  5363. /**
  5364. * Adds luck modifications based on status changes
  5365. * @param bl: Object to change luk [PC|MOB|HOM|MER|ELEM]
  5366. * @param sc: Object's status change information
  5367. * @param luk: Initial luk
  5368. * @return modified luk with cap_value(luk,0,USHRT_MAX)
  5369. */
  5370. static unsigned short status_calc_luk(struct block_list *bl, struct status_change *sc, int luk)
  5371. {
  5372. if(!sc || !sc->count)
  5373. return cap_value(luk,0,USHRT_MAX);
  5374. if(sc->data[SC_HARMONIZE]) {
  5375. luk -= sc->data[SC_HARMONIZE]->val2;
  5376. return (unsigned short)cap_value(luk,0,USHRT_MAX);
  5377. }
  5378. if(sc->data[SC_CURSE])
  5379. return 0;
  5380. if(sc->data[SC_INCALLSTATUS])
  5381. luk += sc->data[SC_INCALLSTATUS]->val1;
  5382. if(sc->data[SC_INCLUK])
  5383. luk += sc->data[SC_INCLUK]->val1;
  5384. if(sc->data[SC_LUKFOOD])
  5385. luk += sc->data[SC_LUKFOOD]->val1;
  5386. if(sc->data[SC_FOOD_LUK_CASH])
  5387. luk += sc->data[SC_FOOD_LUK_CASH]->val1;
  5388. if(sc->data[SC_TRUESIGHT])
  5389. luk += 5;
  5390. if(sc->data[SC_GLORIA])
  5391. luk += 30;
  5392. if(sc->data[SC_MARIONETTE])
  5393. luk -= sc->data[SC_MARIONETTE]->val4&0xFF;
  5394. if(sc->data[SC_MARIONETTE2])
  5395. luk += sc->data[SC_MARIONETTE2]->val4&0xFF;
  5396. if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH)
  5397. luk += sc->data[SC_SPIRIT]->val4&0xFF;
  5398. if(sc->data[SC_PUTTI_TAILS_NOODLES])
  5399. luk += sc->data[SC_PUTTI_TAILS_NOODLES]->val1;
  5400. if(sc->data[SC_INSPIRATION])
  5401. luk += sc->data[SC_INSPIRATION]->val3;
  5402. if(sc->data[SC_STOMACHACHE])
  5403. luk -= sc->data[SC_STOMACHACHE]->val1;
  5404. if(sc->data[SC_KYOUGAKU])
  5405. luk -= sc->data[SC_KYOUGAKU]->val2;
  5406. if(sc->data[SC_2011RWC_SCROLL])
  5407. luk += sc->data[SC_2011RWC_SCROLL]->val1;
  5408. if(sc->data[SC__STRIPACCESSORY] && bl->type != BL_PC)
  5409. luk -= luk * sc->data[SC__STRIPACCESSORY]->val2 / 100;
  5410. if(sc->data[SC_BANANA_BOMB])
  5411. luk -= 75;
  5412. if(sc->data[SC_GOLDENMACECLAN])
  5413. luk += 1;
  5414. if(sc->data[SC_JUMPINGCLAN])
  5415. luk += 1;
  5416. if(sc->data[SC_FULL_THROTTLE])
  5417. luk += luk * sc->data[SC_FULL_THROTTLE]->val3 / 100;
  5418. if(sc->data[SC_CHEERUP])
  5419. luk += 3;
  5420. if(sc->data[SC_GLASTHEIM_STATE])
  5421. luk += sc->data[SC_GLASTHEIM_STATE]->val1;
  5422. #ifdef RENEWAL
  5423. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT)
  5424. luk += 15;
  5425. #endif
  5426. if (sc->data[SC_UNIVERSESTANCE])
  5427. luk += sc->data[SC_UNIVERSESTANCE]->val2;
  5428. return (unsigned short)cap_value(luk,0,USHRT_MAX);
  5429. }
  5430. /**
  5431. * Adds power modifications based on status changes
  5432. * @param bl: Object to change pow [PC|MOB|HOM|MER|ELEM]
  5433. * @param sc: Object's status change information
  5434. * @param pow: Initial pow
  5435. * @return modified pow with cap_value(pow,0,USHRT_MAX)
  5436. */
  5437. static unsigned short status_calc_pow(struct block_list *bl, struct status_change *sc, int pow)
  5438. {
  5439. if (!sc || !sc->count)
  5440. return cap_value(pow, 0, USHRT_MAX);
  5441. if (sc->data[SC_BENEDICTUM])
  5442. pow += sc->data[SC_BENEDICTUM]->val2;
  5443. return (unsigned short)cap_value(pow, 0, USHRT_MAX);
  5444. }
  5445. /**
  5446. * Adds stamina modifications based on status changes
  5447. * @param bl: Object to change sta [PC|MOB|HOM|MER|ELEM]
  5448. * @param sc: Object's status change information
  5449. * @param sta: Initial sta
  5450. * @return modified sta with cap_value(sta,0,USHRT_MAX)
  5451. */
  5452. static unsigned short status_calc_sta(struct block_list *bl, struct status_change *sc, int sta)
  5453. {
  5454. if (!sc || !sc->count)
  5455. return cap_value(sta, 0, USHRT_MAX);
  5456. if (sc->data[SC_RELIGIO])
  5457. sta += sc->data[SC_RELIGIO]->val2;
  5458. return (unsigned short)cap_value(sta, 0, USHRT_MAX);
  5459. }
  5460. /**
  5461. * Adds wisdom modifications based on status changes
  5462. * @param bl: Object to change wis [PC|MOB|HOM|MER|ELEM]
  5463. * @param sc: Object's status change information
  5464. * @param wis: Initial wis
  5465. * @return modified wis with cap_value(wis,0,USHRT_MAX)
  5466. */
  5467. static unsigned short status_calc_wis(struct block_list *bl, struct status_change *sc, int wis)
  5468. {
  5469. if (!sc || !sc->count)
  5470. return cap_value(wis, 0, USHRT_MAX);
  5471. if (sc->data[SC_RELIGIO])
  5472. wis += sc->data[SC_RELIGIO]->val2;
  5473. return (unsigned short)cap_value(wis, 0, USHRT_MAX);
  5474. }
  5475. /**
  5476. * Adds spell modifications based on status changes
  5477. * @param bl: Object to change spl [PC|MOB|HOM|MER|ELEM]
  5478. * @param sc: Object's status change information
  5479. * @param spl: Initial spl
  5480. * @return modified spl with cap_value(spl,0,USHRT_MAX)
  5481. */
  5482. static unsigned short status_calc_spl(struct block_list *bl, struct status_change *sc, int spl)
  5483. {
  5484. if (!sc || !sc->count)
  5485. return cap_value(spl, 0, USHRT_MAX);
  5486. if (sc->data[SC_RELIGIO])
  5487. spl += sc->data[SC_RELIGIO]->val2;
  5488. return (unsigned short)cap_value(spl, 0, USHRT_MAX);
  5489. }
  5490. /**
  5491. * Adds concentration modifications based on status changes
  5492. * @param bl: Object to change con [PC|MOB|HOM|MER|ELEM]
  5493. * @param sc: Object's status change information
  5494. * @param con: Initial con
  5495. * @return modified con with cap_value(con,0,USHRT_MAX)
  5496. */
  5497. static unsigned short status_calc_con(struct block_list *bl, struct status_change *sc, int con)
  5498. {
  5499. if (!sc || !sc->count)
  5500. return cap_value(con, 0, USHRT_MAX);
  5501. if (sc->data[SC_BENEDICTUM])
  5502. con += sc->data[SC_BENEDICTUM]->val2;
  5503. return (unsigned short)cap_value(con, 0, USHRT_MAX);
  5504. }
  5505. /**
  5506. * Adds creative modifications based on status changes
  5507. * @param bl: Object to change crt [PC|MOB|HOM|MER|ELEM]
  5508. * @param sc: Object's status change information
  5509. * @param crt: Initial crt
  5510. * @return modified crt with cap_value(crt,0,USHRT_MAX)
  5511. */
  5512. static unsigned short status_calc_crt(struct block_list *bl, struct status_change *sc, int crt)
  5513. {
  5514. if (!sc || !sc->count)
  5515. return cap_value(crt, 0, USHRT_MAX);
  5516. if (sc->data[SC_BENEDICTUM])
  5517. crt += sc->data[SC_BENEDICTUM]->val2;
  5518. return (unsigned short)cap_value(crt, 0, USHRT_MAX);
  5519. }
  5520. /**
  5521. * Adds base attack modifications based on status changes
  5522. * @param bl: Object to change batk [PC|MOB|HOM|MER|ELEM]
  5523. * @param sc: Object's status change information
  5524. * @param batk: Initial batk
  5525. * @return modified batk with cap_value(batk,0,USHRT_MAX)
  5526. */
  5527. static unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, int batk)
  5528. {
  5529. if(!sc || !sc->count)
  5530. return cap_value(batk,0,USHRT_MAX);
  5531. if(sc->data[SC_ATKPOTION])
  5532. batk += sc->data[SC_ATKPOTION]->val1;
  5533. if(sc->data[SC_BATKFOOD])
  5534. batk += sc->data[SC_BATKFOOD]->val1;
  5535. #ifndef RENEWAL
  5536. if(sc->data[SC_GATLINGFEVER])
  5537. batk += sc->data[SC_GATLINGFEVER]->val3;
  5538. if(sc->data[SC_MADNESSCANCEL])
  5539. batk += 100;
  5540. #endif
  5541. if(sc->data[SC_FULL_SWING_K])
  5542. batk += sc->data[SC_FULL_SWING_K]->val1;
  5543. if(sc->data[SC_ASH])
  5544. batk -= batk * sc->data[SC_ASH]->val4 / 100;
  5545. if(bl->type == BL_HOM && sc->data[SC_PYROCLASTIC])
  5546. batk += sc->data[SC_PYROCLASTIC]->val2;
  5547. if (sc->data[SC_ANGRIFFS_MODUS])
  5548. batk += sc->data[SC_ANGRIFFS_MODUS]->val2;
  5549. if(sc->data[SC_2011RWC_SCROLL])
  5550. batk += 30;
  5551. if(sc->data[SC_INCATKRATE])
  5552. batk += batk * sc->data[SC_INCATKRATE]->val1/100;
  5553. if(sc->data[SC_PROVOKE])
  5554. batk += batk * sc->data[SC_PROVOKE]->val2/100;
  5555. #ifndef RENEWAL
  5556. if(sc->data[SC_CONCENTRATION])
  5557. batk += batk * sc->data[SC_CONCENTRATION]->val2/100;
  5558. #endif
  5559. if(sc->data[SC_SKE])
  5560. batk += batk * 3;
  5561. if(sc->data[SC_BLOODLUST])
  5562. batk += batk * sc->data[SC_BLOODLUST]->val2/100;
  5563. if(sc->data[SC_JOINTBEAT] && sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST)
  5564. batk -= batk * 25/100;
  5565. if(sc->data[SC_CURSE])
  5566. batk -= batk * 25/100;
  5567. /* Curse shouldn't effect on this? <- Curse OR Bleeding??
  5568. if(sc->data[SC_BLEEDING])
  5569. batk -= batk * 25 / 100; */
  5570. if(sc->data[SC_FLEET])
  5571. batk += batk * sc->data[SC_FLEET]->val3/100;
  5572. if(sc->data[SC__ENERVATION])
  5573. batk -= batk * sc->data[SC__ENERVATION]->val2 / 100;
  5574. if( sc->data[SC_ZANGETSU] )
  5575. batk += sc->data[SC_ZANGETSU]->val2;
  5576. if(sc->data[SC_QUEST_BUFF1])
  5577. batk += sc->data[SC_QUEST_BUFF1]->val1;
  5578. if(sc->data[SC_QUEST_BUFF2])
  5579. batk += sc->data[SC_QUEST_BUFF2]->val1;
  5580. if(sc->data[SC_QUEST_BUFF3])
  5581. batk += sc->data[SC_QUEST_BUFF3]->val1;
  5582. if (sc->data[SC_SHRIMP])
  5583. batk += batk * sc->data[SC_SHRIMP]->val2 / 100;
  5584. #ifdef RENEWAL
  5585. if (sc->data[SC_LOUD])
  5586. batk += 30;
  5587. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ATKRATE)
  5588. batk += batk * 20 / 100;
  5589. #endif
  5590. if (sc->data[SC_SUNSTANCE])
  5591. batk += batk * sc->data[SC_SUNSTANCE]->val2 / 100;
  5592. return (unsigned short)cap_value(batk,0,USHRT_MAX);
  5593. }
  5594. /**
  5595. * Adds weapon attack modifications based on status changes
  5596. * @param bl: Object to change watk [PC]
  5597. * @param sc: Object's status change information
  5598. * @param watk: Initial watk
  5599. * @return modified watk with cap_value(watk,0,USHRT_MAX)
  5600. */
  5601. static unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, int watk)
  5602. {
  5603. if(!sc || !sc->count)
  5604. return cap_value(watk,0,USHRT_MAX);
  5605. #ifndef RENEWAL
  5606. if(sc->data[SC_DRUMBATTLE])
  5607. watk += sc->data[SC_DRUMBATTLE]->val2;
  5608. #endif
  5609. if (sc->data[SC_IMPOSITIO])
  5610. watk += sc->data[SC_IMPOSITIO]->val2;
  5611. if(sc->data[SC_WATKFOOD])
  5612. watk += sc->data[SC_WATKFOOD]->val1;
  5613. if(sc->data[SC_VOLCANO])
  5614. watk += sc->data[SC_VOLCANO]->val2;
  5615. if(sc->data[SC_MERC_ATKUP])
  5616. watk += sc->data[SC_MERC_ATKUP]->val2;
  5617. if(sc->data[SC_WATER_BARRIER])
  5618. watk -= sc->data[SC_WATER_BARRIER]->val2;
  5619. #ifndef RENEWAL
  5620. if(sc->data[SC_NIBELUNGEN]) {
  5621. if (bl->type != BL_PC)
  5622. watk += sc->data[SC_NIBELUNGEN]->val2;
  5623. else {
  5624. TBL_PC *sd = (TBL_PC*)bl;
  5625. short index = sd->equip_index[sd->state.lr_flag?EQI_HAND_L:EQI_HAND_R];
  5626. if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON && sd->inventory_data[index]->weapon_level == 4)
  5627. watk += sc->data[SC_NIBELUNGEN]->val2;
  5628. }
  5629. }
  5630. if(sc->data[SC_CONCENTRATION])
  5631. watk += watk * sc->data[SC_CONCENTRATION]->val2 / 100;
  5632. #endif
  5633. if(sc->data[SC_INCATKRATE])
  5634. watk += watk * sc->data[SC_INCATKRATE]->val1/100;
  5635. if(sc->data[SC_PROVOKE])
  5636. watk += watk * sc->data[SC_PROVOKE]->val2/100;
  5637. if(sc->data[SC_SKE])
  5638. watk += watk * 3;
  5639. if(sc->data[SC_FLEET])
  5640. watk += watk * sc->data[SC_FLEET]->val3/100;
  5641. if(sc->data[SC_CURSE])
  5642. watk -= watk * 25/100;
  5643. if(sc->data[SC_STRIPWEAPON] && bl->type != BL_PC)
  5644. watk -= watk * sc->data[SC_STRIPWEAPON]->val2/100;
  5645. if(sc->data[SC_FIGHTINGSPIRIT])
  5646. watk += sc->data[SC_FIGHTINGSPIRIT]->val1;
  5647. if (sc->data[SC_SHIELDSPELL_ATK])
  5648. watk += sc->data[SC_SHIELDSPELL_ATK]->val2;
  5649. if(sc->data[SC_INSPIRATION])
  5650. watk += sc->data[SC_INSPIRATION]->val2;
  5651. if(sc->data[SC_GT_CHANGE])
  5652. watk += sc->data[SC_GT_CHANGE]->val2;
  5653. if(sc->data[SC__ENERVATION])
  5654. watk -= watk * sc->data[SC__ENERVATION]->val2 / 100;
  5655. if(sc->data[SC_STRIKING])
  5656. watk += sc->data[SC_STRIKING]->val2;
  5657. if(sc->data[SC_RUSHWINDMILL])
  5658. watk += sc->data[SC_RUSHWINDMILL]->val3;
  5659. if(sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2)
  5660. watk += 50;
  5661. if((sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2)
  5662. || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2)
  5663. || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2)
  5664. || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2))
  5665. watk += watk * 10 / 100;
  5666. if(sc->data[SC_PYROTECHNIC_OPTION])
  5667. watk += sc->data[SC_PYROTECHNIC_OPTION]->val2;
  5668. if(sc->data[SC_HEATER_OPTION])
  5669. watk += sc->data[SC_HEATER_OPTION]->val2;
  5670. if(sc->data[SC_TROPIC_OPTION])
  5671. watk += sc->data[SC_TROPIC_OPTION]->val2;
  5672. if( sc && sc->data[SC_TIDAL_WEAPON] )
  5673. watk += watk * sc->data[SC_TIDAL_WEAPON]->val2 / 100;
  5674. if(bl->type == BL_PC && sc->data[SC_PYROCLASTIC])
  5675. watk += sc->data[SC_PYROCLASTIC]->val2;
  5676. if(sc->data[SC_ANGRIFFS_MODUS])
  5677. watk += watk * sc->data[SC_ANGRIFFS_MODUS]->val2/100;
  5678. if(sc->data[SC_ODINS_POWER])
  5679. watk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1;
  5680. if (sc->data[SC_FLASHCOMBO])
  5681. watk += sc->data[SC_FLASHCOMBO]->val2;
  5682. if (sc->data[SC_CATNIPPOWDER])
  5683. watk -= watk * sc->data[SC_CATNIPPOWDER]->val2 / 100;
  5684. if (sc->data[SC_CHATTERING])
  5685. watk += sc->data[SC_CHATTERING]->val2;
  5686. if (sc->data[SC_SUNSTANCE])
  5687. watk += watk * sc->data[SC_SUNSTANCE]->val2 / 100;
  5688. if (sc->data[SC_SOULFALCON])
  5689. watk += sc->data[SC_SOULFALCON]->val2;
  5690. if (sc->data[SC_PACKING_ENVELOPE1])
  5691. watk += sc->data[SC_PACKING_ENVELOPE1]->val1;
  5692. if (sc->data[SC_POWERFUL_FAITH])
  5693. watk += sc->data[SC_POWERFUL_FAITH]->val2;
  5694. if (sc->data[SC_GUARD_STANCE])
  5695. watk -= sc->data[SC_GUARD_STANCE]->val3;
  5696. if (sc->data[SC_ATTACK_STANCE])
  5697. watk += sc->data[SC_ATTACK_STANCE]->val3;
  5698. return (unsigned short)cap_value(watk,0,USHRT_MAX);
  5699. }
  5700. #ifdef RENEWAL
  5701. /**
  5702. * Adds equip magic attack modifications based on status changes [RENEWAL]
  5703. * @param bl: Object to change matk [PC]
  5704. * @param sc: Object's status change information
  5705. * @param matk: Initial matk
  5706. * @return modified matk with cap_value(matk,0,USHRT_MAX)
  5707. */
  5708. static unsigned short status_calc_ematk(struct block_list *bl, struct status_change *sc, int matk)
  5709. {
  5710. if (!sc || !sc->count)
  5711. return cap_value(matk,0,USHRT_MAX);
  5712. if (sc->data[SC_IMPOSITIO])
  5713. matk += sc->data[SC_IMPOSITIO]->val2;
  5714. if (sc->data[SC_MATKPOTION])
  5715. matk += sc->data[SC_MATKPOTION]->val1;
  5716. if (sc->data[SC_MATKFOOD])
  5717. matk += sc->data[SC_MATKFOOD]->val1;
  5718. if(sc->data[SC_MANA_PLUS])
  5719. matk += sc->data[SC_MANA_PLUS]->val1;
  5720. if(sc->data[SC_COOLER_OPTION])
  5721. matk += sc->data[SC_COOLER_OPTION]->val2;
  5722. if(sc->data[SC_AQUAPLAY_OPTION])
  5723. matk += sc->data[SC_AQUAPLAY_OPTION]->val2;
  5724. if(sc->data[SC_CHILLY_AIR_OPTION])
  5725. matk += sc->data[SC_CHILLY_AIR_OPTION]->val2;
  5726. if(sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3)
  5727. matk += 50;
  5728. if(sc->data[SC_ODINS_POWER])
  5729. matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; // 70 lvl1, 100lvl2
  5730. if(sc->data[SC_MOONLITSERENADE])
  5731. matk += sc->data[SC_MOONLITSERENADE]->val3;
  5732. if(sc->data[SC_IZAYOI])
  5733. matk += 25 * sc->data[SC_IZAYOI]->val1;
  5734. if(sc->data[SC_ZANGETSU])
  5735. matk += sc->data[SC_ZANGETSU]->val3;
  5736. if(sc->data[SC_QUEST_BUFF1])
  5737. matk += sc->data[SC_QUEST_BUFF1]->val1;
  5738. if(sc->data[SC_QUEST_BUFF2])
  5739. matk += sc->data[SC_QUEST_BUFF2]->val1;
  5740. if(sc->data[SC_QUEST_BUFF3])
  5741. matk += sc->data[SC_QUEST_BUFF3]->val1;
  5742. if(sc->data[SC_MTF_MATK2])
  5743. matk += sc->data[SC_MTF_MATK2]->val1;
  5744. if(sc->data[SC_2011RWC_SCROLL])
  5745. matk += 30;
  5746. if (sc->data[SC_CATNIPPOWDER])
  5747. matk -= matk * sc->data[SC_CATNIPPOWDER]->val2 / 100;
  5748. if (sc->data[SC_CHATTERING])
  5749. matk += sc->data[SC_CHATTERING]->val2;
  5750. if (sc->data[SC_DORAM_MATK])
  5751. matk += sc->data[SC_DORAM_MATK]->val1;
  5752. if (sc->data[SC_SOULFAIRY])
  5753. matk += sc->data[SC_SOULFAIRY]->val2;
  5754. if (sc->data[SC__AUTOSHADOWSPELL])
  5755. matk += sc->data[SC__AUTOSHADOWSPELL]->val4 * 5;
  5756. if (sc->data[SC_INSPIRATION])
  5757. matk += sc->data[SC_INSPIRATION]->val2;
  5758. if (sc->data[SC_PACKING_ENVELOPE2])
  5759. matk += sc->data[SC_PACKING_ENVELOPE2]->val1;
  5760. return (unsigned short)cap_value(matk,0,USHRT_MAX);
  5761. }
  5762. #endif
  5763. /**
  5764. * Adds magic attack modifications based on status changes
  5765. * @param bl: Object to change matk [PC|MOB|HOM|MER|ELEM]
  5766. * @param sc: Object's status change information
  5767. * @param matk: Initial matk
  5768. * @return modified matk with cap_value(matk,0,USHRT_MAX)
  5769. */
  5770. static unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, int matk)
  5771. {
  5772. if(!sc || !sc->count)
  5773. return cap_value(matk,0,USHRT_MAX);
  5774. #ifndef RENEWAL
  5775. /// Take note fixed value first before % modifiers [PRE-RENEWAL]
  5776. if (sc->data[SC_MATKPOTION])
  5777. matk += sc->data[SC_MATKPOTION]->val1;
  5778. if (sc->data[SC_MATKFOOD])
  5779. matk += sc->data[SC_MATKFOOD]->val1;
  5780. if (sc->data[SC_MANA_PLUS])
  5781. matk += sc->data[SC_MANA_PLUS]->val1;
  5782. if (sc->data[SC_AQUAPLAY_OPTION])
  5783. matk += sc->data[SC_AQUAPLAY_OPTION]->val2;
  5784. if (sc->data[SC_CHILLY_AIR_OPTION])
  5785. matk += sc->data[SC_CHILLY_AIR_OPTION]->val2;
  5786. if (sc->data[SC_COOLER_OPTION])
  5787. matk += sc->data[SC_COOLER_OPTION]->val2;
  5788. if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3)
  5789. matk += 50;
  5790. if (sc->data[SC_ODINS_POWER])
  5791. matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; // 70 lvl1, 100lvl2
  5792. if (sc->data[SC_IZAYOI])
  5793. matk += 25 * sc->data[SC_IZAYOI]->val1;
  5794. if (sc->data[SC_MTF_MATK2])
  5795. matk += sc->data[SC_MTF_MATK2]->val1;
  5796. if (sc->data[SC_2011RWC_SCROLL])
  5797. matk += 30;
  5798. #endif
  5799. if (sc->data[SC_ZANGETSU])
  5800. matk += sc->data[SC_ZANGETSU]->val3;
  5801. if (sc->data[SC_QUEST_BUFF1])
  5802. matk += sc->data[SC_QUEST_BUFF1]->val1;
  5803. if (sc->data[SC_QUEST_BUFF2])
  5804. matk += sc->data[SC_QUEST_BUFF2]->val1;
  5805. if (sc->data[SC_QUEST_BUFF3])
  5806. matk += sc->data[SC_QUEST_BUFF3]->val1;
  5807. if (sc->data[SC_MAGICPOWER]
  5808. #ifndef RENEWAL
  5809. && sc->data[SC_MAGICPOWER]->val4
  5810. #endif
  5811. )
  5812. matk += matk * sc->data[SC_MAGICPOWER]->val3/100;
  5813. if (sc->data[SC_MINDBREAKER])
  5814. matk += matk * sc->data[SC_MINDBREAKER]->val2/100;
  5815. if (sc->data[SC_INCMATKRATE])
  5816. matk += matk * sc->data[SC_INCMATKRATE]->val1/100;
  5817. if (sc->data[SC_MOONLITSERENADE])
  5818. matk += sc->data[SC_MOONLITSERENADE]->val3/100;
  5819. if (sc->data[SC_MTF_MATK])
  5820. matk += matk * sc->data[SC_MTF_MATK]->val1 / 100;
  5821. if(sc->data[SC_2011RWC_SCROLL])
  5822. matk += 30;
  5823. if (sc->data[SC_SHRIMP])
  5824. matk += matk * sc->data[SC_SHRIMP]->val2 / 100;
  5825. if (sc->data[SC_VOLCANO])
  5826. matk += sc->data[SC_VOLCANO]->val2;
  5827. #ifdef RENEWAL
  5828. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_MATKRATE)
  5829. matk += matk * 20 / 100;
  5830. #endif
  5831. if (sc->data[SC_SHIELDSPELL_ATK])
  5832. matk += sc->data[SC_SHIELDSPELL_ATK]->val2;
  5833. if (sc->data[SC_CLIMAX_DES_HU])
  5834. matk += 100;
  5835. return (unsigned short)cap_value(matk,0,USHRT_MAX);
  5836. }
  5837. /**
  5838. * Adds critical modifications based on status changes
  5839. * @param bl: Object to change critical [PC|MOB|HOM|MER|ELEM]
  5840. * @param sc: Object's status change information
  5841. * @param critical: Initial critical
  5842. * @return modified critical with cap_value(critical,10,USHRT_MAX)
  5843. */
  5844. static signed short status_calc_critical(struct block_list *bl, struct status_change *sc, int critical)
  5845. {
  5846. if(!sc || !sc->count)
  5847. return cap_value(critical,10,SHRT_MAX);
  5848. if (sc->data[SC_INCCRI])
  5849. critical += sc->data[SC_INCCRI]->val2;
  5850. if (sc->data[SC_EP16_2_BUFF_SC])
  5851. critical += 300;// crit +30
  5852. if (sc->data[SC_CRIFOOD])
  5853. critical += sc->data[SC_CRIFOOD]->val1;
  5854. if (sc->data[SC_EXPLOSIONSPIRITS])
  5855. critical += sc->data[SC_EXPLOSIONSPIRITS]->val2;
  5856. if (sc->data[SC_FORTUNE])
  5857. critical += sc->data[SC_FORTUNE]->val2;
  5858. if (sc->data[SC_TRUESIGHT])
  5859. critical += sc->data[SC_TRUESIGHT]->val2;
  5860. if (sc->data[SC_CLOAKING])
  5861. critical += critical;
  5862. #ifdef RENEWAL
  5863. if (sc->data[SC_SPEARQUICKEN])
  5864. critical += 3*sc->data[SC_SPEARQUICKEN]->val1*10;
  5865. if (sc->data[SC_TWOHANDQUICKEN])
  5866. critical += (2 + sc->data[SC_TWOHANDQUICKEN]->val1) * 10;
  5867. #endif
  5868. if (sc->data[SC__INVISIBILITY])
  5869. critical += sc->data[SC__INVISIBILITY]->val3 * 10;
  5870. if (sc->data[SC__UNLUCKY])
  5871. critical -= sc->data[SC__UNLUCKY]->val2;
  5872. if (sc->data[SC_SOULSHADOW])
  5873. critical += 10 * sc->data[SC_SOULSHADOW]->val3;
  5874. if(sc->data[SC_BEYONDOFWARCRY])
  5875. critical += sc->data[SC_BEYONDOFWARCRY]->val3;
  5876. if (sc->data[SC_MTF_HITFLEE])
  5877. critical += sc->data[SC_MTF_HITFLEE]->val1;
  5878. if (sc->data[SC_PACKING_ENVELOPE9])
  5879. critical += sc->data[SC_PACKING_ENVELOPE9]->val1 * 10;
  5880. return (short)cap_value(critical,10,SHRT_MAX);
  5881. }
  5882. /**
  5883. * Adds hit modifications based on status changes
  5884. * @param bl: Object to change hit [PC|MOB|HOM|MER|ELEM]
  5885. * @param sc: Object's status change information
  5886. * @param hit: Initial hit
  5887. * @return modified hit with cap_value(hit,1,USHRT_MAX)
  5888. */
  5889. static signed short status_calc_hit(struct block_list *bl, struct status_change *sc, int hit)
  5890. {
  5891. if(!sc || !sc->count)
  5892. return cap_value(hit,1,SHRT_MAX);
  5893. if(sc->data[SC_INCHIT])
  5894. hit += sc->data[SC_INCHIT]->val1;
  5895. if(sc->data[SC_HITFOOD])
  5896. hit += sc->data[SC_HITFOOD]->val1;
  5897. if(sc->data[SC_TRUESIGHT])
  5898. hit += sc->data[SC_TRUESIGHT]->val3;
  5899. if(sc->data[SC_HUMMING])
  5900. hit += sc->data[SC_HUMMING]->val2;
  5901. if(sc->data[SC_CONCENTRATION])
  5902. hit += sc->data[SC_CONCENTRATION]->val3;
  5903. if(sc->data[SC_INSPIRATION])
  5904. hit += 12 * sc->data[SC_INSPIRATION]->val1;
  5905. if(sc->data[SC_ADJUSTMENT])
  5906. hit -= 30;
  5907. if(sc->data[SC_INCREASING])
  5908. hit += 20; // RockmanEXE; changed based on updated [Reddozen]
  5909. if(sc->data[SC_MERC_HITUP])
  5910. hit += sc->data[SC_MERC_HITUP]->val2;
  5911. if(sc->data[SC_MTF_HITFLEE])
  5912. hit += sc->data[SC_MTF_HITFLEE]->val1;
  5913. if(sc->data[SC_INCHITRATE])
  5914. hit += hit * sc->data[SC_INCHITRATE]->val1/100;
  5915. if(sc->data[SC_BLIND])
  5916. hit -= hit * 25/100;
  5917. if(sc->data[SC_HEAT_BARREL])
  5918. hit -= sc->data[SC_HEAT_BARREL]->val4;
  5919. if(sc->data[SC__GROOMY])
  5920. hit -= hit * sc->data[SC__GROOMY]->val3 / 100;
  5921. if(sc->data[SC_FEAR])
  5922. hit -= hit * 20 / 100;
  5923. if (sc->data[SC_ASH])
  5924. hit -= hit * sc->data[SC_ASH]->val2 / 100;
  5925. if (sc->data[SC_TEARGAS])
  5926. hit -= hit * 50 / 100;
  5927. if(sc->data[SC_ILLUSIONDOPING])
  5928. hit -= sc->data[SC_ILLUSIONDOPING]->val2;
  5929. if (sc->data[SC_MTF_ASPD])
  5930. hit += sc->data[SC_MTF_ASPD]->val2;
  5931. #ifdef RENEWAL
  5932. if (sc->data[SC_BLESSING])
  5933. hit += sc->data[SC_BLESSING]->val1 * 2;
  5934. if (sc->data[SC_TWOHANDQUICKEN])
  5935. hit += sc->data[SC_TWOHANDQUICKEN]->val1 * 2;
  5936. if (sc->data[SC_ADRENALINE])
  5937. hit += sc->data[SC_ADRENALINE]->val1 * 3 + 5;
  5938. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_HIT)
  5939. hit += 50;
  5940. #endif
  5941. if (sc->data[SC_SOULFALCON])
  5942. hit += sc->data[SC_SOULFALCON]->val3;
  5943. if (sc->data[SC_SATURDAYNIGHTFEVER])
  5944. hit -= 50 + 50 * sc->data[SC_SATURDAYNIGHTFEVER]->val1;
  5945. if (sc->data[SC_PACKING_ENVELOPE10])
  5946. hit += sc->data[SC_PACKING_ENVELOPE10]->val1;
  5947. if (sc->data[SC_ABYSS_SLAYER])
  5948. hit += sc->data[SC_ABYSS_SLAYER]->val3;
  5949. return (short)cap_value(hit,1,SHRT_MAX);
  5950. }
  5951. /**
  5952. * Adds flee modifications based on status changes
  5953. * @param bl: Object to change flee [PC|MOB|HOM|MER|ELEM]
  5954. * @param sc: Object's status change information
  5955. * @param flee: Initial flee
  5956. * @return modified flee with cap_value(flee,1,USHRT_MAX)
  5957. */
  5958. static signed short status_calc_flee(struct block_list *bl, struct status_change *sc, int flee)
  5959. {
  5960. if( bl->type == BL_PC ) {
  5961. struct map_data *mapdata = map_getmapdata(bl->m);
  5962. if( mapdata_flag_gvg(mapdata) )
  5963. flee -= flee * battle_config.gvg_flee_penalty/100;
  5964. else if( mapdata->flag[MF_BATTLEGROUND] )
  5965. flee -= flee * battle_config.bg_flee_penalty/100;
  5966. }
  5967. if(!sc || !sc->count)
  5968. return cap_value(flee,1,SHRT_MAX);
  5969. if (sc->data[SC_POISON_MIST])
  5970. return 0;
  5971. if(sc->data[SC_OVERED_BOOST]) //Should be final and unmodifiable by any means
  5972. return sc->data[SC_OVERED_BOOST]->val2;
  5973. // Fixed value
  5974. if(sc->data[SC_INCFLEE])
  5975. flee += sc->data[SC_INCFLEE]->val1;
  5976. if(sc->data[SC_FLEEFOOD])
  5977. flee += sc->data[SC_FLEEFOOD]->val1;
  5978. if(sc->data[SC_WHISTLE])
  5979. flee += sc->data[SC_WHISTLE]->val2;
  5980. if(sc->data[SC_WINDWALK])
  5981. flee += sc->data[SC_WINDWALK]->val2;
  5982. if(sc->data[SC_VIOLENTGALE])
  5983. flee += sc->data[SC_VIOLENTGALE]->val2;
  5984. if(sc->data[SC_MOON_COMFORT]) // SG skill [Komurka]
  5985. flee += sc->data[SC_MOON_COMFORT]->val2;
  5986. if(sc->data[SC_CLOSECONFINE])
  5987. flee += sc->data[SC_CLOSECONFINE]->val3;
  5988. if (sc->data[SC_ANGRIFFS_MODUS])
  5989. flee -= sc->data[SC_ANGRIFFS_MODUS]->val3;
  5990. if(sc->data[SC_ADJUSTMENT])
  5991. flee += 30;
  5992. if(sc->data[SC_SPEED])
  5993. flee += 10 + sc->data[SC_SPEED]->val1 * 10;
  5994. if(sc->data[SC_GATLINGFEVER])
  5995. flee -= sc->data[SC_GATLINGFEVER]->val4;
  5996. if(sc->data[SC_PARTYFLEE])
  5997. flee += sc->data[SC_PARTYFLEE]->val1 * 10;
  5998. if(sc->data[SC_MERC_FLEEUP])
  5999. flee += sc->data[SC_MERC_FLEEUP]->val2;
  6000. if( sc->data[SC_HALLUCINATIONWALK] )
  6001. flee += sc->data[SC_HALLUCINATIONWALK]->val2;
  6002. if( sc->data[SC_NPC_HALLUCINATIONWALK] )
  6003. flee += sc->data[SC_NPC_HALLUCINATIONWALK]->val2;
  6004. if(sc->data[SC_MTF_HITFLEE])
  6005. flee += sc->data[SC_MTF_HITFLEE]->val2;
  6006. if( sc->data[SC_WATER_BARRIER] )
  6007. flee -= sc->data[SC_WATER_BARRIER]->val2;
  6008. if( sc->data[SC_C_MARKER] )
  6009. flee -= sc->data[SC_C_MARKER]->val3;
  6010. #ifdef RENEWAL
  6011. if( sc->data[SC_SPEARQUICKEN] )
  6012. flee += 2 * sc->data[SC_SPEARQUICKEN]->val1;
  6013. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_FLEE)
  6014. flee += 50;
  6015. #endif
  6016. // Rate value
  6017. if(sc->data[SC_INCFLEERATE])
  6018. flee += flee * sc->data[SC_INCFLEERATE]->val1/100;
  6019. if(sc->data[SC_SPIDERWEB] || sc->data[SC_WIDEWEB])
  6020. flee -= flee * 50/100;
  6021. if(sc->data[SC_BERSERK])
  6022. flee -= flee * 50/100;
  6023. if(sc->data[SC_BLIND])
  6024. flee -= flee * 25/100;
  6025. if(sc->data[SC_FEAR])
  6026. flee -= flee * 20 / 100;
  6027. if(sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 1)
  6028. flee -= flee * 10 / 100;
  6029. if(sc->data[SC_INFRAREDSCAN])
  6030. flee -= flee * 30 / 100;
  6031. if( sc->data[SC__LAZINESS] )
  6032. flee -= flee * sc->data[SC__LAZINESS]->val3 / 100;
  6033. if( sc->data[SC_GLOOMYDAY] )
  6034. flee -= flee * sc->data[SC_GLOOMYDAY]->val2 / 100;
  6035. if( sc->data[SC_SATURDAYNIGHTFEVER] )
  6036. flee -= 20 + 30 * sc->data[SC_SATURDAYNIGHTFEVER]->val1;
  6037. if( sc->data[SC_WIND_STEP_OPTION] )
  6038. flee += flee * sc->data[SC_WIND_STEP_OPTION]->val2 / 100;
  6039. if( sc->data[SC_TINDER_BREAKER] || sc->data[SC_TINDER_BREAKER2] )
  6040. flee -= flee * 50 / 100;
  6041. if( sc->data[SC_ZEPHYR] )
  6042. flee += sc->data[SC_ZEPHYR]->val2;
  6043. if(sc->data[SC_ASH])
  6044. flee -= flee * sc->data[SC_ASH]->val4 / 100;
  6045. if (sc->data[SC_GOLDENE_FERSE])
  6046. flee += flee * sc->data[SC_GOLDENE_FERSE]->val2 / 100;
  6047. if (sc->data[SC_SMOKEPOWDER])
  6048. flee += flee * 20 / 100;
  6049. if (sc->data[SC_TEARGAS])
  6050. flee -= flee * 50 / 100;
  6051. //if( sc->data[SC_C_MARKER] )
  6052. // flee -= (flee * sc->data[SC_C_MARKER]->val3) / 100;
  6053. if (sc->data[SC_GROOMING])
  6054. flee += sc->data[SC_GROOMING]->val2;
  6055. if (sc->data[SC_PACKING_ENVELOPE5])
  6056. flee += sc->data[SC_PACKING_ENVELOPE5]->val1;
  6057. return (short)cap_value(flee,1,SHRT_MAX);
  6058. }
  6059. /**
  6060. * Adds perfect flee modifications based on status changes
  6061. * @param bl: Object to change flee2 [PC|MOB|HOM|MER|ELEM]
  6062. * @param sc: Object's status change information
  6063. * @param flee2: Initial flee2
  6064. * @return modified flee2 with cap_value(flee2,10,USHRT_MAX)
  6065. */
  6066. static signed short status_calc_flee2(struct block_list *bl, struct status_change *sc, int flee2)
  6067. {
  6068. if(!sc || !sc->count)
  6069. return cap_value(flee2,10,SHRT_MAX);
  6070. if(sc->data[SC_INCFLEE2])
  6071. flee2 += sc->data[SC_INCFLEE2]->val2;
  6072. if(sc->data[SC_WHISTLE])
  6073. flee2 += sc->data[SC_WHISTLE]->val3*10;
  6074. if(sc->data[SC__UNLUCKY])
  6075. flee2 -= flee2 * sc->data[SC__UNLUCKY]->val2 / 100;
  6076. if (sc->data[SC_HISS])
  6077. flee2 += sc->data[SC_HISS]->val2*10;
  6078. if (sc->data[SC_DORAM_FLEE2])
  6079. flee2 += sc->data[SC_DORAM_FLEE2]->val1;
  6080. return (short)cap_value(flee2,10,SHRT_MAX);
  6081. }
  6082. /**
  6083. * Adds defense (left-side) modifications based on status changes
  6084. * @param bl: Object to change def [PC|MOB|HOM|MER|ELEM]
  6085. * @param sc: Object's status change information
  6086. * @param def: Initial def
  6087. * @return modified def with cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX)
  6088. */
  6089. static defType status_calc_def(struct block_list *bl, struct status_change *sc, int def)
  6090. {
  6091. if(!sc || !sc->count)
  6092. return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX);
  6093. if(sc->data[SC_BERSERK])
  6094. return 0;
  6095. if(sc->data[SC_BARRIER])
  6096. return 100;
  6097. if(sc->data[SC_KEEPING])
  6098. return 90;
  6099. #ifndef RENEWAL /// Steel Body does not provide 90 DEF in [RENEWAL]
  6100. if(sc->data[SC_STEELBODY])
  6101. return 90;
  6102. #endif
  6103. if (sc->data[SC_NYANGGRASS]) {
  6104. if (bl->type == BL_PC)
  6105. return 0;
  6106. else
  6107. return def >>= 1;
  6108. }
  6109. if(sc->data[SC_DEFSET])
  6110. return sc->data[SC_DEFSET]->val1;
  6111. if(sc->data[SC_DRUMBATTLE])
  6112. def += sc->data[SC_DRUMBATTLE]->val3;
  6113. #ifdef RENEWAL
  6114. if (sc->data[SC_ASSUMPTIO])
  6115. def += sc->data[SC_ASSUMPTIO]->val1 * 50;
  6116. #else
  6117. if(sc->data[SC_DEFENCE])
  6118. def += sc->data[SC_DEFENCE]->val2;
  6119. #endif
  6120. if(sc->data[SC_INCDEFRATE])
  6121. def += def * sc->data[SC_INCDEFRATE]->val1/100;
  6122. if(sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2)
  6123. def += 50;
  6124. if(sc->data[SC_ODINS_POWER])
  6125. def -= 20 * sc->data[SC_ODINS_POWER]->val1;
  6126. if( sc->data[SC_ANGRIFFS_MODUS] )
  6127. def -= 20 + 10 * sc->data[SC_ANGRIFFS_MODUS]->val1;
  6128. if(sc->data[SC_STONEHARDSKIN])
  6129. def += sc->data[SC_STONEHARDSKIN]->val1;
  6130. if(sc->data[SC_STONE])
  6131. def >>=1;
  6132. if(sc->data[SC_FREEZE])
  6133. def >>=1;
  6134. if(sc->data[SC_SIGNUMCRUCIS])
  6135. def -= def * sc->data[SC_SIGNUMCRUCIS]->val2/100;
  6136. if(sc->data[SC_CONCENTRATION])
  6137. def -= def * sc->data[SC_CONCENTRATION]->val4/100;
  6138. if(sc->data[SC_SKE])
  6139. def >>=1;
  6140. if(sc->data[SC_PROVOKE] && bl->type != BL_PC) // Provoke doesn't alter player defense->
  6141. def -= def * sc->data[SC_PROVOKE]->val3/100;
  6142. if(sc->data[SC_STRIPSHIELD] && bl->type != BL_PC) // Player doesn't have def reduction only equip removed
  6143. def -= def * sc->data[SC_STRIPSHIELD]->val2/100;
  6144. if (sc->data[SC_FLING])
  6145. def -= def * (sc->data[SC_FLING]->val2)/100;
  6146. if( sc->data[SC_FREEZING] )
  6147. def -= def * (bl->type == BL_PC ? 30 : 10) / 100;
  6148. if( sc->data[SC_ANALYZE] )
  6149. def -= def * (14 * sc->data[SC_ANALYZE]->val1) / 100;
  6150. if( sc->data[SC_NEUTRALBARRIER] )
  6151. def += def * sc->data[SC_NEUTRALBARRIER]->val2 / 100;
  6152. if( sc->data[SC_PRESTIGE] )
  6153. def += sc->data[SC_PRESTIGE]->val3;
  6154. if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 1 )
  6155. def += 6 * sc->data[SC_BANDING]->val1;
  6156. if( sc->data[SC_ECHOSONG] )
  6157. def += sc->data[SC_ECHOSONG]->val3;
  6158. if( sc->data[SC_CAMOUFLAGE] )
  6159. def -= def * 5 * sc->data[SC_CAMOUFLAGE]->val3 / 100;
  6160. if( sc->data[SC_SOLID_SKIN_OPTION] )
  6161. def += def * sc->data[SC_SOLID_SKIN_OPTION]->val2 / 100;
  6162. if( sc->data[SC_ROCK_CRUSHER] )
  6163. def -= def * sc->data[SC_ROCK_CRUSHER]->val2 / 100;
  6164. if( sc->data[SC_POWER_OF_GAIA] )
  6165. def += def * sc->data[SC_POWER_OF_GAIA]->val2 / 100;
  6166. if(sc->data[SC_ASH])
  6167. def -= def * sc->data[SC_ASH]->val3/100;
  6168. if( sc->data[SC_OVERED_BOOST] && bl->type == BL_HOM )
  6169. def -= def * sc->data[SC_OVERED_BOOST]->val4 / 100;
  6170. if(sc->data[SC_GLASTHEIM_ITEMDEF])
  6171. def += sc->data[SC_GLASTHEIM_ITEMDEF]->val1;
  6172. if (sc->data[SC_SOULGOLEM])
  6173. def += sc->data[SC_SOULGOLEM]->val2;
  6174. if (sc->data[SC_STONE_WALL])
  6175. def += sc->data[SC_STONE_WALL]->val2;
  6176. if( sc->data[SC_PACKING_ENVELOPE7] )
  6177. def += sc->data[SC_PACKING_ENVELOPE7]->val1;
  6178. if (sc->data[SC_D_MACHINE])
  6179. def += sc->data[SC_D_MACHINE]->val2;
  6180. if (sc->data[SC_CLIMAX_CRYIMP])
  6181. def += 300;
  6182. if (sc->data[SC_GUARD_STANCE])
  6183. def += sc->data[SC_GUARD_STANCE]->val2;
  6184. if (sc->data[SC_ATTACK_STANCE])
  6185. def -= sc->data[SC_ATTACK_STANCE]->val2;
  6186. return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX);
  6187. }
  6188. /**
  6189. * Adds defense (right-side) modifications based on status changes
  6190. * @param bl: Object to change def2 [PC|MOB|HOM|MER|ELEM]
  6191. * @param sc: Object's status change information
  6192. * @param def2: Initial def2
  6193. * @return modified def2 with cap_value(def2,SHRT_MIN,SHRT_MAX)
  6194. */
  6195. static signed short status_calc_def2(struct block_list *bl, struct status_change *sc, int def2)
  6196. {
  6197. if(!sc || !sc->count)
  6198. #ifdef RENEWAL
  6199. return (short)cap_value(def2,SHRT_MIN,SHRT_MAX);
  6200. #else
  6201. return (short)cap_value(def2,1,SHRT_MAX);
  6202. #endif
  6203. if(sc->data[SC_BERSERK])
  6204. return 0;
  6205. if(sc->data[SC_ETERNALCHAOS])
  6206. return 0;
  6207. if(sc->data[SC_DEFSET])
  6208. return sc->data[SC_DEFSET]->val1;
  6209. if(sc->data[SC_SUN_COMFORT])
  6210. def2 += sc->data[SC_SUN_COMFORT]->val2;
  6211. #ifdef RENEWAL
  6212. if (sc->data[SC_SKA])
  6213. def2 += 80;
  6214. #endif
  6215. if(sc->data[SC_ANGELUS])
  6216. #ifdef RENEWAL /// The VIT stat bonus is boosted by angelus [RENEWAL]
  6217. def2 += status_get_vit(bl) / 2 * sc->data[SC_ANGELUS]->val2/100;
  6218. #else
  6219. def2 += def2 * sc->data[SC_ANGELUS]->val2/100;
  6220. if(sc->data[SC_CONCENTRATION])
  6221. def2 -= def2 * sc->data[SC_CONCENTRATION]->val4/100;
  6222. #endif
  6223. if(sc->data[SC_POISON])
  6224. def2 -= def2 * 25/100;
  6225. if(sc->data[SC_DPOISON])
  6226. def2 -= def2 * 25/100;
  6227. if(sc->data[SC_SKE])
  6228. def2 -= def2 * 50/100;
  6229. if(sc->data[SC_PROVOKE])
  6230. def2 -= def2 * sc->data[SC_PROVOKE]->val3/100;
  6231. if(sc->data[SC_JOINTBEAT])
  6232. def2 -= def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_SHOULDER ? 50 : 0 ) / 100
  6233. + def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST ? 25 : 0 ) / 100;
  6234. if(sc->data[SC_FLING])
  6235. def2 -= def2 * (sc->data[SC_FLING]->val3)/100;
  6236. if(sc->data[SC_ANALYZE])
  6237. def2 -= def2 * (14 * sc->data[SC_ANALYZE]->val1) / 100;
  6238. if(sc->data[SC_ASH])
  6239. def2 -= def2 * sc->data[SC_ASH]->val3/100;
  6240. if (sc->data[SC_PARALYSIS])
  6241. def2 -= def2 * sc->data[SC_PARALYSIS]->val2 / 100;
  6242. if(sc->data[SC_EQC])
  6243. def2 -= def2 * sc->data[SC_EQC]->val2 / 100;
  6244. if( sc->data[SC_CAMOUFLAGE] )
  6245. def2 -= def2 * 5 * sc->data[SC_CAMOUFLAGE]->val3 / 100;
  6246. #ifdef RENEWAL
  6247. return (short)cap_value(def2,SHRT_MIN,SHRT_MAX);
  6248. #else
  6249. return (short)cap_value(def2,1,SHRT_MAX);
  6250. #endif
  6251. }
  6252. /**
  6253. * Adds magic defense (left-side) modifications based on status changes
  6254. * @param bl: Object to change mdef [PC|MOB|HOM|MER|ELEM]
  6255. * @param sc: Object's status change information
  6256. * @param mdef: Initial mdef
  6257. * @return modified mdef with cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX)
  6258. */
  6259. static defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int mdef)
  6260. {
  6261. if(!sc || !sc->count)
  6262. return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX);
  6263. if(sc->data[SC_BERSERK])
  6264. return 0;
  6265. if(sc->data[SC_BARRIER])
  6266. return 100;
  6267. #ifndef RENEWAL /// Steel Body does not provide 90 MDEF in [RENEWAL]
  6268. if(sc->data[SC_STEELBODY])
  6269. return 90;
  6270. #endif
  6271. if (sc->data[SC_NYANGGRASS]) {
  6272. if (bl->type == BL_PC)
  6273. return 0;
  6274. else
  6275. return mdef >>= 1;
  6276. }
  6277. if(sc->data[SC_MDEFSET])
  6278. return sc->data[SC_MDEFSET]->val1;
  6279. if(sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 3)
  6280. mdef += 50;
  6281. if(sc->data[SC_ENDURE] && !sc->data[SC_ENDURE]->val3) // It has been confirmed that Eddga card grants 1 MDEF, not 0, not 10, but 1.
  6282. mdef += (sc->data[SC_ENDURE]->val4 == 0) ? sc->data[SC_ENDURE]->val1 : 1;
  6283. if(sc->data[SC_STONEHARDSKIN])
  6284. mdef += sc->data[SC_STONEHARDSKIN]->val1;
  6285. if(sc->data[SC_STONE])
  6286. mdef += 25 * mdef / 100;
  6287. if(sc->data[SC_FREEZE])
  6288. mdef += 25 * mdef / 100;
  6289. if(sc->data[SC_BURNING])
  6290. mdef -= 25 * mdef / 100;
  6291. if( sc->data[SC_NEUTRALBARRIER] )
  6292. mdef += mdef * sc->data[SC_NEUTRALBARRIER]->val2 / 100;
  6293. if(sc->data[SC_ANALYZE])
  6294. mdef -= mdef * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100;
  6295. if(sc->data[SC_SYMPHONYOFLOVER])
  6296. mdef += mdef * sc->data[SC_SYMPHONYOFLOVER]->val3 / 100;
  6297. if (sc->data[SC_ODINS_POWER])
  6298. mdef -= 20 * sc->data[SC_ODINS_POWER]->val1;
  6299. if(sc->data[SC_GLASTHEIM_ITEMDEF])
  6300. mdef += sc->data[SC_GLASTHEIM_ITEMDEF]->val2;
  6301. if (sc->data[SC_SOULGOLEM])
  6302. mdef += sc->data[SC_SOULGOLEM]->val3;
  6303. if (sc->data[SC_STONE_WALL])
  6304. mdef += sc->data[SC_STONE_WALL]->val3;
  6305. if (sc->data[SC_PACKING_ENVELOPE8])
  6306. mdef += sc->data[SC_PACKING_ENVELOPE8]->val1;
  6307. if (sc->data[SC_CLIMAX_CRYIMP])
  6308. mdef += 100;
  6309. return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX);
  6310. }
  6311. /**
  6312. * Adds magic defense (right-side) modifications based on status changes
  6313. * @param bl: Object to change mdef2 [PC|MOB|HOM|MER|ELEM]
  6314. * @param sc: Object's status change information
  6315. * @param mdef2: Initial mdef2
  6316. * @return modified mdef2 with cap_value(mdef2,SHRT_MIN,SHRT_MAX)
  6317. */
  6318. static signed short status_calc_mdef2(struct block_list *bl, struct status_change *sc, int mdef2)
  6319. {
  6320. if(!sc || !sc->count)
  6321. #ifdef RENEWAL
  6322. return (short)cap_value(mdef2,SHRT_MIN,SHRT_MAX);
  6323. #else
  6324. return (short)cap_value(mdef2,1,SHRT_MAX);
  6325. #endif
  6326. if(sc->data[SC_BERSERK])
  6327. return 0;
  6328. if(sc->data[SC_SKA])
  6329. return 90;
  6330. if(sc->data[SC_MDEFSET])
  6331. return sc->data[SC_MDEFSET]->val1;
  6332. if(sc->data[SC_MINDBREAKER])
  6333. mdef2 -= mdef2 * sc->data[SC_MINDBREAKER]->val3/100;
  6334. if(sc->data[SC_BURNING])
  6335. mdef2 -= mdef2 * 25 / 100;
  6336. if(sc->data[SC_ANALYZE])
  6337. mdef2 -= mdef2 * (14 * sc->data[SC_ANALYZE]->val1) / 100;
  6338. #ifdef RENEWAL
  6339. return (short)cap_value(mdef2,SHRT_MIN,SHRT_MAX);
  6340. #else
  6341. return (short)cap_value(mdef2,1,SHRT_MAX);
  6342. #endif
  6343. }
  6344. /**
  6345. * Adds speed modifications based on status changes
  6346. * @param bl: Object to change speed [PC|MOB|HOM|MER|ELEM]
  6347. * @param sc: Object's status change information
  6348. * @param speed: Initial speed
  6349. * @return modified speed with cap_value(speed,10,USHRT_MAX)
  6350. */
  6351. static unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc, int speed)
  6352. {
  6353. TBL_PC* sd = BL_CAST(BL_PC, bl);
  6354. int speed_rate = 100;
  6355. if (sc == NULL || (sd && sd->state.permanent_speed))
  6356. return (unsigned short)cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED);
  6357. if (sd && pc_ismadogear(sd)) { // Mado speed is not affected by other statuses
  6358. int val = 0;
  6359. if (pc_checkskill(sd, NC_MADOLICENCE) < 5)
  6360. val = 50 - 10 * pc_checkskill(sd, NC_MADOLICENCE);
  6361. else
  6362. val -= 25;
  6363. if (sc->data[SC_ACCELERATION])
  6364. val -= 25;
  6365. speed += speed * val / 100;
  6366. return (unsigned short)cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED);
  6367. }
  6368. if( sd && sd->ud.skilltimer != INVALID_TIMER && (pc_checkskill(sd,SA_FREECAST) > 0 || sd->ud.skill_id == LG_EXEEDBREAK) ) {
  6369. if( sd->ud.skill_id == LG_EXEEDBREAK )
  6370. speed_rate = 160 - 10 * sd->ud.skill_lv;
  6371. else
  6372. speed_rate = 175 - 5 * pc_checkskill(sd,SA_FREECAST);
  6373. } else {
  6374. int val = 0;
  6375. // GetMoveHasteValue2()
  6376. if( sc->data[SC_FUSION] )
  6377. val = 25;
  6378. else if( sd ) {
  6379. if( pc_isriding(sd) || sd->sc.option&OPTION_DRAGON )
  6380. val = 25; // Same bonus
  6381. else if( pc_isridingwug(sd) )
  6382. val = 15 + 5 * pc_checkskill(sd, RA_WUGRIDER);
  6383. else if( sc->data[SC_ALL_RIDING] )
  6384. val = battle_config.rental_mount_speed_boost;
  6385. }
  6386. speed_rate -= val;
  6387. // GetMoveSlowValue()
  6388. if( sd && sc->data[SC_HIDING] && pc_checkskill(sd,RG_TUNNELDRIVE) > 0 )
  6389. val = 120 - 6 * pc_checkskill(sd,RG_TUNNELDRIVE);
  6390. else if( sd && sc->data[SC_CHASEWALK] && sc->data[SC_CHASEWALK]->val3 < 0 )
  6391. val = sc->data[SC_CHASEWALK]->val3;
  6392. else {
  6393. val = 0;
  6394. // Longing for Freedom/Special Singer cancels song/dance penalty
  6395. #ifdef RENEWAL
  6396. if (sc->data[SC_ENSEMBLEFATIGUE])
  6397. val = max(val, sc->data[SC_ENSEMBLEFATIGUE]->val2);
  6398. #else
  6399. if( sc->data[SC_LONGING] )
  6400. val = max( val, 50 - 10 * sc->data[SC_LONGING]->val1 );
  6401. #endif
  6402. else
  6403. if( sd && sc->data[SC_DANCING] )
  6404. val = max( val, 500 - (40 + 10 * (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER)) * pc_checkskill(sd,(sd->status.sex?BA_MUSICALLESSON:DC_DANCINGLESSON)) );
  6405. if( sc->data[SC_DECREASEAGI] )
  6406. val = max( val, 25 );
  6407. if( sc->data[SC_QUAGMIRE] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY] || (sc->data[SC_GLOOMYDAY] && sc->data[SC_GLOOMYDAY]->val4) )
  6408. val = max( val, 50 );
  6409. if( sc->data[SC_DONTFORGETME] )
  6410. val = max( val, sc->data[SC_DONTFORGETME]->val3 );
  6411. if( sc->data[SC_CURSE] )
  6412. val = max( val, 300 );
  6413. if( sc->data[SC_CHASEWALK] )
  6414. val = max( val, sc->data[SC_CHASEWALK]->val3 );
  6415. if( sc->data[SC_WEDDING] )
  6416. val = max( val, 100 );
  6417. if( sc->data[SC_JOINTBEAT] && sc->data[SC_JOINTBEAT]->val2&(BREAK_ANKLE|BREAK_KNEE) )
  6418. val = max( val, (sc->data[SC_JOINTBEAT]->val2&BREAK_ANKLE ? 50 : 0) + (sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE ? 30 : 0) );
  6419. if( sc->data[SC_CLOAKING] && (sc->data[SC_CLOAKING]->val4&1) == 0 )
  6420. val = max( val, sc->data[SC_CLOAKING]->val1 < 3 ? 300 : 30 - 3 * sc->data[SC_CLOAKING]->val1 );
  6421. if( sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_ENEMY )
  6422. val = max( val, 75 );
  6423. if( sc->data[SC_SLOWDOWN] ) // Slow Potion
  6424. val = max( val, sc->data[SC_SLOWDOWN]->val1 );
  6425. if( sc->data[SC_GATLINGFEVER] )
  6426. val = max( val, 100 );
  6427. if( sc->data[SC_SUITON] )
  6428. val = max( val, sc->data[SC_SUITON]->val3 );
  6429. if( sc->data[SC_SWOO] )
  6430. val = max( val, 300 );
  6431. if( sc->data[SC_SKA] )
  6432. val = max( val, 25 );
  6433. if( sc->data[SC_FREEZING] )
  6434. val = max( val, 30 );
  6435. if( sc->data[SC_MARSHOFABYSS] )
  6436. val = max( val, sc->data[SC_MARSHOFABYSS]->val3 );
  6437. if( sc->data[SC_CAMOUFLAGE] && sc->data[SC_CAMOUFLAGE]->val1 > 2 )
  6438. val = max( val, 25 * (5 - sc->data[SC_CAMOUFLAGE]->val1) );
  6439. if( sc->data[SC_STEALTHFIELD] )
  6440. val = max( val, 20 );
  6441. if( sc->data[SC__LAZINESS] )
  6442. val = max( val, 25 );
  6443. if( sc->data[SC_ROCK_CRUSHER_ATK] )
  6444. val = max( val, sc->data[SC_ROCK_CRUSHER_ATK]->val2 );
  6445. if( sc->data[SC_POWER_OF_GAIA] )
  6446. val = max( val, sc->data[SC_POWER_OF_GAIA]->val2 );
  6447. if( sc->data[SC_MELON_BOMB] )
  6448. val = max( val, sc->data[SC_MELON_BOMB]->val2 );
  6449. if( sc->data[SC_REBOUND] )
  6450. val = max( val, 25 );
  6451. if( sc->data[SC_B_TRAP] )
  6452. val = max( val, sc->data[SC_B_TRAP]->val3 );
  6453. if (sc->data[SC_CATNIPPOWDER])
  6454. val = max(val, sc->data[SC_CATNIPPOWDER]->val3);
  6455. if (sc->data[SC_SP_SHA])
  6456. val = max(val, sc->data[SC_SP_SHA]->val2);
  6457. if (sc->data[SC_CREATINGSTAR])
  6458. val = max(val, 90);
  6459. if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate > 0 ) // Permanent item-based speedup
  6460. val = max( val, sd->bonus.speed_rate + sd->bonus.speed_add_rate );
  6461. }
  6462. speed_rate += val;
  6463. val = 0;
  6464. if( sc->data[SC_MARSHOFABYSS] && speed_rate > 150 )
  6465. speed_rate = 150;
  6466. // GetMoveHasteValue1()
  6467. if( sc->data[SC_SPEEDUP1] ) // !FIXME: used both by NPC_AGIUP and Speed Potion script
  6468. val = max( val, sc->data[SC_SPEEDUP1]->val1 );
  6469. if( sc->data[SC_INCREASEAGI] )
  6470. val = max( val, 25 );
  6471. if( sc->data[SC_WINDWALK] )
  6472. val = max( val, 2 * sc->data[SC_WINDWALK]->val1 );
  6473. if( sc->data[SC_CARTBOOST] )
  6474. val = max( val, 20 );
  6475. if( sd && (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN && pc_checkskill(sd,TF_MISS) > 0 )
  6476. val = max( val, 1 * pc_checkskill(sd,TF_MISS) );
  6477. if( sc->data[SC_CLOAKING] && (sc->data[SC_CLOAKING]->val4&1) == 1 )
  6478. val = max( val, sc->data[SC_CLOAKING]->val1 >= 10 ? 25 : 3 * sc->data[SC_CLOAKING]->val1 - 3 );
  6479. if( sc->data[SC_BERSERK] )
  6480. val = max( val, 25 );
  6481. if( sc->data[SC_RUN] )
  6482. val = max( val, 55 );
  6483. if( sc->data[SC_AVOID] )
  6484. val = max( val, 10 * sc->data[SC_AVOID]->val1 );
  6485. if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
  6486. val = max( val, 75 );
  6487. if( sc->data[SC_CLOAKINGEXCEED] )
  6488. val = max( val, sc->data[SC_CLOAKINGEXCEED]->val3);
  6489. if (sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 0)
  6490. val = max(val, 50);
  6491. if( sc->data[SC_HOVERING] )
  6492. val = max( val, 10 );
  6493. if( sc->data[SC_GN_CARTBOOST] )
  6494. val = max( val, sc->data[SC_GN_CARTBOOST]->val2 );
  6495. if( sc->data[SC_SWINGDANCE] )
  6496. val = max( val, sc->data[SC_SWINGDANCE]->val3 );
  6497. if( sc->data[SC_WIND_STEP_OPTION] )
  6498. val = max( val, sc->data[SC_WIND_STEP_OPTION]->val2 );
  6499. if( sc->data[SC_FULL_THROTTLE] )
  6500. val = max( val, 25 );
  6501. if (sc->data[SC_ARCLOUSEDASH])
  6502. val = max(val, sc->data[SC_ARCLOUSEDASH]->val3);
  6503. if( sc->data[SC_DORAM_WALKSPEED] )
  6504. val = max(val, sc->data[SC_DORAM_WALKSPEED]->val1);
  6505. if (sc->data[SC_RUSHWINDMILL])
  6506. val = max(val, 25); // !TODO: Confirm bonus movement speed
  6507. if (sc->data[SC_EMERGENCY_MOVE])
  6508. val = max(val, sc->data[SC_EMERGENCY_MOVE]->val2);
  6509. if( sc->data[SC_JAWAII_SERENADE] ){
  6510. val = max( val, 25 );
  6511. }
  6512. // !FIXME: official items use a single bonus for this [ultramage]
  6513. if( sc->data[SC_SPEEDUP0] ) // Temporary item-based speedup
  6514. val = max( val, sc->data[SC_SPEEDUP0]->val1 );
  6515. if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate < 0 ) // Permanent item-based speedup
  6516. val = max( val, -(sd->bonus.speed_rate + sd->bonus.speed_add_rate) );
  6517. speed_rate -= val;
  6518. if( speed_rate < 40 )
  6519. speed_rate = 40;
  6520. }
  6521. // GetSpeed()
  6522. if( sd && pc_iscarton(sd) )
  6523. speed += speed * (50 - 5 * pc_checkskill(sd,MC_PUSHCART)) / 100;
  6524. if( sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 1 )
  6525. speed += speed * 50 / 100;
  6526. if( speed_rate != 100 )
  6527. speed = speed * speed_rate / 100;
  6528. if( sc->data[SC_STEELBODY] )
  6529. speed = 200;
  6530. if( sc->data[SC_DEFENDER] )
  6531. speed = max(speed, 200);
  6532. if( sc->data[SC_WALKSPEED] && sc->data[SC_WALKSPEED]->val1 > 0 ) // ChangeSpeed
  6533. speed = speed * 100 / sc->data[SC_WALKSPEED]->val1;
  6534. return (unsigned short)cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED);
  6535. }
  6536. #ifdef RENEWAL_ASPD
  6537. /**
  6538. * Renewal attack speed modifiers based on status changes
  6539. * This function only affects RENEWAL players and comes after base calculation
  6540. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  6541. * @param sc: Object's status change information
  6542. * @param fixed: True - fixed value [malufett]
  6543. * False - percentage value
  6544. * @return modified aspd
  6545. */
  6546. static short status_calc_aspd(struct block_list *bl, struct status_change *sc, bool fixed)
  6547. {
  6548. int bonus = 0;
  6549. if (!sc || !sc->count)
  6550. return 0;
  6551. if (fixed) {
  6552. enum sc_type sc_val;
  6553. if (!sc->data[SC_QUAGMIRE]) {
  6554. // !TODO: How does Two-Hand Quicken, Adrenaline Rush, and Spear quick change? (+10%)
  6555. if (bonus < 7 && (sc->data[SC_TWOHANDQUICKEN] || sc->data[SC_ONEHAND] || sc->data[SC_MERC_QUICKEN] || sc->data[SC_ADRENALINE] || sc->data[SC_SPEARQUICKEN]))
  6556. bonus = 7;
  6557. else if (bonus < 6 && sc->data[SC_ADRENALINE2])
  6558. bonus = 6;
  6559. else if (bonus < 5 && sc->data[SC_FLEET])
  6560. bonus = 5;
  6561. }
  6562. if (sc->data[SC_ASSNCROS] && bonus < sc->data[SC_ASSNCROS]->val2) {
  6563. #ifdef RENEWAL
  6564. bonus += sc->data[SC_ASSNCROS]->val2;
  6565. #else
  6566. if (bl->type != BL_PC)
  6567. bonus += sc->data[SC_ASSNCROS]->val2;
  6568. else {
  6569. switch(((TBL_PC*)bl)->status.weapon) {
  6570. case W_BOW:
  6571. case W_REVOLVER:
  6572. case W_RIFLE:
  6573. case W_GATLING:
  6574. case W_SHOTGUN:
  6575. case W_GRENADE:
  6576. break;
  6577. default:
  6578. bonus += sc->data[SC_ASSNCROS]->val2;
  6579. break;
  6580. }
  6581. }
  6582. #endif
  6583. }
  6584. if (bonus < 20 && sc->data[SC_MADNESSCANCEL])
  6585. bonus = 20;
  6586. else if (bonus < 15 && sc->data[SC_BERSERK])
  6587. bonus = 15;
  6588. if (sc->data[sc_val = SC_ASPDPOTION3] || sc->data[sc_val = SC_ASPDPOTION2] || sc->data[sc_val = SC_ASPDPOTION1] || sc->data[sc_val = SC_ASPDPOTION0])
  6589. bonus += sc->data[sc_val]->val1;
  6590. if (sc->data[SC_ATTHASTE_CASH])
  6591. bonus += sc->data[SC_ATTHASTE_CASH]->val1;
  6592. } else {
  6593. if (sc->data[SC_DONTFORGETME])
  6594. bonus -= sc->data[SC_DONTFORGETME]->val2 / 10;
  6595. #ifdef RENEWAL
  6596. if (sc->data[SC_ENSEMBLEFATIGUE])
  6597. bonus -= sc->data[SC_ENSEMBLEFATIGUE]->val2 / 10;
  6598. #else
  6599. if (sc->data[SC_LONGING])
  6600. bonus -= sc->data[SC_LONGING]->val2 / 10;
  6601. #endif
  6602. if (sc->data[SC_STEELBODY])
  6603. bonus -= 25;
  6604. if (sc->data[SC_SKA])
  6605. bonus -= 25;
  6606. if (sc->data[SC_DEFENDER])
  6607. bonus -= sc->data[SC_DEFENDER]->val4 / 10;
  6608. if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_ENEMY)
  6609. bonus -= 75;
  6610. #ifndef RENEWAL
  6611. if (sc->data[SC_GRAVITATION])
  6612. bonus -= sc->data[SC_GRAVITATION]->val2 / 10; // Needs more info
  6613. #endif
  6614. if (sc->data[SC_JOINTBEAT]) { // Needs more info
  6615. if (sc->data[SC_JOINTBEAT]->val2&BREAK_WRIST)
  6616. bonus -= 25;
  6617. if (sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE)
  6618. bonus -= 10;
  6619. }
  6620. if (sc->data[SC_FREEZING])
  6621. bonus -= 30;
  6622. if (sc->data[SC_HALLUCINATIONWALK_POSTDELAY])
  6623. bonus -= 50;
  6624. if (sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 1)
  6625. bonus -= 10;
  6626. if (sc->data[SC__BODYPAINT])
  6627. bonus -= 5 * sc->data[SC__BODYPAINT]->val1;
  6628. if (sc->data[SC__INVISIBILITY])
  6629. bonus -= sc->data[SC__INVISIBILITY]->val2;
  6630. if (sc->data[SC__GROOMY])
  6631. bonus -= sc->data[SC__GROOMY]->val2;
  6632. if (sc->data[SC_SWINGDANCE])
  6633. bonus += sc->data[SC_SWINGDANCE]->val3;
  6634. if (sc->data[SC_DANCEWITHWUG])
  6635. bonus += sc->data[SC_DANCEWITHWUG]->val3;
  6636. if (sc->data[SC_GLOOMYDAY])
  6637. bonus -= sc->data[SC_GLOOMYDAY]->val3;
  6638. if (sc->data[SC_GT_CHANGE])
  6639. bonus += sc->data[SC_GT_CHANGE]->val3;
  6640. if (sc->data[SC_MELON_BOMB])
  6641. bonus -= sc->data[SC_MELON_BOMB]->val3;
  6642. if (sc->data[SC_BOOST500])
  6643. bonus += sc->data[SC_BOOST500]->val1;
  6644. if (sc->data[SC_EXTRACT_SALAMINE_JUICE])
  6645. bonus += sc->data[SC_EXTRACT_SALAMINE_JUICE]->val1;
  6646. if (sc->data[SC_GOLDENE_FERSE])
  6647. bonus += sc->data[SC_GOLDENE_FERSE]->val3;
  6648. if (sc->data[SC_INCASPDRATE])
  6649. bonus += sc->data[SC_INCASPDRATE]->val1;
  6650. if (sc->data[SC_GATLINGFEVER])
  6651. bonus += sc->data[SC_GATLINGFEVER]->val1;
  6652. if (sc->data[SC_STAR_COMFORT])
  6653. bonus += 3 * sc->data[SC_STAR_COMFORT]->val1;
  6654. if (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2)
  6655. bonus += 10;
  6656. if (sc->data[SC_INCREASEAGI])
  6657. bonus += sc->data[SC_INCREASEAGI]->val1;
  6658. if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ASPDRATE)
  6659. bonus += 20;
  6660. if (sc->data[SC_STARSTANCE])
  6661. bonus += sc->data[SC_STARSTANCE]->val2;
  6662. struct map_session_data* sd = BL_CAST(BL_PC, bl);
  6663. uint8 skill_lv;
  6664. if (sd && (skill_lv = pc_checkskill(sd, BA_MUSICALLESSON)) > 0)
  6665. bonus += skill_lv;
  6666. }
  6667. return bonus;
  6668. }
  6669. #endif
  6670. /**
  6671. * Modifies ASPD by a number, rather than a percentage (10 = 1 ASPD)
  6672. * A subtraction reduces the delay, meaning an increase in ASPD
  6673. * This comes after the percentage changes and is based on status changes
  6674. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  6675. * @param sc: Object's status change information
  6676. * @param aspd: Object's current ASPD
  6677. * @return modified aspd
  6678. */
  6679. static short status_calc_fix_aspd(struct block_list *bl, struct status_change *sc, int aspd)
  6680. {
  6681. if (!sc || !sc->count)
  6682. return cap_value(aspd, 0, 2000);
  6683. if (sc->data[SC_OVERED_BOOST])
  6684. return cap_value(2000 - sc->data[SC_OVERED_BOOST]->val3 * 10, 0, 2000);
  6685. if ((sc->data[SC_GUST_OPTION] || sc->data[SC_BLAST_OPTION] || sc->data[SC_WILD_STORM_OPTION]))
  6686. aspd -= 50; // +5 ASPD
  6687. if (sc->data[SC_FIGHTINGSPIRIT])
  6688. aspd -= sc->data[SC_FIGHTINGSPIRIT]->val2;
  6689. if (sc->data[SC_MTF_ASPD])
  6690. aspd -= sc->data[SC_MTF_ASPD]->val1;
  6691. if (sc->data[SC_MTF_ASPD2])
  6692. aspd -= sc->data[SC_MTF_ASPD2]->val1;
  6693. if (sc->data[SC_SOULSHADOW])
  6694. aspd -= 10 * sc->data[SC_SOULSHADOW]->val2;
  6695. if (sc->data[SC_HEAT_BARREL])
  6696. aspd -= sc->data[SC_HEAT_BARREL]->val1 * 10;
  6697. if (sc->data[SC_EP16_2_BUFF_SS])
  6698. aspd -= 100; // +10 ASPD
  6699. if (sc->data[SC_PACKING_ENVELOPE6])
  6700. aspd -= sc->data[SC_PACKING_ENVELOPE6]->val1 * 10;
  6701. if (sc->data[SC_SINCERE_FAITH])
  6702. aspd -= 10 * sc->data[SC_SINCERE_FAITH]->val2;
  6703. return cap_value(aspd, 0, 2000); // Will be recap for proper bl anyway
  6704. }
  6705. /**
  6706. * Calculates an object's ASPD modifier based on status changes (alters amotion value)
  6707. * Note: The scale of aspd_rate is 1000 = 100%
  6708. * Note2: This only affects Homunculus, Mercenaries, and Pre-renewal Players
  6709. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  6710. * @param sc: Object's status change information
  6711. * @param aspd_rate: Object's current ASPD
  6712. * @return modified aspd_rate
  6713. */
  6714. static short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int aspd_rate)
  6715. {
  6716. int i;
  6717. if(!sc || !sc->count)
  6718. return cap_value(aspd_rate,0,SHRT_MAX);
  6719. if( !sc->data[SC_QUAGMIRE] ) {
  6720. int max = 0;
  6721. if(sc->data[SC_STAR_COMFORT])
  6722. max = sc->data[SC_STAR_COMFORT]->val2;
  6723. if(sc->data[SC_TWOHANDQUICKEN] &&
  6724. max < sc->data[SC_TWOHANDQUICKEN]->val2)
  6725. max = sc->data[SC_TWOHANDQUICKEN]->val2;
  6726. if(sc->data[SC_ONEHAND] &&
  6727. max < sc->data[SC_ONEHAND]->val2)
  6728. max = sc->data[SC_ONEHAND]->val2;
  6729. if(sc->data[SC_MERC_QUICKEN] &&
  6730. max < sc->data[SC_MERC_QUICKEN]->val2)
  6731. max = sc->data[SC_MERC_QUICKEN]->val2;
  6732. if(sc->data[SC_ADRENALINE2] &&
  6733. max < sc->data[SC_ADRENALINE2]->val3)
  6734. max = sc->data[SC_ADRENALINE2]->val3;
  6735. if(sc->data[SC_ADRENALINE] &&
  6736. max < sc->data[SC_ADRENALINE]->val3)
  6737. max = sc->data[SC_ADRENALINE]->val3;
  6738. if(sc->data[SC_SPEARQUICKEN] &&
  6739. max < sc->data[SC_SPEARQUICKEN]->val2)
  6740. max = sc->data[SC_SPEARQUICKEN]->val2;
  6741. if(sc->data[SC_GATLINGFEVER] &&
  6742. max < sc->data[SC_GATLINGFEVER]->val2)
  6743. max = sc->data[SC_GATLINGFEVER]->val2;
  6744. if(sc->data[SC_FLEET] &&
  6745. max < sc->data[SC_FLEET]->val2)
  6746. max = sc->data[SC_FLEET]->val2;
  6747. if(sc->data[SC_ASSNCROS] && max < sc->data[SC_ASSNCROS]->val2) {
  6748. if (bl->type!=BL_PC)
  6749. max = sc->data[SC_ASSNCROS]->val2;
  6750. else
  6751. switch(((TBL_PC*)bl)->status.weapon) {
  6752. case W_BOW:
  6753. case W_REVOLVER:
  6754. case W_RIFLE:
  6755. case W_GATLING:
  6756. case W_SHOTGUN:
  6757. case W_GRENADE:
  6758. break;
  6759. default:
  6760. max = sc->data[SC_ASSNCROS]->val2;
  6761. }
  6762. }
  6763. aspd_rate -= max;
  6764. if(sc->data[SC_BERSERK])
  6765. aspd_rate -= 300;
  6766. else if(sc->data[SC_MADNESSCANCEL])
  6767. aspd_rate -= 200;
  6768. }
  6769. if( sc->data[i=SC_ASPDPOTION3] ||
  6770. sc->data[i=SC_ASPDPOTION2] ||
  6771. sc->data[i=SC_ASPDPOTION1] ||
  6772. sc->data[i=SC_ASPDPOTION0] )
  6773. aspd_rate -= sc->data[i]->val2;
  6774. if (sc->data[SC_ATTHASTE_CASH])
  6775. aspd_rate -= sc->data[SC_ATTHASTE_CASH]->val2;
  6776. if(sc->data[SC_DONTFORGETME])
  6777. aspd_rate += sc->data[SC_DONTFORGETME]->val2;
  6778. #ifdef RENEWAL
  6779. if (sc->data[SC_ENSEMBLEFATIGUE])
  6780. aspd_rate += sc->data[SC_ENSEMBLEFATIGUE]->val2;
  6781. #else
  6782. if(sc->data[SC_LONGING])
  6783. aspd_rate += sc->data[SC_LONGING]->val2;
  6784. #endif
  6785. if(sc->data[SC_STEELBODY])
  6786. aspd_rate += 250;
  6787. if(sc->data[SC_SKA])
  6788. aspd_rate += 250;
  6789. if(sc->data[SC_DEFENDER])
  6790. aspd_rate += sc->data[SC_DEFENDER]->val4;
  6791. if(sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_ENEMY)
  6792. aspd_rate += 250;
  6793. #ifndef RENEWAL
  6794. if(sc->data[SC_GRAVITATION])
  6795. aspd_rate += sc->data[SC_GRAVITATION]->val2;
  6796. #endif
  6797. if(sc->data[SC_JOINTBEAT]) {
  6798. if( sc->data[SC_JOINTBEAT]->val2&BREAK_WRIST )
  6799. aspd_rate += 250;
  6800. if( sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE )
  6801. aspd_rate += 100;
  6802. }
  6803. if( sc->data[SC_FREEZING] )
  6804. aspd_rate += 300;
  6805. if( sc->data[SC_HALLUCINATIONWALK_POSTDELAY] )
  6806. aspd_rate += 500;
  6807. if( sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 1 )
  6808. aspd_rate += 100;
  6809. if( sc->data[SC__BODYPAINT] )
  6810. aspd_rate += 50 * sc->data[SC__BODYPAINT]->val1;
  6811. if( sc->data[SC__INVISIBILITY] )
  6812. aspd_rate += sc->data[SC__INVISIBILITY]->val2 * 10;
  6813. if( sc->data[SC__GROOMY] )
  6814. aspd_rate += sc->data[SC__GROOMY]->val2 * 10;
  6815. if( sc->data[SC_SWINGDANCE] )
  6816. aspd_rate -= sc->data[SC_SWINGDANCE]->val3 * 10;
  6817. if( sc->data[SC_DANCEWITHWUG] )
  6818. aspd_rate -= sc->data[SC_DANCEWITHWUG]->val3 * 10;
  6819. if( sc->data[SC_GLOOMYDAY] )
  6820. aspd_rate += sc->data[SC_GLOOMYDAY]->val3 * 10;
  6821. if( sc->data[SC_GT_CHANGE] )
  6822. aspd_rate -= sc->data[SC_GT_CHANGE]->val3 * 10;
  6823. if( sc->data[SC_MELON_BOMB] )
  6824. aspd_rate += sc->data[SC_MELON_BOMB]->val3 * 10;
  6825. if( sc->data[SC_BOOST500] )
  6826. aspd_rate -= sc->data[SC_BOOST500]->val1 *10;
  6827. if( sc->data[SC_EXTRACT_SALAMINE_JUICE] )
  6828. aspd_rate -= sc->data[SC_EXTRACT_SALAMINE_JUICE]->val1 * 10;
  6829. if( sc->data[SC_INCASPDRATE] )
  6830. aspd_rate -= sc->data[SC_INCASPDRATE]->val1 * 10;
  6831. if( sc->data[SC_GOLDENE_FERSE])
  6832. aspd_rate -= sc->data[SC_GOLDENE_FERSE]->val3 * 10;
  6833. if (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2)
  6834. aspd_rate -= 100;
  6835. if (sc->data[SC_STARSTANCE])
  6836. aspd_rate -= 10 * sc->data[SC_STARSTANCE]->val2;
  6837. return (short)cap_value(aspd_rate,0,SHRT_MAX);
  6838. }
  6839. /**
  6840. * Modifies the damage delay time based on status changes
  6841. * The lower your delay, the quicker you can act after taking damage
  6842. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  6843. * @param sc: Object's status change information
  6844. * @param dmotion: Object's current damage delay
  6845. * @return modified delay rate
  6846. */
  6847. static unsigned short status_calc_dmotion(struct block_list *bl, struct status_change *sc, int dmotion)
  6848. {
  6849. /// It has been confirmed on official servers that MvP mobs have no dmotion even without endure
  6850. if( bl->type == BL_MOB && status_get_class_(bl) == CLASS_BOSS )
  6851. return 0;
  6852. if (bl->type == BL_PC) {
  6853. if (map_flag_gvg2(bl->m) || map_getmapflag(bl->m, MF_BATTLEGROUND))
  6854. return (unsigned short)cap_value(dmotion, 0, USHRT_MAX);
  6855. if (((TBL_PC *)bl)->special_state.no_walk_delay)
  6856. return 0;
  6857. }
  6858. if (sc && sc->count > 0 && (sc->data[SC_ENDURE] || sc->data[SC_RUN] || sc->data[SC_WUGDASH]))
  6859. return 0;
  6860. return (unsigned short)cap_value(dmotion,0,USHRT_MAX);
  6861. }
  6862. /**
  6863. * Adds power atk modifications based on status changes
  6864. * @param bl: Object to change patk [PC|MOB|HOM|MER|ELEM]
  6865. * @param sc: Object's status change information
  6866. * @param patk: Initial patk
  6867. * @return modified patk with cap_value(patk,0,USHRT_MAX)
  6868. */
  6869. static signed short status_calc_patk(struct block_list *bl, struct status_change *sc, int patk)
  6870. {
  6871. if (!sc || !sc->count)
  6872. return cap_value(patk, 0, SHRT_MAX);
  6873. if (sc->data[SC_POWERFUL_FAITH])
  6874. patk += sc->data[SC_POWERFUL_FAITH]->val3;
  6875. if (sc->data[SC_COMPETENTIA])
  6876. patk += sc->data[SC_COMPETENTIA]->val2;
  6877. if (sc->data[SC_ABYSS_SLAYER])
  6878. patk += sc->data[SC_ABYSS_SLAYER]->val2;
  6879. if (sc->data[SC_PRON_MARCH])
  6880. patk += sc->data[SC_PRON_MARCH]->val2;
  6881. return (short)cap_value(patk, 0, SHRT_MAX);
  6882. }
  6883. /**
  6884. * Adds spell matk modifications based on status changes
  6885. * @param bl: Object to change smatk [PC|MOB|HOM|MER|ELEM]
  6886. * @param sc: Object's status change information
  6887. * @param smatk: Initial smatk
  6888. * @return modified smatk with cap_value(smatk,0,USHRT_MAX)
  6889. */
  6890. static signed short status_calc_smatk(struct block_list *bl, struct status_change *sc, int smatk)
  6891. {
  6892. if (!sc || !sc->count)
  6893. return cap_value(smatk, 0, SHRT_MAX);
  6894. if (sc->data[SC_COMPETENTIA])
  6895. smatk += sc->data[SC_COMPETENTIA]->val2;
  6896. if (sc->data[SC_ABYSS_SLAYER])
  6897. smatk += sc->data[SC_ABYSS_SLAYER]->val2;
  6898. if (sc->data[SC_JAWAII_SERENADE])
  6899. smatk += sc->data[SC_JAWAII_SERENADE]->val2;
  6900. if (sc->data[SC_SPELL_ENCHANTING])
  6901. smatk += sc->data[SC_SPELL_ENCHANTING]->val2;
  6902. return (short)cap_value(smatk, 0, SHRT_MAX);
  6903. }
  6904. /**
  6905. * Adds resist modifications based on status changes
  6906. * @param bl: Object to change res [PC|MOB|HOM|MER|ELEM]
  6907. * @param sc: Object's status change information
  6908. * @param res: Initial res
  6909. * @return modified res with cap_value(res,0,USHRT_MAX)
  6910. */
  6911. static signed short status_calc_res(struct block_list *bl, struct status_change *sc, int res)
  6912. {
  6913. if (!sc || !sc->count)
  6914. return cap_value(res, 0, SHRT_MAX);
  6915. if (sc->data[SC_FIRM_FAITH])
  6916. res += sc->data[SC_FIRM_FAITH]->val3;
  6917. if (sc->data[SC_D_MACHINE])
  6918. res += sc->data[SC_D_MACHINE]->val3;
  6919. if (sc->data[SC_MUSICAL_INTERLUDE])
  6920. res += sc->data[SC_MUSICAL_INTERLUDE]->val2;
  6921. if (sc->data[SC_SHADOW_STRIP] && bl->type != BL_PC)
  6922. res -= res * sc->data[SC_SHADOW_STRIP]->val2 / 100;
  6923. if (sc->data[SC_AIN_RHAPSODY])
  6924. res -= sc->data[SC_AIN_RHAPSODY]->val2;
  6925. return (short)cap_value(res, 0, SHRT_MAX);
  6926. }
  6927. /**
  6928. * Adds magic resist modifications based on status changes
  6929. * @param bl: Object to change mres [PC|MOB|HOM|MER|ELEM]
  6930. * @param sc: Object's status change information
  6931. * @param mres: Initial mres
  6932. * @return modified mres with cap_value(mres,0,USHRT_MAX)
  6933. */
  6934. static signed short status_calc_mres(struct block_list *bl, struct status_change *sc, int mres)
  6935. {
  6936. if (!sc || !sc->count)
  6937. return cap_value(mres, 0, SHRT_MAX);
  6938. if (sc->data[SC_SHADOW_STRIP] && bl->type != BL_PC)
  6939. mres -= mres * sc->data[SC_SHADOW_STRIP]->val2 / 100;
  6940. if (sc->data[SC_GEF_NOCTURN])
  6941. mres -= sc->data[SC_GEF_NOCTURN]->val2;
  6942. return (short)cap_value(mres, 0, SHRT_MAX);
  6943. }
  6944. /**
  6945. * Adds heal plus modifications based on status changes
  6946. * @param bl: Object to change hplus [PC|MOB|HOM|MER|ELEM]
  6947. * @param sc: Object's status change information
  6948. * @param hplus: Initial hplus
  6949. * @return modified hplus with cap_value(hplus,0,USHRT_MAX)
  6950. */
  6951. static signed short status_calc_hplus(struct block_list *bl, struct status_change *sc, int hplus)
  6952. {
  6953. if (!sc || !sc->count)
  6954. return cap_value(hplus, 0, SHRT_MAX);
  6955. return (short)cap_value(hplus, 0, SHRT_MAX);
  6956. }
  6957. /**
  6958. * Adds critical damage rate modifications based on status changes
  6959. * @param bl: Object to change crate [PC|MOB|HOM|MER|ELEM]
  6960. * @param sc: Object's status change information
  6961. * @param crate: Initial crate
  6962. * @return modified crate with cap_value(crate,0,USHRT_MAX)
  6963. */
  6964. static signed short status_calc_crate(struct block_list *bl, struct status_change *sc, int crate)
  6965. {
  6966. if (!sc || !sc->count)
  6967. return cap_value(crate, 0, SHRT_MAX);
  6968. if (sc->data[SC_PRE_ACIES])
  6969. crate += sc->data[SC_PRE_ACIES]->val2;
  6970. return (short)cap_value(crate, 0, SHRT_MAX);
  6971. }
  6972. /**
  6973. * Calculates a max HP based on status changes
  6974. * Values can either be percentages or fixed, based on how equations are formulated
  6975. * @param bl: Object's block_list data
  6976. * @param maxhp: Object's current max HP
  6977. * @return modified maxhp
  6978. */
  6979. static unsigned int status_calc_maxhp(struct block_list *bl, uint64 maxhp)
  6980. {
  6981. int rate = 100;
  6982. maxhp += status_get_hpbonus(bl,STATUS_BONUS_FIX);
  6983. if ((rate += status_get_hpbonus(bl,STATUS_BONUS_RATE)) != 100)
  6984. maxhp = maxhp * rate / 100;
  6985. return (unsigned int)cap_value(maxhp,1,UINT_MAX);
  6986. }
  6987. /**
  6988. * Calculates a max SP based on status changes
  6989. * Values can either be percentages or fixed, bas ed on how equations are formulated
  6990. * @param bl: Object's block_list data
  6991. * @param maxsp: Object's current max SP
  6992. * @return modified maxsp
  6993. */
  6994. static unsigned int status_calc_maxsp(struct block_list *bl, uint64 maxsp)
  6995. {
  6996. int rate = 100;
  6997. maxsp += status_get_spbonus(bl,STATUS_BONUS_FIX);
  6998. if ((rate += status_get_spbonus(bl,STATUS_BONUS_RATE)) != 100)
  6999. maxsp = maxsp * rate / 100;
  7000. return (unsigned int)cap_value(maxsp,1,UINT_MAX);
  7001. }
  7002. /**
  7003. * Calculates a max AP based on status changes
  7004. * Values can either be percentages or fixed, bas ed on how equations are formulated
  7005. * @param bl: Object's block_list data
  7006. * @param maxap: Object's current max AP
  7007. * @return modified maxap
  7008. */
  7009. static unsigned int status_calc_maxap(struct block_list *bl, uint64 maxap)
  7010. {
  7011. int rate = 100;
  7012. maxap += status_get_apbonus(bl, STATUS_BONUS_FIX);
  7013. if ((rate += status_get_apbonus(bl, STATUS_BONUS_RATE)) != 100)
  7014. maxap = maxap * rate / 100;
  7015. return (unsigned int)cap_value(maxap, 0, UINT_MAX);
  7016. }
  7017. /**
  7018. * Changes a player's element based on status changes
  7019. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  7020. * @param sc: Object's status change information
  7021. * @param element: Object's current element
  7022. * @return new element
  7023. */
  7024. static unsigned char status_calc_element(struct block_list *bl, struct status_change *sc, int element)
  7025. {
  7026. if(!sc || !sc->count)
  7027. return cap_value(element, 0, UCHAR_MAX);
  7028. if(sc->data[SC_FREEZE] || sc->data[SC_CRYSTAL_ARMOR_OPTION])
  7029. return ELE_WATER;
  7030. if(sc->data[SC_STONE] || sc->data[SC_STRONG_PROTECTION_OPTION])
  7031. return ELE_EARTH;
  7032. if(sc->data[SC_FLAMEARMOR_OPTION])
  7033. return ELE_FIRE;
  7034. if(sc->data[SC_EYES_OF_STORM_OPTION])
  7035. return ELE_WIND;
  7036. if(sc->data[SC_POISON_SHIELD_OPTION])
  7037. return ELE_POISON;
  7038. if(sc->data[SC_BENEDICTIO])
  7039. return ELE_HOLY;
  7040. if(sc->data[SC_CHANGEUNDEAD])
  7041. return ELE_UNDEAD;
  7042. if(sc->data[SC_ELEMENTALCHANGE])
  7043. return sc->data[SC_ELEMENTALCHANGE]->val2;
  7044. if(sc->data[SC_SHAPESHIFT])
  7045. return sc->data[SC_SHAPESHIFT]->val2;
  7046. return (unsigned char)cap_value(element,0,UCHAR_MAX);
  7047. }
  7048. /**
  7049. * Changes a player's element level based on status changes
  7050. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  7051. * @param sc: Object's status change information
  7052. * @param lv: Object's current element level
  7053. * @return new element level
  7054. */
  7055. static unsigned char status_calc_element_lv(struct block_list *bl, struct status_change *sc, int lv)
  7056. {
  7057. if(!sc || !sc->count)
  7058. return cap_value(lv, 1, 4);
  7059. if(sc->data[SC_FREEZE])
  7060. return 1;
  7061. if(sc->data[SC_STONE])
  7062. return 1;
  7063. if(sc->data[SC_BENEDICTIO])
  7064. return 1;
  7065. if(sc->data[SC_CHANGEUNDEAD])
  7066. return 1;
  7067. if(sc->data[SC_ELEMENTALCHANGE])
  7068. return sc->data[SC_ELEMENTALCHANGE]->val1;
  7069. if(sc->data[SC_SHAPESHIFT])
  7070. return 1;
  7071. if(sc->data[SC__INVISIBILITY])
  7072. return 1;
  7073. if (sc->data[SC_FLAMEARMOR_OPTION] || sc->data[SC_CRYSTAL_ARMOR_OPTION] || sc->data[SC_EYES_OF_STORM_OPTION] ||
  7074. sc->data[SC_STRONG_PROTECTION_OPTION] || sc->data[SC_POISON_SHIELD_OPTION])
  7075. return 1;
  7076. return (unsigned char)cap_value(lv,1,4);
  7077. }
  7078. /**
  7079. * Changes a player's attack element based on status changes
  7080. * @param bl: Object to change aspd [PC|MOB|HOM|MER|ELEM]
  7081. * @param sc: Object's status change information
  7082. * @param element: Object's current attack element
  7083. * @return new attack element
  7084. */
  7085. unsigned char status_calc_attack_element(struct block_list *bl, struct status_change *sc, int element)
  7086. {
  7087. if(!sc || !sc->count)
  7088. return cap_value(element, 0, UCHAR_MAX);
  7089. if(sc->data[SC_ENCHANTARMS])
  7090. return sc->data[SC_ENCHANTARMS]->val1;
  7091. if(sc->data[SC_WATERWEAPON]
  7092. || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) )
  7093. return ELE_WATER;
  7094. if(sc->data[SC_EARTHWEAPON]
  7095. || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2) )
  7096. return ELE_EARTH;
  7097. if(sc->data[SC_FIREWEAPON]
  7098. || (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2) )
  7099. return ELE_FIRE;
  7100. if(sc->data[SC_WINDWEAPON]
  7101. || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2) )
  7102. return ELE_WIND;
  7103. if(sc->data[SC_ENCPOISON])
  7104. return ELE_POISON;
  7105. if(sc->data[SC_ASPERSIO])
  7106. return ELE_HOLY;
  7107. if(sc->data[SC_SHADOWWEAPON])
  7108. return ELE_DARK;
  7109. if(sc->data[SC_GHOSTWEAPON] || sc->data[SC__INVISIBILITY])
  7110. return ELE_GHOST;
  7111. if(sc->data[SC_TIDAL_WEAPON_OPTION] || sc->data[SC_TIDAL_WEAPON] )
  7112. return ELE_WATER;
  7113. return (unsigned char)cap_value(element,0,UCHAR_MAX);
  7114. }
  7115. /**
  7116. * Changes the mode of an object
  7117. * @param bl: Object whose mode to change [PC|MOB|PET|HOM|NPC]
  7118. * @param sc: Object's status change data
  7119. * @param mode: Original mode
  7120. * @return mode with cap_value(mode, 0, INT_MAX)
  7121. */
  7122. static int status_calc_mode(struct block_list *bl, struct status_change *sc, int mode)
  7123. {
  7124. if(!sc || !sc->count)
  7125. return cap_value(mode, MD_NONE,INT_MAX);
  7126. if(sc->data[SC_MODECHANGE]) {
  7127. if (sc->data[SC_MODECHANGE]->val2)
  7128. mode = (mode&~MD_MASK)|sc->data[SC_MODECHANGE]->val2; // Set mode
  7129. if (sc->data[SC_MODECHANGE]->val3)
  7130. mode = mode|sc->data[SC_MODECHANGE]->val3; // Add mode
  7131. if (sc->data[SC_MODECHANGE]->val4)
  7132. mode = mode&~sc->data[SC_MODECHANGE]->val4; // Del mode
  7133. }
  7134. return cap_value(mode, MD_NONE, INT_MAX);
  7135. }
  7136. /**
  7137. * Changes the mode of a slave mob
  7138. * @param md: Slave mob whose mode to change
  7139. * @param mmd: Master of slave mob
  7140. */
  7141. void status_calc_slave_mode(struct mob_data *md, struct mob_data *mmd)
  7142. {
  7143. switch (battle_config.slaves_inherit_mode) {
  7144. case 1: //Always aggressive
  7145. if (!status_has_mode(&md->status,MD_AGGRESSIVE))
  7146. sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 0);
  7147. break;
  7148. case 2: //Always passive
  7149. if (status_has_mode(&md->status,MD_AGGRESSIVE))
  7150. sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, 0, MD_AGGRESSIVE, 0);
  7151. break;
  7152. case 4: // Overwrite with slave mode
  7153. sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, MD_CANMOVE|MD_NORANDOMWALK|MD_CANATTACK, 0, 0, 0);
  7154. break;
  7155. default: //Copy master
  7156. if (status_has_mode(&mmd->status,MD_AGGRESSIVE))
  7157. sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 0);
  7158. else
  7159. sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, 0, MD_AGGRESSIVE, 0);
  7160. break;
  7161. }
  7162. }
  7163. /**
  7164. * Gets the name of the given bl
  7165. * @param bl: Object whose name to get [PC|MOB|PET|HOM|NPC]
  7166. * @return name or "Unknown" if any other bl->type than noted above
  7167. */
  7168. const char* status_get_name(struct block_list *bl)
  7169. {
  7170. nullpo_ret(bl);
  7171. switch (bl->type) {
  7172. case BL_PC: return ((TBL_PC *)bl)->fakename[0] != '\0' ? ((TBL_PC*)bl)->fakename : ((TBL_PC*)bl)->status.name;
  7173. case BL_MOB: return ((TBL_MOB*)bl)->name;
  7174. case BL_PET: return ((TBL_PET*)bl)->pet.name;
  7175. case BL_HOM: return ((TBL_HOM*)bl)->homunculus.name;
  7176. case BL_MER: return ((TBL_MER *)bl)->db->name.c_str(); // They only have database names which are global, not specific to GID.
  7177. case BL_NPC: return ((TBL_NPC*)bl)->name;
  7178. case BL_ELEM: return ((TBL_ELEM *)bl)->db->name.c_str(); // They only have database names which are global, not specific to GID.
  7179. }
  7180. return "Unknown";
  7181. }
  7182. /**
  7183. * Gets the class/sprite id of the given bl
  7184. * @param bl: Object whose class to get [PC|MOB|PET|HOM|MER|NPC|ELEM]
  7185. * @return class or 0 if any other bl->type than noted above
  7186. */
  7187. int status_get_class(struct block_list *bl)
  7188. {
  7189. nullpo_ret(bl);
  7190. switch( bl->type ) {
  7191. case BL_PC: return ((TBL_PC*)bl)->status.class_;
  7192. case BL_MOB: return ((TBL_MOB*)bl)->vd->class_; // Class used on all code should be the view class of the mob.
  7193. case BL_PET: return ((TBL_PET*)bl)->pet.class_;
  7194. case BL_HOM: return ((TBL_HOM*)bl)->homunculus.class_;
  7195. case BL_MER: return ((TBL_MER*)bl)->mercenary.class_;
  7196. case BL_NPC: return ((TBL_NPC*)bl)->class_;
  7197. case BL_ELEM: return ((TBL_ELEM*)bl)->elemental.class_;
  7198. }
  7199. return 0;
  7200. }
  7201. /**
  7202. * Gets the base level of the given bl
  7203. * @param bl: Object whose base level to get [PC|MOB|PET|HOM|MER|NPC|ELEM]
  7204. * @return base level or 1 if any other bl->type than noted above
  7205. */
  7206. int status_get_lv(struct block_list *bl)
  7207. {
  7208. nullpo_ret(bl);
  7209. switch (bl->type) {
  7210. case BL_PC: return ((TBL_PC*)bl)->status.base_level;
  7211. case BL_MOB: return ((TBL_MOB*)bl)->level;
  7212. case BL_PET: return ((TBL_PET*)bl)->pet.level;
  7213. case BL_HOM: return ((TBL_HOM*)bl)->homunculus.level;
  7214. case BL_MER: return ((TBL_MER*)bl)->db->lv;
  7215. case BL_ELEM: return ((TBL_ELEM*)bl)->db->lv;
  7216. case BL_NPC: return ((TBL_NPC*)bl)->level;
  7217. }
  7218. return 1;
  7219. }
  7220. /**
  7221. * Gets the regeneration info of the given bl
  7222. * @param bl: Object whose regen info to get [PC|HOM|MER|ELEM]
  7223. * @return regen data or NULL if any other bl->type than noted above
  7224. */
  7225. struct regen_data *status_get_regen_data(struct block_list *bl)
  7226. {
  7227. nullpo_retr(NULL, bl);
  7228. switch (bl->type) {
  7229. case BL_PC: return &((TBL_PC*)bl)->regen;
  7230. case BL_HOM: return &((TBL_HOM*)bl)->regen;
  7231. case BL_MER: return &((TBL_MER*)bl)->regen;
  7232. case BL_ELEM: return &((TBL_ELEM*)bl)->regen;
  7233. default:
  7234. return NULL;
  7235. }
  7236. }
  7237. /**
  7238. * Gets the status data of the given bl
  7239. * @param bl: Object whose status to get [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7240. * @return status or "dummy_status" if any other bl->type than noted above
  7241. */
  7242. struct status_data *status_get_status_data(struct block_list *bl)
  7243. {
  7244. nullpo_retr(&dummy_status, bl);
  7245. switch (bl->type) {
  7246. case BL_PC: return &((TBL_PC*)bl)->battle_status;
  7247. case BL_MOB: return &((TBL_MOB*)bl)->status;
  7248. case BL_PET: return &((TBL_PET*)bl)->status;
  7249. case BL_HOM: return &((TBL_HOM*)bl)->battle_status;
  7250. case BL_MER: return &((TBL_MER*)bl)->battle_status;
  7251. case BL_ELEM: return &((TBL_ELEM*)bl)->battle_status;
  7252. case BL_NPC: return ((mobdb_checkid(((TBL_NPC*)bl)->class_) == 0) ? &((TBL_NPC*)bl)->status : &dummy_status);
  7253. default:
  7254. return &dummy_status;
  7255. }
  7256. }
  7257. /**
  7258. * Gets the base status data of the given bl
  7259. * @param bl: Object whose status to get [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7260. * @return base_status or NULL if any other bl->type than noted above
  7261. */
  7262. struct status_data *status_get_base_status(struct block_list *bl)
  7263. {
  7264. nullpo_retr(NULL, bl);
  7265. switch (bl->type) {
  7266. case BL_PC: return &((TBL_PC*)bl)->base_status;
  7267. case BL_MOB: return ((TBL_MOB*)bl)->base_status ? ((TBL_MOB*)bl)->base_status : &((TBL_MOB*)bl)->db->status;
  7268. case BL_PET: return &((TBL_PET*)bl)->db->status;
  7269. case BL_HOM: return &((TBL_HOM*)bl)->base_status;
  7270. case BL_MER: return &((TBL_MER*)bl)->base_status;
  7271. case BL_ELEM: return &((TBL_ELEM*)bl)->base_status;
  7272. case BL_NPC: return ((mobdb_checkid(((TBL_NPC*)bl)->class_) == 0) ? &((TBL_NPC*)bl)->status : NULL);
  7273. default:
  7274. return NULL;
  7275. }
  7276. }
  7277. /**
  7278. * Gets the defense of the given bl
  7279. * @param bl: Object whose defense to get [PC|MOB|HOM|MER|ELEM]
  7280. * @return defense with cap_value(def, DEFTYPE_MIN, DEFTYPE_MAX)
  7281. */
  7282. defType status_get_def(struct block_list *bl)
  7283. {
  7284. struct unit_data *ud;
  7285. struct status_data *status = status_get_status_data(bl);
  7286. int def = status?status->def:0;
  7287. ud = unit_bl2ud(bl);
  7288. if (ud && ud->skilltimer != INVALID_TIMER)
  7289. def -= def * skill_get_castdef(ud->skill_id)/100;
  7290. return cap_value(def, DEFTYPE_MIN, DEFTYPE_MAX);
  7291. }
  7292. /**
  7293. * Gets the walking speed of the given bl
  7294. * @param bl: Object whose speed to get [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7295. * @return speed
  7296. */
  7297. unsigned short status_get_speed(struct block_list *bl)
  7298. {
  7299. if(bl->type==BL_NPC)// Only BL with speed data but no status_data [Skotlex]
  7300. return ((struct npc_data *)bl)->speed;
  7301. return status_get_status_data(bl)->speed;
  7302. }
  7303. /**
  7304. * Gets the party ID of the given bl
  7305. * @param bl: Object whose party ID to get [PC|MOB|PET|HOM|MER|SKILL|ELEM]
  7306. * @return party ID
  7307. */
  7308. int status_get_party_id(struct block_list *bl)
  7309. {
  7310. nullpo_ret(bl);
  7311. switch (bl->type) {
  7312. case BL_PC:
  7313. return ((TBL_PC*)bl)->status.party_id;
  7314. case BL_PET:
  7315. if (((TBL_PET*)bl)->master)
  7316. return ((TBL_PET*)bl)->master->status.party_id;
  7317. break;
  7318. case BL_MOB: {
  7319. struct mob_data *md=(TBL_MOB*)bl;
  7320. if( md->master_id > 0 ) {
  7321. struct map_session_data *msd;
  7322. if (md->special_state.ai && (msd = map_id2sd(md->master_id)) != NULL)
  7323. return msd->status.party_id;
  7324. return -md->master_id;
  7325. }
  7326. }
  7327. break;
  7328. case BL_HOM:
  7329. if (((TBL_HOM*)bl)->master)
  7330. return ((TBL_HOM*)bl)->master->status.party_id;
  7331. break;
  7332. case BL_MER:
  7333. if (((TBL_MER*)bl)->master)
  7334. return ((TBL_MER*)bl)->master->status.party_id;
  7335. break;
  7336. case BL_SKILL:
  7337. if (((TBL_SKILL*)bl)->group)
  7338. return ((TBL_SKILL*)bl)->group->party_id;
  7339. break;
  7340. case BL_ELEM:
  7341. if (((TBL_ELEM*)bl)->master)
  7342. return ((TBL_ELEM*)bl)->master->status.party_id;
  7343. break;
  7344. }
  7345. return 0;
  7346. }
  7347. /**
  7348. * Gets the guild ID of the given bl
  7349. * @param bl: Object whose guild ID to get [PC|MOB|PET|HOM|MER|SKILL|ELEM|NPC]
  7350. * @return guild ID
  7351. */
  7352. int status_get_guild_id(struct block_list *bl)
  7353. {
  7354. nullpo_ret(bl);
  7355. switch (bl->type) {
  7356. case BL_PC:
  7357. return ((TBL_PC*)bl)->status.guild_id;
  7358. case BL_PET:
  7359. if (((TBL_PET*)bl)->master)
  7360. return ((TBL_PET*)bl)->master->status.guild_id;
  7361. break;
  7362. case BL_MOB:
  7363. {
  7364. struct map_session_data *msd;
  7365. struct mob_data *md = (struct mob_data *)bl;
  7366. if (md->guardian_data) // Guardian's guild [Skotlex]
  7367. return md->guardian_data->guild_id;
  7368. if (md->special_state.ai && (msd = map_id2sd(md->master_id)) != NULL)
  7369. return msd->status.guild_id; // Alchemist's mobs [Skotlex]
  7370. }
  7371. break;
  7372. case BL_HOM:
  7373. if (((TBL_HOM*)bl)->master)
  7374. return ((TBL_HOM*)bl)->master->status.guild_id;
  7375. break;
  7376. case BL_MER:
  7377. if (((TBL_MER*)bl)->master)
  7378. return ((TBL_MER*)bl)->master->status.guild_id;
  7379. break;
  7380. case BL_NPC:
  7381. if (((TBL_NPC*)bl)->subtype == NPCTYPE_SCRIPT)
  7382. return ((TBL_NPC*)bl)->u.scr.guild_id;
  7383. break;
  7384. case BL_SKILL:
  7385. if (((TBL_SKILL*)bl)->group)
  7386. return ((TBL_SKILL*)bl)->group->guild_id;
  7387. break;
  7388. case BL_ELEM:
  7389. if (((TBL_ELEM*)bl)->master)
  7390. return ((TBL_ELEM*)bl)->master->status.guild_id;
  7391. break;
  7392. }
  7393. return 0;
  7394. }
  7395. /**
  7396. * Gets the guild emblem ID of the given bl
  7397. * @param bl: Object whose emblem ID to get [PC|MOB|PET|HOM|MER|SKILL|ELEM|NPC]
  7398. * @return guild emblem ID
  7399. */
  7400. int status_get_emblem_id(struct block_list *bl)
  7401. {
  7402. nullpo_ret(bl);
  7403. switch (bl->type) {
  7404. case BL_PC:
  7405. return ((TBL_PC*)bl)->guild_emblem_id;
  7406. case BL_PET:
  7407. if (((TBL_PET*)bl)->master)
  7408. return ((TBL_PET*)bl)->master->guild_emblem_id;
  7409. break;
  7410. case BL_MOB:
  7411. {
  7412. struct map_session_data *msd;
  7413. struct mob_data *md = (struct mob_data *)bl;
  7414. if (md->guardian_data) // Guardian's guild [Skotlex]
  7415. return md->guardian_data->emblem_id;
  7416. if (md->special_state.ai && (msd = map_id2sd(md->master_id)) != NULL)
  7417. return msd->guild_emblem_id; // Alchemist's mobs [Skotlex]
  7418. }
  7419. break;
  7420. case BL_HOM:
  7421. if (((TBL_HOM*)bl)->master)
  7422. return ((TBL_HOM*)bl)->master->guild_emblem_id;
  7423. break;
  7424. case BL_MER:
  7425. if (((TBL_MER*)bl)->master)
  7426. return ((TBL_MER*)bl)->master->guild_emblem_id;
  7427. break;
  7428. case BL_NPC:
  7429. if (((TBL_NPC*)bl)->subtype == NPCTYPE_SCRIPT && ((TBL_NPC*)bl)->u.scr.guild_id > 0) {
  7430. struct guild *g = guild_search(((TBL_NPC*)bl)->u.scr.guild_id);
  7431. if (g)
  7432. return g->emblem_id;
  7433. }
  7434. break;
  7435. case BL_ELEM:
  7436. if (((TBL_ELEM*)bl)->master)
  7437. return ((TBL_ELEM*)bl)->master->guild_emblem_id;
  7438. break;
  7439. }
  7440. return 0;
  7441. }
  7442. /**
  7443. * Gets the race2 of a mob or pet
  7444. * @param bl: Object whose race2 to get [MOB|PET]
  7445. * @return race2
  7446. */
  7447. std::vector<e_race2> status_get_race2(struct block_list *bl)
  7448. {
  7449. nullpo_retr(std::vector<e_race2>(),bl);
  7450. if (bl->type == BL_MOB)
  7451. return ((struct mob_data *)bl)->db->race2;
  7452. if (bl->type == BL_PET)
  7453. return ((struct pet_data *)bl)->db->race2;
  7454. return std::vector<e_race2>();
  7455. }
  7456. /**
  7457. * Checks if an object is dead
  7458. * @param bl: Object to check [PC|MOB|HOM|MER|ELEM]
  7459. * @return 1: Is dead or 0: Is alive
  7460. */
  7461. int status_isdead(struct block_list *bl)
  7462. {
  7463. nullpo_ret(bl);
  7464. return status_get_status_data(bl)->hp == 0;
  7465. }
  7466. /**
  7467. * Checks if an object is immune to magic
  7468. * @param bl: Object to check [PC|MOB|HOM|MER|ELEM]
  7469. * @return value of magic damage to be blocked
  7470. */
  7471. int status_isimmune(struct block_list *bl)
  7472. {
  7473. struct status_change *sc =status_get_sc(bl);
  7474. if (sc) {
  7475. if (sc->data[SC_HERMODE])
  7476. return 100;
  7477. if (sc->data[SC_DEADLY_DEFEASANCE])
  7478. return 0;
  7479. }
  7480. if (bl->type == BL_PC &&
  7481. ((TBL_PC*)bl)->special_state.no_magic_damage >= battle_config.gtb_sc_immunity)
  7482. return ((TBL_PC*)bl)->special_state.no_magic_damage;
  7483. return 0;
  7484. }
  7485. /**
  7486. * Get view data of an object
  7487. * @param bl: Object whose view data to get [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7488. * @return view data structure bl->vd
  7489. */
  7490. struct view_data* status_get_viewdata(struct block_list *bl)
  7491. {
  7492. nullpo_retr(NULL, bl);
  7493. switch (bl->type) {
  7494. case BL_PC: return &((TBL_PC*)bl)->vd;
  7495. case BL_MOB: return ((TBL_MOB*)bl)->vd;
  7496. case BL_PET: return &((TBL_PET*)bl)->vd;
  7497. case BL_NPC: return &((TBL_NPC*)bl)->vd;
  7498. case BL_HOM: return ((TBL_HOM*)bl)->vd;
  7499. case BL_MER: return ((TBL_MER*)bl)->vd;
  7500. case BL_ELEM: return ((TBL_ELEM*)bl)->vd;
  7501. }
  7502. return NULL;
  7503. }
  7504. /**
  7505. * Set view data of an object
  7506. * This function deals with class, mount, and item views
  7507. * SC views are set in clif_getareachar_unit()
  7508. * @param bl: Object whose view data to set [PC|MOB|PET|HOM|MER|ELEM|NPC]
  7509. * @param class_: class of the object
  7510. */
  7511. void status_set_viewdata(struct block_list *bl, int class_)
  7512. {
  7513. struct view_data* vd;
  7514. nullpo_retv(bl);
  7515. if (mobdb_checkid(class_) || mob_is_clone(class_))
  7516. vd = mob_get_viewdata(class_);
  7517. else if (npcdb_checkid(class_))
  7518. vd = npc_get_viewdata(class_);
  7519. else if (homdb_checkid(class_))
  7520. vd = hom_get_viewdata(class_);
  7521. else if (mercenary_db.exists(class_))
  7522. vd = mercenary_get_viewdata(class_);
  7523. else if (elemental_db.exists(class_))
  7524. vd = elemental_get_viewdata(class_);
  7525. else
  7526. vd = NULL;
  7527. switch (bl->type) {
  7528. case BL_PC:
  7529. {
  7530. TBL_PC* sd = (TBL_PC*)bl;
  7531. if (pcdb_checkid(class_)) {
  7532. if (sd->sc.option&OPTION_RIDING) {
  7533. switch (class_) { // Adapt class to a Mounted one.
  7534. case JOB_KNIGHT:
  7535. class_ = JOB_KNIGHT2;
  7536. break;
  7537. case JOB_CRUSADER:
  7538. class_ = JOB_CRUSADER2;
  7539. break;
  7540. case JOB_LORD_KNIGHT:
  7541. class_ = JOB_LORD_KNIGHT2;
  7542. break;
  7543. case JOB_PALADIN:
  7544. class_ = JOB_PALADIN2;
  7545. break;
  7546. case JOB_BABY_KNIGHT:
  7547. class_ = JOB_BABY_KNIGHT2;
  7548. break;
  7549. case JOB_BABY_CRUSADER:
  7550. class_ = JOB_BABY_CRUSADER2;
  7551. break;
  7552. }
  7553. }
  7554. sd->vd.class_ = class_;
  7555. clif_get_weapon_view(sd, &sd->vd.weapon, &sd->vd.shield);
  7556. sd->vd.head_top = sd->status.head_top;
  7557. sd->vd.head_mid = sd->status.head_mid;
  7558. sd->vd.head_bottom = sd->status.head_bottom;
  7559. sd->vd.hair_style = cap_value(sd->status.hair, MIN_HAIR_STYLE, MAX_HAIR_STYLE);
  7560. sd->vd.hair_color = cap_value(sd->status.hair_color, MIN_HAIR_COLOR, MAX_HAIR_COLOR);
  7561. sd->vd.cloth_color = cap_value(sd->status.clothes_color, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
  7562. sd->vd.body_style = cap_value(sd->status.body, MIN_BODY_STYLE, MAX_BODY_STYLE);
  7563. sd->vd.sex = sd->status.sex;
  7564. if (sd->vd.cloth_color) {
  7565. if(sd->sc.option&OPTION_WEDDING && battle_config.wedding_ignorepalette)
  7566. sd->vd.cloth_color = 0;
  7567. if(sd->sc.option&OPTION_XMAS && battle_config.xmas_ignorepalette)
  7568. sd->vd.cloth_color = 0;
  7569. if(sd->sc.option&(OPTION_SUMMER|OPTION_SUMMER2) && battle_config.summer_ignorepalette)
  7570. sd->vd.cloth_color = 0;
  7571. if(sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette)
  7572. sd->vd.cloth_color = 0;
  7573. if(sd->sc.option&OPTION_OKTOBERFEST && battle_config.oktoberfest_ignorepalette)
  7574. sd->vd.cloth_color = 0;
  7575. }
  7576. if ( sd->vd.body_style && sd->sc.option&OPTION_COSTUME)
  7577. sd->vd.body_style = 0;
  7578. } else if (vd)
  7579. memcpy(&sd->vd, vd, sizeof(struct view_data));
  7580. else
  7581. ShowError("status_set_viewdata (PC): No view data for class %d\n", class_);
  7582. }
  7583. break;
  7584. case BL_MOB:
  7585. {
  7586. TBL_MOB* md = (TBL_MOB*)bl;
  7587. if (vd){
  7588. mob_free_dynamic_viewdata( md );
  7589. md->vd = vd;
  7590. }else if( pcdb_checkid( class_ ) ){
  7591. mob_set_dynamic_viewdata( md );
  7592. md->vd->class_ = class_;
  7593. md->vd->hair_style = cap_value(md->vd->hair_style, MIN_HAIR_STYLE, MAX_HAIR_STYLE);
  7594. md->vd->hair_color = cap_value(md->vd->hair_color, MIN_HAIR_COLOR, MAX_HAIR_COLOR);
  7595. }else
  7596. ShowError("status_set_viewdata (MOB): No view data for class %d\n", class_);
  7597. }
  7598. break;
  7599. case BL_PET:
  7600. {
  7601. TBL_PET* pd = (TBL_PET*)bl;
  7602. if (vd) {
  7603. memcpy(&pd->vd, vd, sizeof(struct view_data));
  7604. if (!pcdb_checkid(vd->class_)) {
  7605. pd->vd.hair_style = battle_config.pet_hair_style;
  7606. if(pd->pet.equip) {
  7607. pd->vd.head_bottom = itemdb_viewid(pd->pet.equip);
  7608. if (!pd->vd.head_bottom)
  7609. pd->vd.head_bottom = pd->pet.equip;
  7610. }
  7611. }
  7612. } else
  7613. ShowError("status_set_viewdata (PET): No view data for class %d\n", class_);
  7614. }
  7615. break;
  7616. case BL_NPC:
  7617. {
  7618. TBL_NPC* nd = (TBL_NPC*)bl;
  7619. if (vd)
  7620. memcpy(&nd->vd, vd, sizeof(struct view_data));
  7621. else if (pcdb_checkid(class_)) {
  7622. memset(&nd->vd, 0, sizeof(struct view_data));
  7623. nd->vd.class_ = class_;
  7624. nd->vd.hair_style = cap_value(nd->vd.hair_style, MIN_HAIR_STYLE, MAX_HAIR_STYLE);
  7625. } else {
  7626. ShowError("status_set_viewdata (NPC): Invalid view data %d\n", class_);
  7627. if (bl->m >= 0)
  7628. ShowDebug("Source (NPC): %s at %s (%d,%d)\n", nd->name, map_mapid2mapname(bl->m), bl->x, bl->y);
  7629. else
  7630. ShowDebug("Source (NPC): %s (invisible/not on a map)\n", nd->name);
  7631. ShowDebug( "Source (NPC): %s is located in: %s\n", nd->name, nd->path );
  7632. }
  7633. break;
  7634. }
  7635. break;
  7636. case BL_HOM:
  7637. {
  7638. struct homun_data *hd = (struct homun_data*)bl;
  7639. if (vd)
  7640. hd->vd = vd;
  7641. else
  7642. ShowError("status_set_viewdata (HOMUNCULUS): No view data for class %d\n", class_);
  7643. }
  7644. break;
  7645. case BL_MER:
  7646. {
  7647. s_mercenary_data *md = (s_mercenary_data*)bl;
  7648. if (vd)
  7649. md->vd = vd;
  7650. else
  7651. ShowError("status_set_viewdata (MERCENARY): No view data for class %d\n", class_);
  7652. }
  7653. break;
  7654. case BL_ELEM:
  7655. {
  7656. s_elemental_data *ed = (s_elemental_data*)bl;
  7657. if (vd)
  7658. ed->vd = vd;
  7659. else
  7660. ShowError("status_set_viewdata (ELEMENTAL): No view data for class %d\n", class_);
  7661. }
  7662. break;
  7663. }
  7664. }
  7665. /**
  7666. * Get status change data of an object
  7667. * @param bl: Object whose sc data to get [PC|MOB|HOM|MER|ELEM|NPC]
  7668. * @return status change data structure bl->sc
  7669. */
  7670. struct status_change *status_get_sc(struct block_list *bl)
  7671. {
  7672. if( bl )
  7673. switch (bl->type) {
  7674. case BL_PC: return &((TBL_PC*)bl)->sc;
  7675. case BL_MOB: return &((TBL_MOB*)bl)->sc;
  7676. case BL_NPC: return &((TBL_NPC*)bl)->sc;
  7677. case BL_HOM: return &((TBL_HOM*)bl)->sc;
  7678. case BL_MER: return &((TBL_MER*)bl)->sc;
  7679. case BL_ELEM: return &((TBL_ELEM*)bl)->sc;
  7680. }
  7681. return NULL;
  7682. }
  7683. /**
  7684. * Initiate (memset) the status change data of an object
  7685. * @param bl: Object whose sc data to memset [PC|MOB|HOM|MER|ELEM|NPC]
  7686. */
  7687. void status_change_init(struct block_list *bl)
  7688. {
  7689. struct status_change *sc = status_get_sc(bl);
  7690. nullpo_retv(sc);
  7691. memset(sc, 0, sizeof (struct status_change));
  7692. sc->lastEffect = SC_NONE;
  7693. sc->lastEffectTimer = INVALID_TIMER;
  7694. }
  7695. /*========================================== [Playtester]
  7696. * Returns the interval for status changes that iterate multiple times
  7697. * through the timer (e.g. those that deal damage in regular intervals)
  7698. * @param type: Status change (SC_*)
  7699. *------------------------------------------*/
  7700. static int status_get_sc_interval(enum sc_type type)
  7701. {
  7702. switch (type) {
  7703. case SC_POISON:
  7704. case SC_LEECHESEND:
  7705. case SC_DPOISON:
  7706. case SC_DEATHHURT:
  7707. return 1000;
  7708. case SC_BURNING:
  7709. case SC_PYREXIA:
  7710. return 3000;
  7711. case SC_MAGICMUSHROOM:
  7712. return 4000;
  7713. case SC_STONE:
  7714. return 5000;
  7715. case SC_BLEEDING:
  7716. case SC_TOXIN:
  7717. return 10000;
  7718. case SC_HELLS_PLANT:
  7719. return 333;
  7720. case SC_SHIELDSPELL_HP:
  7721. return 3000;
  7722. case SC_SHIELDSPELL_SP:
  7723. return 5000;
  7724. default:
  7725. break;
  7726. }
  7727. return 0;
  7728. }
  7729. /**
  7730. * Applies SC defense to a given status change
  7731. * This function also determines whether or not the status change will be applied
  7732. * @param src: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
  7733. * @param bl: Target of the status change
  7734. * @param type: Status change (SC_*)
  7735. * @param rate: Initial percentage rate of affecting bl (0~10000)
  7736. * @param tick: Initial duration that the status change affects bl
  7737. * @param flag: Value which determines what parts to calculate. See e_status_change_start_flags
  7738. * @return adjusted duration based on flag values
  7739. */
  7740. t_tick status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, t_tick tick, unsigned char flag)
  7741. {
  7742. /// Resistance rate: 10000 = 100%
  7743. /// Example: 50% (5000) -> sc_def = 5000 -> 25%;
  7744. /// 5000ms -> tick_def = 5000 -> 2500ms
  7745. int sc_def = 0, tick_def = -1; // -1 = use sc_def
  7746. /// Fixed resistance value (after rate calculation)
  7747. /// Example: 25% (2500) -> sc_def2 = 2000 -> 5%;
  7748. /// 2500ms -> tick_def2=2000 -> 500ms
  7749. int sc_def2 = 0, tick_def2 = 0;
  7750. struct status_data *status, *status_src;
  7751. struct status_change *sc;
  7752. struct map_session_data *sd;
  7753. nullpo_ret(bl);
  7754. if (src == NULL)
  7755. return tick?tick:1; // This should not happen in current implementation, but leave it anyway
  7756. // Skills (magic type) that are blocked by Golden Thief Bug card or Wand of Hermod
  7757. if (status_isimmune(bl)) {
  7758. std::shared_ptr<s_skill_db> skill = skill_db.find(battle_getcurrentskill(src));
  7759. if (skill == nullptr) // Check for ground-type skills using the status when a player moves through units
  7760. skill = skill_db.find(status_db.getSkill(type));
  7761. if (skill != nullptr && skill->skill_type == BF_MAGIC && // Basic magic skill
  7762. !skill->inf2[INF2_IGNOREGTB] && // Specific skill to bypass
  7763. ((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
  7764. (skill->inf == INF_SELF_SKILL && src != bl))) // Self skills should get blocked on all targets except self
  7765. return 0;
  7766. }
  7767. sd = BL_CAST(BL_PC,bl);
  7768. status = status_get_status_data(bl);
  7769. status_src = status_get_status_data(src);
  7770. sc = status_get_sc(bl);
  7771. if( sc && !sc->count )
  7772. sc = NULL;
  7773. #ifdef RENEWAL
  7774. uint16 levelAdv = (static_cast<uint16>(pow(max(0, status_get_lv(src) - status_get_lv(bl)), 2)) / 5) * 100;
  7775. #endif
  7776. switch (type) {
  7777. case SC_POISON:
  7778. case SC_DPOISON:
  7779. #ifndef RENEWAL
  7780. sc_def = status->vit*100;
  7781. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  7782. if (sd) {
  7783. // For players: 60000 - 450*vit - 100*luk
  7784. tick_def = status->vit*75;
  7785. tick_def2 = status->luk*100;
  7786. } else {
  7787. // For monsters: 30000 - 200*vit
  7788. tick>>=1;
  7789. tick_def = (status->vit*200)/3;
  7790. }
  7791. #else
  7792. sc_def = status->vit * 100 - levelAdv;
  7793. tick_def2 = -2000;
  7794. #endif
  7795. break;
  7796. case SC_STUN:
  7797. #ifndef RENEWAL
  7798. sc_def = status->vit*100;
  7799. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  7800. tick_def2 = status->luk*10;
  7801. #else
  7802. sc_def = status->vit * 100 - levelAdv;
  7803. tick_def2 = -500;
  7804. #endif
  7805. break;
  7806. case SC_SILENCE:
  7807. #ifndef RENEWAL
  7808. sc_def = status->vit*100;
  7809. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  7810. tick_def2 = status->luk*10;
  7811. #else
  7812. sc_def = status->int_ * 100 - levelAdv;
  7813. tick_def2 = -2000;
  7814. #endif
  7815. break;
  7816. case SC_BLEEDING:
  7817. #ifndef RENEWAL
  7818. sc_def = status->vit*100;
  7819. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  7820. tick_def2 = status->luk*10;
  7821. #else
  7822. sc_def = status->agi * 100 - levelAdv;
  7823. tick_def2 = -12000;
  7824. #endif
  7825. break;
  7826. case SC_SLEEP:
  7827. #ifndef RENEWAL
  7828. sc_def = status->int_*100;
  7829. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  7830. tick_def2 = status->luk*10;
  7831. #else
  7832. sc_def = status->agi * 100 - levelAdv;
  7833. tick_def2 = -2000;
  7834. #endif
  7835. break;
  7836. case SC_STONEWAIT:
  7837. #ifndef RENEWAL
  7838. sc_def = status->mdef*100;
  7839. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  7840. tick_def = 0; // No duration reduction
  7841. #else
  7842. sc_def = status->mdef * 100 - levelAdv;
  7843. tick_def2 = -3000;
  7844. #endif
  7845. break;
  7846. case SC_FREEZE:
  7847. #ifndef RENEWAL
  7848. sc_def = status->mdef*100;
  7849. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  7850. tick_def2 = status_src->luk*-10; // Caster can increase final duration with luk
  7851. #else
  7852. sc_def = status->mdef * 100 - levelAdv;
  7853. tick_def2 = -3000;
  7854. #endif
  7855. break;
  7856. case SC_CURSE:
  7857. // Special property: immunity when luk is zero
  7858. if (status->luk == 0)
  7859. return 0;
  7860. #ifndef RENEWAL
  7861. sc_def = status->luk*100;
  7862. sc_def2 = status->luk*10 - status_get_lv(src)*10; // Curse only has a level penalty and no resistance
  7863. tick_def = status->vit*100;
  7864. tick_def2 = status->luk*10;
  7865. #else
  7866. sc_def = status->luk * 100 - levelAdv;
  7867. tick_def2 = -2000;
  7868. #endif
  7869. break;
  7870. case SC_BLIND:
  7871. #ifndef RENEWAL
  7872. sc_def = (status->vit + status->int_)*50;
  7873. sc_def2 = status->luk*10 + status_get_lv(bl)*10 - status_get_lv(src)*10;
  7874. tick_def2 = status->luk*10;
  7875. #else
  7876. sc_def = status->int_ * 100 - levelAdv;
  7877. tick_def2 = -2000;
  7878. #endif
  7879. break;
  7880. case SC_CONFUSION:
  7881. #ifndef RENEWAL
  7882. sc_def = (status->str + status->int_)*50;
  7883. sc_def2 = status_get_lv(src)*10 - status_get_lv(bl)*10 - status->luk*10; // Reversed sc_def2
  7884. tick_def2 = status->luk*10;
  7885. #else
  7886. sc_def = status->luk * 100 - levelAdv;
  7887. tick_def2 = -2000;
  7888. #endif
  7889. break;
  7890. case SC_DECREASEAGI:
  7891. if (sd)
  7892. tick >>= 1; // Half duration for players.
  7893. sc_def2 = status->mdef*100;
  7894. break;
  7895. case SC_ANKLE:
  7896. if(status_has_mode(status,MD_STATUSIMMUNE)) // Lasts 5 times less on bosses
  7897. tick /= 5;
  7898. sc_def = status->agi*50;
  7899. break;
  7900. case SC_JOINTBEAT:
  7901. tick_def2 = 1000 * ((status->luk / 2 + status->agi / 5) / 2); // (50 * LUK / 100 + 20 * AGI / 100) / 2
  7902. break;
  7903. case SC_DEEPSLEEP:
  7904. tick_def2 = status_get_base_status(bl)->int_ * 25 + status_get_lv(bl) * 50;
  7905. break;
  7906. case SC_NETHERWORLD:
  7907. // Resistance: {(Target's Base Level / 50) + (Target's Job Level / 10)} seconds
  7908. tick_def2 = status_get_lv(bl) * 20 + (sd ? sd->status.job_level : 1) * 100;
  7909. break;
  7910. case SC_MARSHOFABYSS:
  7911. // 5 second (Fixed) + 25 second - {( INT + LUK ) / 20 second }
  7912. tick_def2 = (status->int_ + status->luk)*50;
  7913. break;
  7914. case SC_STASIS:
  7915. // 10 second (fixed) + { Stasis Skill level * 10 - (Target's VIT + DEX) / 20 }
  7916. tick_def2 = (status->vit + status->dex) * 50;
  7917. break;
  7918. case SC_WHITEIMPRISON:
  7919. if( src == bl ) // 100% on caster
  7920. break;
  7921. sc_def = status->str * 20 + status_get_lv(bl) * 20 + status->luk * 10;
  7922. tick_def2 = -2000;
  7923. break;
  7924. case SC_FEAR:
  7925. sc_def = status->int_ * 20 + status_get_lv(bl) * 20 + status->luk * 10;
  7926. tick_def2 = -4000; // 2 seconds is applied twice on Aegis
  7927. break;
  7928. case SC_BURNING:
  7929. sc_def = status->agi * 20 + status_get_lv(bl) * 20 + status->luk * 10;
  7930. tick_def2 = -2000;
  7931. break;
  7932. case SC_FREEZING:
  7933. tick_def2 = (status->vit + status->dex) * 50;
  7934. break;
  7935. case SC_OBLIVIONCURSE: // 100% - (100 - 0.8 x INT)
  7936. sc_def = status->int_ * 80;
  7937. sc_def = max(sc_def, 500); // minimum of 5% resist
  7938. tick_def = 0;
  7939. tick_def2 = (status->vit + status->luk) * 500;
  7940. break;
  7941. case SC_TOXIN:
  7942. case SC_PARALYSE:
  7943. case SC_VENOMBLEED:
  7944. case SC_MAGICMUSHROOM:
  7945. case SC_DEATHHURT:
  7946. case SC_PYREXIA:
  7947. case SC_LEECHESEND:
  7948. tick_def2 = (status->vit + status->luk) * 500;
  7949. break;
  7950. case SC_BITE: // {(Base Success chance) - (Target's AGI / 4)}
  7951. sc_def2 = status->agi*25;
  7952. break;
  7953. case SC_ELECTRICSHOCKER:
  7954. tick_def2 = (status->vit + status->agi) * 70;
  7955. break;
  7956. case SC_CRYSTALIZE:
  7957. tick_def2 = status_get_base_status(bl)->vit * 100;
  7958. break;
  7959. case SC_VACUUM_EXTREME:
  7960. tick_def2 = (sd ? sd->status.str : status_get_base_status(bl)->str) * 50;
  7961. break;
  7962. case SC_KYOUGAKU:
  7963. tick_def2 = 30*status->int_;
  7964. break;
  7965. case SC_PARALYSIS:
  7966. tick_def2 = (status->vit + status->luk)*50;
  7967. break;
  7968. case SC_VOICEOFSIREN:
  7969. // Resistance: {(Target's Base Level / 10) + (Target's Job Level / 5)} seconds
  7970. tick_def2 = status_get_lv(bl) * 100 + (sd ? sd->status.job_level : 1) * 200;
  7971. break;
  7972. case SC_B_TRAP:
  7973. tick_def = (sd ? sd->status.str : status_get_base_status(bl)->str) * 50; //! TODO: Figure out reduction formula
  7974. break;
  7975. case SC_NORECOVER_STATE:
  7976. tick_def2 = status->luk * 100;
  7977. break;
  7978. default:
  7979. // Effect that cannot be reduced? Likely a buff.
  7980. if (!(rnd()%10000 < rate))
  7981. return 0;
  7982. return tick ? tick : 1;
  7983. }
  7984. if (sd) {
  7985. if (battle_config.pc_sc_def_rate != 100) {
  7986. sc_def = sc_def*battle_config.pc_sc_def_rate/100;
  7987. sc_def2 = sc_def2*battle_config.pc_sc_def_rate/100;
  7988. }
  7989. sc_def = cap_value(sc_def, 0, battle_config.pc_max_sc_def*100);
  7990. sc_def2 = cap_value(sc_def2, 0, battle_config.pc_max_sc_def*100);
  7991. if (battle_config.pc_sc_def_rate != 100) {
  7992. tick_def = tick_def*battle_config.pc_sc_def_rate/100;
  7993. tick_def2 = tick_def2*battle_config.pc_sc_def_rate/100;
  7994. }
  7995. } else {
  7996. if (battle_config.mob_sc_def_rate != 100) {
  7997. sc_def = sc_def*battle_config.mob_sc_def_rate/100;
  7998. sc_def2 = sc_def2*battle_config.mob_sc_def_rate/100;
  7999. }
  8000. sc_def = cap_value(sc_def, 0, battle_config.mob_max_sc_def*100);
  8001. sc_def2 = cap_value(sc_def2, 0, battle_config.mob_max_sc_def*100);
  8002. if (battle_config.mob_sc_def_rate != 100) {
  8003. tick_def = tick_def*battle_config.mob_sc_def_rate/100;
  8004. tick_def2 = tick_def2*battle_config.mob_sc_def_rate/100;
  8005. }
  8006. }
  8007. if (sc) {
  8008. if (sc->data[SC_SCRESIST])
  8009. sc_def += sc->data[SC_SCRESIST]->val1*100; // Status resist
  8010. #ifdef RENEWAL
  8011. else if (sc->data[SC_SIEGFRIED] && (type == SC_BLIND || type == SC_STONE || type == SC_FREEZE || type == SC_STUN || type == SC_CURSE || type == SC_SLEEP || type == SC_SILENCE))
  8012. sc_def += sc->data[SC_SIEGFRIED]->val3 * 100; // Status resistance.
  8013. #else
  8014. else if (sc->data[SC_SIEGFRIED])
  8015. sc_def += sc->data[SC_SIEGFRIED]->val3*100; // Status resistance.
  8016. #endif
  8017. else if (sc->data[SC_LEECHESEND] && sc->data[SC_LEECHESEND]->val3 == 0) {
  8018. switch (type) {
  8019. case SC_BLIND:
  8020. case SC_STUN:
  8021. return 0; // Immune
  8022. }
  8023. } else if (sc->data[SC_OBLIVIONCURSE] && sc->data[SC_OBLIVIONCURSE]->val3 == 0) {
  8024. switch (type) {
  8025. case SC_SILENCE:
  8026. case SC_CURSE:
  8027. return 0; // Immune
  8028. }
  8029. }
  8030. }
  8031. // When tick def not set, reduction is the same for both.
  8032. if(tick_def == -1)
  8033. tick_def = sc_def;
  8034. // Natural resistance
  8035. if (!(flag&SCSTART_NORATEDEF)) {
  8036. rate -= rate*sc_def/10000;
  8037. rate -= sc_def2;
  8038. // Item resistance (only applies to rate%)
  8039. if (sd) {
  8040. for (const auto &it : sd->reseff) {
  8041. if (it.id == type)
  8042. rate -= rate * it.val / 10000;
  8043. }
  8044. if (sd->sc.data[SC_COMMONSC_RESIST] && SC_COMMON_MIN <= type && type <= SC_COMMON_MAX)
  8045. rate -= rate*sd->sc.data[SC_COMMONSC_RESIST]->val1/100;
  8046. }
  8047. // Aegis accuracy
  8048. if(rate > 0 && rate%10 != 0) rate += (10 - rate%10);
  8049. }
  8050. std::shared_ptr<s_status_change_db> scdb = status_db.find(type);
  8051. // Cap minimum rate
  8052. rate = max(rate, scdb->min_rate);
  8053. if (rate < 10000 && (rate <= 0 || !(rnd()%10000 < rate)))
  8054. return 0;
  8055. // Duration cannot be reduced
  8056. if (flag&SCSTART_NOTICKDEF)
  8057. return i64max(tick, scdb->min_duration);
  8058. tick -= tick*tick_def/10000;
  8059. #ifdef RENEWAL
  8060. // Renewal applies item resistance also to duration
  8061. if (sd) {
  8062. for (const auto &it : sd->reseff) {
  8063. if (it.id == type)
  8064. tick -= tick * it.val / 10000;
  8065. }
  8066. if (sd->sc.data[SC_COMMONSC_RESIST] && SC_COMMON_MIN <= type && type <= SC_COMMON_MAX)
  8067. tick -= tick * sd->sc.data[SC_COMMONSC_RESIST]->val1 / 100;
  8068. }
  8069. #endif
  8070. tick -= tick_def2;
  8071. return i64max(tick, scdb->min_duration);
  8072. }
  8073. /**
  8074. * Applies SC effect
  8075. * @param bl: Source to apply effect
  8076. * @param type: Status change (SC_*)
  8077. * @param dval1~3: Depends on type of status change
  8078. * Author: Ind
  8079. */
  8080. void status_display_add(struct block_list *bl, enum sc_type type, int dval1, int dval2, int dval3) {
  8081. struct eri *eri;
  8082. struct sc_display_entry **sc_display;
  8083. struct sc_display_entry ***sc_display_ptr;
  8084. struct sc_display_entry *entry;
  8085. int i;
  8086. unsigned char sc_display_count;
  8087. unsigned char *sc_display_count_ptr;
  8088. nullpo_retv(bl);
  8089. switch( bl->type ){
  8090. case BL_PC: {
  8091. struct map_session_data* sd = (struct map_session_data*)bl;
  8092. sc_display_ptr = &sd->sc_display;
  8093. sc_display_count_ptr = &sd->sc_display_count;
  8094. eri = pc_sc_display_ers;
  8095. }
  8096. break;
  8097. case BL_NPC: {
  8098. struct npc_data* nd = (struct npc_data*)bl;
  8099. sc_display_ptr = &nd->sc_display;
  8100. sc_display_count_ptr = &nd->sc_display_count;
  8101. eri = npc_sc_display_ers;
  8102. }
  8103. break;
  8104. default:
  8105. return;
  8106. }
  8107. sc_display = *sc_display_ptr;
  8108. sc_display_count = *sc_display_count_ptr;
  8109. ARR_FIND(0, sc_display_count, i, sc_display[i]->type == type);
  8110. if( i != sc_display_count ) {
  8111. sc_display[i]->val1 = dval1;
  8112. sc_display[i]->val2 = dval2;
  8113. sc_display[i]->val3 = dval3;
  8114. return;
  8115. }
  8116. entry = ers_alloc(eri, struct sc_display_entry);
  8117. entry->type = type;
  8118. entry->val1 = dval1;
  8119. entry->val2 = dval2;
  8120. entry->val3 = dval3;
  8121. RECREATE(sc_display, struct sc_display_entry *, ++sc_display_count);
  8122. sc_display[sc_display_count - 1] = entry;
  8123. *sc_display_ptr = sc_display;
  8124. *sc_display_count_ptr = sc_display_count;
  8125. }
  8126. /**
  8127. * Removes SC effect
  8128. * @param bl: Source to remove effect
  8129. * @param type: Status change (SC_*)
  8130. * Author: Ind
  8131. */
  8132. void status_display_remove(struct block_list *bl, enum sc_type type) {
  8133. struct eri *eri;
  8134. struct sc_display_entry **sc_display;
  8135. struct sc_display_entry ***sc_display_ptr;
  8136. int i;
  8137. unsigned char sc_display_count;
  8138. unsigned char *sc_display_count_ptr;
  8139. nullpo_retv(bl);
  8140. switch( bl->type ){
  8141. case BL_PC: {
  8142. struct map_session_data* sd = (struct map_session_data*)bl;
  8143. sc_display_ptr = &sd->sc_display;
  8144. sc_display_count_ptr = &sd->sc_display_count;
  8145. eri = pc_sc_display_ers;
  8146. }
  8147. break;
  8148. case BL_NPC: {
  8149. struct npc_data* nd = (struct npc_data*)bl;
  8150. sc_display_ptr = &nd->sc_display;
  8151. sc_display_count_ptr = &nd->sc_display_count;
  8152. eri = npc_sc_display_ers;
  8153. }
  8154. break;
  8155. default:
  8156. return;
  8157. }
  8158. sc_display = *sc_display_ptr;
  8159. sc_display_count = *sc_display_count_ptr;
  8160. ARR_FIND(0, sc_display_count, i, sc_display[i]->type == type);
  8161. if( i != sc_display_count ) {
  8162. int cursor;
  8163. ers_free(eri, sc_display[i]);
  8164. sc_display[i] = NULL;
  8165. /* The all-mighty compact-o-matic */
  8166. for( i = 0, cursor = 0; i < sc_display_count; i++ ) {
  8167. if( sc_display[i] == NULL )
  8168. continue;
  8169. if( i != cursor )
  8170. sc_display[cursor] = sc_display[i];
  8171. cursor++;
  8172. }
  8173. if( !(sc_display_count = cursor) ) {
  8174. aFree(sc_display);
  8175. sc_display = NULL;
  8176. }
  8177. *sc_display_ptr = sc_display;
  8178. *sc_display_count_ptr = sc_display_count;
  8179. }
  8180. }
  8181. /**
  8182. * Applies SC defense to a given status change
  8183. * This function also determines whether or not the status change will be applied
  8184. * @param src: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
  8185. * @param bl: Target of the status change (See: enum sc_type)
  8186. * @param type: Status change (SC_*)
  8187. * @param rate: Initial percentage rate of affecting bl (0~10000)
  8188. * @param val1~4: Depends on type of status change
  8189. * @param duration: Initial duration that the status change affects bl
  8190. * @param flag: Value which determines what parts to calculate. See e_status_change_start_flags
  8191. * @param delay: Delay in milliseconds before the SC is applied
  8192. * @return adjusted duration based on flag values
  8193. */
  8194. int status_change_start(struct block_list* src, struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,t_tick duration,unsigned char flag, int32 delay) {
  8195. struct map_session_data *sd = NULL;
  8196. struct status_change* sc;
  8197. struct status_change_entry* sce;
  8198. struct status_data *status;
  8199. struct view_data *vd;
  8200. int undead_flag, tick_time = 0;
  8201. bool sc_isnew = true;
  8202. std::shared_ptr<s_status_change_db> scdb = status_db.find(type);
  8203. nullpo_ret(bl);
  8204. sc = status_get_sc(bl);
  8205. status = status_get_status_data(bl);
  8206. if( !scdb ) {
  8207. ShowError("status_change_start: Invalid status change (%d)!\n", type);
  8208. return 0;
  8209. }
  8210. if( !sc )
  8211. return 0; // Unable to receive status changes
  8212. 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
  8213. return 0;
  8214. if (status_change_isDisabledOnMap(type, map_getmapdata(bl->m)))
  8215. return 0;
  8216. if (sc->data[SC_GRAVITYCONTROL])
  8217. return 0; // !TODO: Confirm what statuses/conditions (if not all) are blocked.
  8218. // Uncomment to prevent status adding hp to gvg mob (like bloodylust=hp*3 etc...
  8219. // if (bl->type == BL_MOB)
  8220. // if (util::vector_exists(status_get_race2(bl), RC2_GVG) && status_sc2scb_flag(type)&SCB_MAXHP) return 0;
  8221. // Fail if Madogear is active
  8222. if (sc->option&OPTION_MADOGEAR && flag&SCSTART_NOAVOID && scdb->flag[SCF_FAILEDMADO])
  8223. return 0;
  8224. // Check for Boss resistances
  8225. if(status->mode&MD_STATUSIMMUNE && !(flag&SCSTART_NOAVOID) && scdb->flag[SCF_BOSSRESIST])
  8226. return 0;
  8227. // Check for MVP resistance
  8228. if(status->mode&MD_MVP && !(flag&SCSTART_NOAVOID) && scdb->flag[SCF_MVPRESIST])
  8229. return 0;
  8230. // End the SCs from the list and immediately return
  8231. // If anything in this list is removed, the rest is ignored.
  8232. if (!scdb->endreturn.empty()) {
  8233. bool isRemoved = false;
  8234. for (const auto &it : scdb->endreturn) {
  8235. sc_type rem_sc = it;
  8236. if (sc->data[rem_sc]) {
  8237. status_change_end(bl, rem_sc, INVALID_TIMER);
  8238. isRemoved = true;
  8239. }
  8240. }
  8241. if (isRemoved) // Something was removed, don't give the status
  8242. return 1; // Return 1 so that sc_start can be checked as success
  8243. }
  8244. // Check failing SCs from list
  8245. if (!scdb->fail.empty()) {
  8246. for (const auto &it : scdb->fail) {
  8247. // Don't let OPT1 that have RemoveOnDamaged start a new effect in the same attack.
  8248. if (sc->data[it] || sc->lastEffect == it)
  8249. return 0;
  8250. }
  8251. }
  8252. // Adjust tick according to status resistances
  8253. if( !(flag&(SCSTART_NOAVOID|SCSTART_LOADED)) ) {
  8254. duration = status_get_sc_def(src, bl, type, rate, duration, flag);
  8255. if( !duration )
  8256. return 0;
  8257. }
  8258. int tick = (int)duration;
  8259. sd = BL_CAST(BL_PC, bl);
  8260. vd = status_get_viewdata(bl);
  8261. undead_flag = battle_check_undead(status->race,status->def_ele);
  8262. // Check for immunities / sc fails
  8263. switch (type) {
  8264. case SC_VACUUM_EXTREME:
  8265. if (sc && sc->data[SC_VACUUM_EXTREME_POSTDELAY] && sc->data[SC_VACUUM_EXTREME_POSTDELAY]->val2 == val2) // Ignore post delay from other vacuum (this will make stack effect enabled)
  8266. return 0;
  8267. break;
  8268. case SC_STONE:
  8269. case SC_STONEWAIT:
  8270. case SC_FREEZE:
  8271. // Undead are immune to Freeze/Stone
  8272. if (undead_flag && !(flag&SCSTART_NOAVOID))
  8273. return 0;
  8274. break;
  8275. case SC_BURNING:
  8276. // Level 2 Fire Element is immune
  8277. if (status->def_ele == ELE_FIRE && status->ele_lv == 2)
  8278. return 0;
  8279. break;
  8280. case SC_ALL_RIDING:
  8281. if( !sd || sc->option&(OPTION_RIDING|OPTION_DRAGON|OPTION_WUG|OPTION_MADOGEAR) )
  8282. return 0;
  8283. break;
  8284. case SC_SIGNUMCRUCIS:
  8285. // Only affects demons and undead element (but not players)
  8286. if((!undead_flag && status->race!=RC_DEMON) || bl->type == BL_PC)
  8287. return 0;
  8288. break;
  8289. case SC_KYRIE:
  8290. case SC_TUNAPARTY:
  8291. if (bl->type == BL_MOB)
  8292. return 0;
  8293. break;
  8294. case SC_ADRENALINE:
  8295. if(sd && !pc_check_weapontype(sd,skill_get_weapontype(BS_ADRENALINE)))
  8296. return 0;
  8297. break;
  8298. case SC_ADRENALINE2:
  8299. if(sd && !pc_check_weapontype(sd,skill_get_weapontype(BS_ADRENALINE2)))
  8300. return 0;
  8301. break;
  8302. case SC_CLOAKING:
  8303. // Avoid cloaking with no wall and low skill level. [Skotlex]
  8304. // Due to the cloaking card, we have to check the wall versus to known
  8305. // skill level rather than the used one. [Skotlex]
  8306. // if (sd && val1 < 3 && skill_check_cloaking(bl,NULL))
  8307. if( sd && pc_checkskill(sd, AS_CLOAKING) < 3 && !skill_check_cloaking(bl,NULL) )
  8308. return 0;
  8309. break;
  8310. case SC_MODECHANGE: {
  8311. int32 mode;
  8312. struct status_data *bstatus = status_get_base_status(bl);
  8313. if (!bstatus) return 0;
  8314. if (sc->data[type]) { // Pile up with previous values.
  8315. if (!val2) val2 = sc->data[type]->val2;
  8316. val3 |= sc->data[type]->val3;
  8317. val4 |= sc->data[type]->val4;
  8318. }
  8319. mode = val2 ? ((val2&~MD_MASK) | val2) : bstatus->mode; // Base mode
  8320. if (val4) mode = static_cast<e_mode>(mode&~val4); // Del mode
  8321. if (val3) mode = static_cast<e_mode>(mode | val3); // Add mode
  8322. if (mode == bstatus->mode) { // No change.
  8323. if (sc->data[type]) // Abort previous status
  8324. return status_change_end(bl, type, INVALID_TIMER);
  8325. return 0;
  8326. }
  8327. }
  8328. break;
  8329. // Strip skills, need to divest something or it fails.
  8330. case SC_STRIPWEAPON:
  8331. if (val2 == 1)
  8332. val2 = 0; // Brandish Spear/Bowling Bash effet. Do not take weapon off.
  8333. else if (sd && !(flag&SCSTART_LOADED)) { // Apply sc anyway if loading saved sc_data
  8334. short i;
  8335. uint8 successFlag = 0;
  8336. if(sd->bonus.unstripable_equip&EQP_WEAPON)
  8337. return 0;
  8338. i = sd->equip_index[EQI_HAND_L];
  8339. if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) {
  8340. successFlag|=1;
  8341. pc_unequipitem(sd,i,3); // Left-hand weapon
  8342. }
  8343. i = sd->equip_index[EQI_HAND_R];
  8344. if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) {
  8345. successFlag|=2;
  8346. pc_unequipitem(sd,i,3);
  8347. }
  8348. if (!successFlag) return 0;
  8349. }
  8350. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8351. break;
  8352. case SC_STRIPSHIELD:
  8353. if( val2 == 1 ) val2 = 0; // GX effect. Do not take shield off..
  8354. else
  8355. if (sd && !(flag&SCSTART_LOADED)) {
  8356. short i;
  8357. if(sd->bonus.unstripable_equip&EQP_SHIELD)
  8358. return 0;
  8359. i = sd->equip_index[EQI_HAND_L];
  8360. if ( i < 0 || !sd->inventory_data[i] || sd->inventory_data[i]->type != IT_ARMOR )
  8361. return 0;
  8362. pc_unequipitem(sd,i,3);
  8363. }
  8364. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8365. break;
  8366. case SC_STRIPARMOR:
  8367. if (sd && !(flag&SCSTART_LOADED)) {
  8368. short i;
  8369. if(sd->bonus.unstripable_equip&EQP_ARMOR)
  8370. return 0;
  8371. i = sd->equip_index[EQI_ARMOR];
  8372. if ( i < 0 || !sd->inventory_data[i] )
  8373. return 0;
  8374. pc_unequipitem(sd,i,3);
  8375. }
  8376. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8377. break;
  8378. case SC_STRIPHELM:
  8379. if (sd && !(flag&SCSTART_LOADED)) {
  8380. short i;
  8381. if(sd->bonus.unstripable_equip&EQP_HELM)
  8382. return 0;
  8383. i = sd->equip_index[EQI_HEAD_TOP];
  8384. if ( i < 0 || !sd->inventory_data[i] )
  8385. return 0;
  8386. pc_unequipitem(sd,i,3);
  8387. }
  8388. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8389. break;
  8390. case SC_SHADOW_STRIP:
  8391. if (sd && !(flag&SCSTART_LOADED)) {
  8392. if (sd->bonus.unstripable_equip&EQP_SHADOW_GEAR)
  8393. return 0;
  8394. bool successFlag = false;
  8395. for( int i = EQI_SHADOW_ARMOR; i <= EQI_SHADOW_ACC_L; i++ ){
  8396. int index = sd->equip_index[i];
  8397. if( index >= 0 && sd->inventory_data[index] != nullptr ){
  8398. pc_unequipitem( sd, index, 3 );
  8399. successFlag = true;
  8400. }
  8401. }
  8402. if (!successFlag)
  8403. return 0;
  8404. }
  8405. if (tick == 1)
  8406. return 1;
  8407. break;
  8408. case SC_MERC_FLEEUP:
  8409. case SC_MERC_ATKUP:
  8410. case SC_MERC_HPUP:
  8411. case SC_MERC_SPUP:
  8412. case SC_MERC_HITUP:
  8413. if( bl->type != BL_MER )
  8414. return 0; // Stats only for Mercenaries
  8415. break;
  8416. case SC_STRFOOD:
  8417. if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > val1)
  8418. return 0;
  8419. break;
  8420. case SC_AGIFOOD:
  8421. if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > val1)
  8422. return 0;
  8423. break;
  8424. case SC_VITFOOD:
  8425. if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > val1)
  8426. return 0;
  8427. break;
  8428. case SC_INTFOOD:
  8429. if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > val1)
  8430. return 0;
  8431. break;
  8432. case SC_DEXFOOD:
  8433. if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > val1)
  8434. return 0;
  8435. break;
  8436. case SC_LUKFOOD:
  8437. if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > val1)
  8438. return 0;
  8439. break;
  8440. case SC_FOOD_STR_CASH:
  8441. if (sc->data[SC_STRFOOD] && sc->data[SC_STRFOOD]->val1 > val1)
  8442. return 0;
  8443. break;
  8444. case SC_FOOD_AGI_CASH:
  8445. if (sc->data[SC_AGIFOOD] && sc->data[SC_AGIFOOD]->val1 > val1)
  8446. return 0;
  8447. break;
  8448. case SC_FOOD_VIT_CASH:
  8449. if (sc->data[SC_VITFOOD] && sc->data[SC_VITFOOD]->val1 > val1)
  8450. return 0;
  8451. break;
  8452. case SC_FOOD_INT_CASH:
  8453. if (sc->data[SC_INTFOOD] && sc->data[SC_INTFOOD]->val1 > val1)
  8454. return 0;
  8455. break;
  8456. case SC_FOOD_DEX_CASH:
  8457. if (sc->data[SC_DEXFOOD] && sc->data[SC_DEXFOOD]->val1 > val1)
  8458. return 0;
  8459. break;
  8460. case SC_FOOD_LUK_CASH:
  8461. if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 > val1)
  8462. return 0;
  8463. break;
  8464. case SC_CAMOUFLAGE:
  8465. if( sd && pc_checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill_check_camouflage(bl,NULL) )
  8466. return 0;
  8467. break;
  8468. case SC__STRIPACCESSORY:
  8469. if( sd ) {
  8470. short i = -1;
  8471. if( !(sd->bonus.unstripable_equip&EQP_ACC_L) ) {
  8472. i = sd->equip_index[EQI_ACC_L];
  8473. if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR )
  8474. pc_unequipitem(sd,i,3); // Left-Accessory
  8475. }
  8476. if( !(sd->bonus.unstripable_equip&EQP_ACC_R) ) {
  8477. i = sd->equip_index[EQI_ACC_R];
  8478. if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR )
  8479. pc_unequipitem(sd,i,3); // Right-Accessory
  8480. }
  8481. if( i < 0 )
  8482. return 0;
  8483. }
  8484. if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
  8485. break;
  8486. case SC_C_MARKER:
  8487. if (src == bl)
  8488. return 0;
  8489. else {
  8490. struct status_change *tsc = status_get_sc(bl);
  8491. // Failed if the target is already marked and the new marker that isn't same marker
  8492. if (tsc && tsc->data[type] && tsc->data[type]->val2 != src->id)
  8493. return 0;
  8494. }
  8495. break;
  8496. case SC_MADNESSCANCEL:
  8497. if (sc->data[type]) { // Toggle the status but still consume requirements.
  8498. status_change_end(bl, type, INVALID_TIMER);
  8499. return 0;
  8500. }
  8501. break;
  8502. case SC_TOXIN:
  8503. case SC_PARALYSE:
  8504. case SC_VENOMBLEED:
  8505. case SC_MAGICMUSHROOM:
  8506. case SC_DEATHHURT:
  8507. case SC_PYREXIA:
  8508. case SC_OBLIVIONCURSE:
  8509. case SC_LEECHESEND:
  8510. if (val3 == 0) // Don't display icon on self
  8511. flag |= SCSTART_NOICON;
  8512. for (int32 i = SC_TOXIN; i <= SC_LEECHESEND; i++) {
  8513. if (sc->data[i] && sc->data[i]->val3 == 1) // It doesn't stack or even renew on the target
  8514. return 0;
  8515. else if (sc->data[i] && sc->data[i]->val3 == 0)
  8516. status_change_end(bl, static_cast<sc_type>(i), INVALID_TIMER); // End the bonus part on the caster
  8517. }
  8518. break;
  8519. case SC_SPIRIT:
  8520. if( sd ){
  8521. uint64 target_class = 0;
  8522. uint64 mask = MAPID_UPPERMASK;
  8523. switch( val2 ){
  8524. case SL_ALCHEMIST:
  8525. target_class = MAPID_ALCHEMIST;
  8526. break;
  8527. case SL_ASSASIN:
  8528. target_class = MAPID_ASSASSIN;
  8529. break;
  8530. case SL_BARDDANCER:
  8531. target_class = MAPID_BARDDANCER;
  8532. break;
  8533. case SL_BLACKSMITH:
  8534. target_class = MAPID_BLACKSMITH;
  8535. break;
  8536. case SL_CRUSADER:
  8537. target_class = MAPID_CRUSADER;
  8538. break;
  8539. case SL_HUNTER:
  8540. target_class = MAPID_HUNTER;
  8541. break;
  8542. case SL_KNIGHT:
  8543. target_class = MAPID_KNIGHT;
  8544. break;
  8545. case SL_MONK:
  8546. target_class = MAPID_MONK;
  8547. break;
  8548. case SL_PRIEST:
  8549. target_class = MAPID_PRIEST;
  8550. break;
  8551. case SL_ROGUE:
  8552. target_class = MAPID_ROGUE;
  8553. break;
  8554. case SL_SAGE:
  8555. target_class = MAPID_SAGE;
  8556. break;
  8557. case SL_SOULLINKER:
  8558. target_class = MAPID_SOUL_LINKER;
  8559. break;
  8560. case SL_STAR:
  8561. target_class = MAPID_STAR_GLADIATOR;
  8562. break;
  8563. case SL_SUPERNOVICE:
  8564. target_class = MAPID_SUPER_NOVICE;
  8565. break;
  8566. case SL_WIZARD:
  8567. target_class = MAPID_WIZARD;
  8568. break;
  8569. case SL_HIGH:
  8570. if( sd->status.base_level < 70 ){
  8571. return 0;
  8572. }
  8573. mask |= JOBL_UPPER;
  8574. target_class = MAPID_NOVICE_HIGH;
  8575. break;
  8576. default:
  8577. ShowError( "Unknown skill id %d for SC_SPIRIT.\n", val2 );
  8578. return 0;
  8579. }
  8580. if( ( sd->class_ & mask ) != target_class ){
  8581. return 0;
  8582. }
  8583. }else{
  8584. // Status change is only applicable for players
  8585. return 0;
  8586. }
  8587. break;
  8588. case SC_SOULGOLEM:
  8589. case SC_SOULSHADOW:
  8590. case SC_SOULFALCON:
  8591. case SC_SOULFAIRY:
  8592. if( sd == nullptr ){
  8593. // Status change is only applicable for players
  8594. return 0;
  8595. }
  8596. break;
  8597. }
  8598. // Check for OPT1 stacking
  8599. if (sc->opt1 > OPT1_NONE && scdb->opt1 > OPT1_NONE) {
  8600. for (const auto &status_it : status_db) {
  8601. sc_type opt1_type = status_it.second->type;
  8602. if (sc->data[opt1_type] && status_it.second->opt1 > OPT1_NONE)
  8603. status_change_end(bl, opt1_type, INVALID_TIMER);
  8604. }
  8605. }
  8606. // Before overlapping fail, one must check for status cured.
  8607. std::vector<sc_type> endlist;
  8608. if (type == SC_BERSERK && val3 == SC__BLOODYLUST) //There is some reasons that using SC_BERSERK first before SC__BLOODYLUST itself on Akinari's fix
  8609. endlist = status_db.getEnd(SC__BLOODYLUST);
  8610. else
  8611. endlist = scdb->end;
  8612. // End the SCs from the list
  8613. if (!endlist.empty()) {
  8614. for (const auto &it : endlist) {
  8615. sc_type rem_sc = it;
  8616. if (sc->data[rem_sc]) {
  8617. switch (rem_sc) {
  8618. case SC_BERSERK:
  8619. case SC_SATURDAYNIGHTFEVER:
  8620. sc->data[rem_sc]->val2 = 0; // Mark to not lose hp
  8621. default:
  8622. status_change_end(bl, rem_sc, INVALID_TIMER);
  8623. break;
  8624. }
  8625. }
  8626. }
  8627. }
  8628. // List of hardcoded status cured.
  8629. switch (type) {
  8630. case SC_BLESSING:
  8631. if (bl->type == BL_PC) {
  8632. // Remove Curse first, Stone is only removed if the target is not cursed
  8633. if (sc->data[SC_CURSE]) {
  8634. status_change_end(bl, SC_CURSE, INVALID_TIMER);
  8635. return 1; // End Curse and do not give stat boost
  8636. } else if (sc->data[SC_STONE]) {
  8637. status_change_end(bl, SC_STONE, INVALID_TIMER);
  8638. return 1; // End Stone and do not give stat boost
  8639. }
  8640. }
  8641. if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH)
  8642. status_change_end(bl, SC_SPIRIT, INVALID_TIMER);
  8643. break;
  8644. case SC_INCREASEAGI:
  8645. if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH)
  8646. status_change_end(bl, SC_SPIRIT, INVALID_TIMER);
  8647. break;
  8648. case SC_DELUGE:
  8649. if (sc->data[SC_FOGWALL] && sc->data[SC_BLIND])
  8650. status_change_end(bl, SC_BLIND, INVALID_TIMER);
  8651. break;
  8652. case SC_SILENCE:
  8653. if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF)
  8654. status_change_end(bl, SC_GOSPEL, INVALID_TIMER);
  8655. break;
  8656. case SC_IMPOSITIO:
  8657. if (sc->data[SC_IMPOSITIO] && sc->data[SC_IMPOSITIO]->val1 > val1) //Replace higher level effect for lower.
  8658. status_change_end(bl,SC_IMPOSITIO,INVALID_TIMER);
  8659. break;
  8660. case SC_ENDURE:
  8661. if (sd && sd->special_state.no_walk_delay)
  8662. return 1;
  8663. break;
  8664. case SC_MADOGEAR:
  8665. status_db.removeByStatusFlag(bl, { SCF_MADOCANCEL });
  8666. if (sd)
  8667. pc_bonus_script_clear(sd, BSF_REM_ON_MADOGEAR);
  8668. break;
  8669. default:
  8670. break;
  8671. }
  8672. // Check for overlapping fails
  8673. if( (sce = sc->data[type]) ) {
  8674. if (scdb->flag[SCF_OVERLAPFAIL])
  8675. return 0;
  8676. switch( type ) {
  8677. case SC_MERC_FLEEUP:
  8678. case SC_MERC_ATKUP:
  8679. case SC_MERC_HPUP:
  8680. case SC_MERC_SPUP:
  8681. case SC_MERC_HITUP:
  8682. if( sce->val1 > val1 )
  8683. val1 = sce->val1;
  8684. break;
  8685. case SC_ADRENALINE:
  8686. case SC_ADRENALINE2:
  8687. case SC_WEAPONPERFECTION:
  8688. case SC_OVERTHRUST:
  8689. if (sce->val2 > val2)
  8690. return 0;
  8691. break;
  8692. case SC_GOSPEL:
  8693. // Must not override a casting gospel char.
  8694. if(sce->val4 == BCT_SELF)
  8695. return 0;
  8696. if(sce->val1 > val1)
  8697. return 1;
  8698. break;
  8699. case SC_ENDURE:
  8700. if(sce->val4 && !val4)
  8701. return 1; // Don't let you override infinite endure.
  8702. if(sce->val1 > val1)
  8703. return 1;
  8704. break;
  8705. case SC_JAILED:
  8706. // When a player is already jailed, do not edit the jail data.
  8707. val2 = sce->val2;
  8708. val3 = sce->val3;
  8709. val4 = sce->val4;
  8710. break;
  8711. case SC_LERADSDEW:
  8712. if (sc && sc->data[SC_BERSERK])
  8713. return 0;
  8714. case SC_SHAPESHIFT:
  8715. case SC_PROPERTYWALK:
  8716. break;
  8717. case SC_LEADERSHIP:
  8718. case SC_GLORYWOUNDS:
  8719. case SC_SOULCOLD:
  8720. case SC_HAWKEYES:
  8721. if( sce->val4 && !val4 ) // You cannot override master guild aura
  8722. return 0;
  8723. break;
  8724. case SC_JOINTBEAT:
  8725. if (sc && sc->data[type]->val2 & BREAK_NECK)
  8726. return 0; // BREAK_NECK cannot be stacked with new breaks until the status is over.
  8727. val2 |= sce->val2; // Stackable ailments
  8728. default:
  8729. if (scdb->flag[SCF_OVERLAPIGNORELEVEL])
  8730. break;
  8731. if(sce->val1 > val1)
  8732. return 1; // Return true to not mess up skill animations. [Skotlex]
  8733. }
  8734. }
  8735. vd = status_get_viewdata(bl);
  8736. std::bitset<SCB_MAX> calc_flag = scdb->calc_flag;
  8737. if(!(flag&SCSTART_LOADED)) // &4 - Do not parse val settings when loading SCs
  8738. switch(type)
  8739. {
  8740. /* Permanent effects */
  8741. case SC_AETERNA:
  8742. case SC_MODECHANGE:
  8743. case SC_WEIGHT50:
  8744. case SC_WEIGHT90:
  8745. case SC_BROKENWEAPON:
  8746. case SC_BROKENARMOR:
  8747. case SC_READYSTORM:
  8748. case SC_READYDOWN:
  8749. case SC_READYCOUNTER:
  8750. case SC_READYTURN:
  8751. case SC_DODGE:
  8752. case SC_PUSH_CART:
  8753. case SC_SPRITEMABLE:
  8754. case SC_CLAN_INFO:
  8755. case SC_DAILYSENDMAILCNT:
  8756. case SC_SOULATTACK:
  8757. tick = INFINITE_TICK;
  8758. break;
  8759. case SC_KEEPING:
  8760. case SC_BARRIER: {
  8761. unit_data *ud = unit_bl2ud(bl);
  8762. if (ud)
  8763. ud->attackabletime = ud->canact_tick = ud->canmove_tick = gettick() + tick;
  8764. }
  8765. break;
  8766. case SC_DECREASEAGI:
  8767. case SC_INCREASEAGI:
  8768. case SC_ADORAMUS:
  8769. if (type == SC_ADORAMUS) {
  8770. // 1000% base chance to blind, but still can be resisted
  8771. sc_start(src, bl, SC_BLIND, 1000, val1, skill_get_time(scdb->skill_id, val1));
  8772. if (sc->data[SC_ADORAMUS])
  8773. return 0; //Adoramus can't refresh itself, but it can cause blind again
  8774. }
  8775. val2 = 2 + val1; // Agi change
  8776. break;
  8777. case SC_ENDURE:
  8778. val2 = 7; // Hit-count [Celest]
  8779. if( !(flag&SCSTART_NOAVOID) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg2(bl->m) && !map_getmapflag(bl->m, MF_BATTLEGROUND) && !val4 ) {
  8780. struct map_session_data *tsd;
  8781. if( sd ) {
  8782. int i;
  8783. for( i = 0; i < MAX_DEVOTION; i++ ) {
  8784. if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
  8785. status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  8786. }
  8787. }
  8788. else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
  8789. status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  8790. }
  8791. if( val4 )
  8792. tick = INFINITE_TICK;
  8793. break;
  8794. case SC_AUTOBERSERK:
  8795. if (status->hp < status->max_hp>>2 &&
  8796. (!sc->data[SC_PROVOKE] || sc->data[SC_PROVOKE]->val4==0))
  8797. sc_start4(src,bl,SC_PROVOKE,100,10,0,0,1,60000);
  8798. tick = INFINITE_TICK;
  8799. break;
  8800. case SC_SIGNUMCRUCIS:
  8801. val2 = 10 + 4*val1; // Def reduction
  8802. tick = INFINITE_TICK;
  8803. clif_emotion(bl, ET_SWEAT);
  8804. break;
  8805. case SC_MAXIMIZEPOWER:
  8806. tick_time = val2 = tick>0?tick:60000;
  8807. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  8808. break;
  8809. case SC_EDP:
  8810. val2 = val1 + 2; // Chance to Poison enemies.
  8811. #ifndef RENEWAL
  8812. val3 = 50*(val1+1); // Damage increase (+50 +50*lv%)
  8813. #endif
  8814. if (sd) {
  8815. uint16 poison_level = pc_checkskill(sd, GC_RESEARCHNEWPOISON);
  8816. if (poison_level > 0) {
  8817. tick += 30000; // Base of 30 seconds
  8818. tick += poison_level * 15 * 1000; // Additional 15 seconds per level
  8819. }
  8820. }
  8821. break;
  8822. case SC_POISONREACT:
  8823. #ifdef RENEWAL
  8824. val2=(val1 - ((val1-1) % 1 - 1)) / 2;
  8825. #else
  8826. val2=(val1+1)/2 + val1/10; // Number of counters [Skotlex]
  8827. #endif
  8828. val3=50; // + 5*val1; // Chance to counter. [Skotlex]
  8829. break;
  8830. case SC_MAGICROD:
  8831. val2 = val1*20; // SP gained
  8832. break;
  8833. case SC_KYRIE:
  8834. if( val4 ) { // Formulas for Praefatio
  8835. val2 = (status->max_hp * (val1 * 2 + 10) / 100) + val4 * 2; //%Max HP to absorb
  8836. val3 = 6 + val1; //Hits
  8837. } else { // Formulas for Kyrie Eleison
  8838. val2 = status->max_hp * (val1 * 2 + 10) / 100;
  8839. val3 = (val1 / 2 + 5);
  8840. }
  8841. break;
  8842. case SC_MAGICPOWER:
  8843. #ifdef RENEWAL
  8844. val3 = 5 * val1; // Matk% increase
  8845. #else
  8846. val2 = 1; // Lasts 1 invocation
  8847. val3 = 10 * val1; // Matk% increase
  8848. val4 = 0; // 0 = ready to be used, 1 = activated and running
  8849. #endif
  8850. break;
  8851. case SC_SACRIFICE:
  8852. val2 = 5; // Lasts 5 hits
  8853. tick = INFINITE_TICK;
  8854. break;
  8855. case SC_ENCPOISON:
  8856. val2= 250+50*val1; // Poisoning Chance (2.5+0.5%) in 1/10000 rate
  8857. break;
  8858. case SC_ELEMENTALCHANGE:
  8859. // val1 : Element Lvl (if called by skill lvl 1, takes random value between 1 and 4)
  8860. // val2 : Element (When no element, random one is picked)
  8861. // val3 : 0 = called by skill 1 = called by script (fixed level)
  8862. if( !val2 ) val2 = rnd()%ELE_ALL;
  8863. if( val1 == 1 && val3 == 0 )
  8864. val1 = 1 + rnd()%4;
  8865. else if( val1 > 4 )
  8866. val1 = 4; // Max Level
  8867. val3 = 0; // Not need to keep this info.
  8868. break;
  8869. case SC_PROVIDENCE:
  8870. val2 = val1*5; // Race/Ele resist
  8871. break;
  8872. case SC_REFLECTSHIELD:
  8873. val2 = 10+val1*3; // %Dmg reflected
  8874. // val4 used to mark if reflect shield is an inheritance bonus from Devotion
  8875. if( !(flag&SCSTART_NOAVOID) && (bl->type&(BL_PC|BL_MER)) ) {
  8876. struct map_session_data *tsd;
  8877. if( sd ) {
  8878. int i;
  8879. for( i = 0; i < MAX_DEVOTION; i++ ) {
  8880. if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
  8881. status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  8882. }
  8883. }
  8884. else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
  8885. status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  8886. }
  8887. break;
  8888. case SC_STRIPWEAPON:
  8889. if (!sd) // Watk reduction
  8890. val2 = 25;
  8891. break;
  8892. case SC_STRIPSHIELD:
  8893. if (!sd) // Def reduction
  8894. val2 = 15;
  8895. break;
  8896. case SC_STRIPARMOR:
  8897. if (!sd) // Vit reduction
  8898. val2 = 40;
  8899. break;
  8900. case SC_STRIPHELM:
  8901. if (!sd) // Int reduction
  8902. val2 = 40;
  8903. break;
  8904. case SC_AUTOSPELL:
  8905. // Val1 Skill LV of Autospell
  8906. // Val2 Skill ID to cast
  8907. // Val3 Max Lv to cast
  8908. #ifdef RENEWAL
  8909. val4 = val1 * 2; // Chance of casting
  8910. #else
  8911. val4 = 5 + val1*2; // Chance of casting
  8912. #endif
  8913. break;
  8914. case SC_VOLCANO:
  8915. {
  8916. int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition
  8917. uint8 i = max((val1-1)%5, 0);
  8918. #ifdef RENEWAL
  8919. val2 = 5 + val1 * 5; // ATK/MATK increase
  8920. #else
  8921. val2 = val1*10; // Watk increase
  8922. if (status->def_ele != ELE_FIRE)
  8923. val2 = 0;
  8924. #endif
  8925. val3 = enchant_eff[i];
  8926. }
  8927. break;
  8928. case SC_VIOLENTGALE:
  8929. {
  8930. int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition
  8931. uint8 i = max((val1-1)%5, 0);
  8932. val2 = val1*3; // Flee increase
  8933. #ifndef RENEWAL
  8934. if (status->def_ele != ELE_WIND)
  8935. val2 = 0;
  8936. #endif
  8937. val3 = enchant_eff[i];
  8938. }
  8939. break;
  8940. case SC_DELUGE:
  8941. {
  8942. int8 deluge_eff[] = { 5, 9, 12, 14, 15 }; // HP addition rate n/100
  8943. int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition
  8944. uint8 i = max((val1-1)%5, 0);
  8945. val2 = deluge_eff[i]; // HP increase
  8946. #ifndef RENEWAL
  8947. if (status->def_ele != ELE_WATER)
  8948. val2 = 0;
  8949. #endif
  8950. val3 = enchant_eff[i];
  8951. }
  8952. break;
  8953. case SC_SUITON:
  8954. if (!val2 || (sd && (sd->class_&MAPID_BASEMASK) == MAPID_NINJA)) {
  8955. // No penalties.
  8956. val2 = 0; // Agi penalty
  8957. val3 = 0; // Walk speed penalty
  8958. break;
  8959. }
  8960. val3 = 50;
  8961. val2 = 3*((val1+1)/3);
  8962. if (val1 > 4) val2--;
  8963. //Suiton is a special case, stop effect is forced and only happens when target enters it
  8964. if (!unit_blown_immune(bl, 0x1))
  8965. unit_stop_walking(bl, 9);
  8966. break;
  8967. case SC_ONEHAND:
  8968. case SC_TWOHANDQUICKEN:
  8969. val2 = 300;
  8970. if (val1 > 10) // For boss casted skills [Skotlex]
  8971. val2 += 20*(val1-10);
  8972. break;
  8973. case SC_MERC_QUICKEN:
  8974. val2 = 300;
  8975. break;
  8976. #ifndef RENEWAL_ASPD
  8977. case SC_SPEARQUICKEN:
  8978. val2 = 200+10*val1;
  8979. break;
  8980. #endif
  8981. case SC_DANCING:
  8982. // val1 : Skill ID + LV
  8983. // val2 : Skill Group of the Dance.
  8984. // val3 : Brings the skill_lv (merged into val1 here)
  8985. // val4 : Partner
  8986. if (val1 == CG_MOONLIT)
  8987. clif_status_change(bl,EFST_MOON,1,tick,0, 0, 0);
  8988. val1|= (val3<<16);
  8989. val3 = tick/1000; // Tick duration
  8990. tick_time = 1000; // [GodLesZ] tick time
  8991. break;
  8992. #ifndef RENEWAL
  8993. case SC_LONGING:
  8994. val2 = 500-100*val1; // Aspd penalty.
  8995. break;
  8996. #else
  8997. case SC_ENSEMBLEFATIGUE:
  8998. val2 = 30; // Speed and ASPD penalty
  8999. break;
  9000. case SC_RICHMANKIM:
  9001. val2 = 10 + 10 * val1; // Exp increase bonus
  9002. break;
  9003. case SC_DRUMBATTLE:
  9004. val2 = 15 + val1 * 5; // Atk increase
  9005. val3 = val1 * 15; // Def increase
  9006. break;
  9007. case SC_NIBELUNGEN:
  9008. val2 = rnd() % RINGNBL_MAX; // See e_nibelungen_status
  9009. break;
  9010. case SC_SIEGFRIED:
  9011. val2 = val1 * 3; // Elemental Resistance
  9012. val3 = val1 * 5; // Status ailment resistance
  9013. break;
  9014. case SC_WHISTLE:
  9015. val2 = 18 + 2 * val1; // Flee increase
  9016. val3 = (val1 + 1) / 2; // Perfect dodge increase
  9017. break;
  9018. case SC_ASSNCROS:
  9019. val2 = val1 < 10 ? val1 * 2 - 1 : 20; // ASPD increase
  9020. break;
  9021. case SC_POEMBRAGI:
  9022. val2 = 2 * val1; // Cast time reduction
  9023. val3 = 3 * val1; // After-cast delay reduction
  9024. break;
  9025. case SC_APPLEIDUN:
  9026. val2 = val1 < 10 ? 9 + val1 : 20; // HP rate increase
  9027. val3 = 2 * val1; // Potion recovery rate
  9028. break;
  9029. case SC_HUMMING:
  9030. val2 = 4 * val1; // Hit increase
  9031. break;
  9032. case SC_DONTFORGETME:
  9033. val2 = 1 + 30 * val1; // ASPD decrease
  9034. val3 = 5 + 2 * val1; // Movement speed adjustment.
  9035. break;
  9036. case SC_FORTUNE:
  9037. val2 = val1 * 10; // Critical increase
  9038. break;
  9039. case SC_SERVICE4U:
  9040. val2 = val1 < 10 ? 9 + val1 : 20; // MaxSP percent increase
  9041. val3 = 5 + val1; // SP cost reduction
  9042. break;
  9043. #endif
  9044. case SC_EXPLOSIONSPIRITS:
  9045. val2 = 75 + 25*val1; // Cri bonus
  9046. break;
  9047. case SC_ASPDPOTION0:
  9048. case SC_ASPDPOTION1:
  9049. case SC_ASPDPOTION2:
  9050. case SC_ASPDPOTION3:
  9051. val2 = 50*(2+type-SC_ASPDPOTION0);
  9052. break;
  9053. case SC_ATTHASTE_CASH:
  9054. val2 = 50*val1; // Just custom for pre-re
  9055. break;
  9056. case SC_NOCHAT:
  9057. // A hardcoded interval of 60 seconds is expected, as the time that SC_NOCHAT uses is defined by
  9058. // mmocharstatus.manner, each negative point results in 1 minute with this status activated.
  9059. // This is done this way because the message that the client displays is hardcoded, and only
  9060. // shows how many minutes are remaining. [Panikon]
  9061. tick = 60000;
  9062. val1 = battle_config.manner_system; // Mute filters.
  9063. if (sd) {
  9064. clif_changestatus(sd,SP_MANNER,sd->status.manner);
  9065. clif_updatestatus(sd,SP_MANNER);
  9066. }
  9067. break;
  9068. case SC_STONEWAIT:
  9069. val3 = max(1, tick - delay); // Petrify time
  9070. tick = delay;
  9071. break;
  9072. case SC_DPOISON:
  9073. // Lose 10/15% of your life as long as it doesn't brings life below 25%
  9074. if (status->hp > status->max_hp>>2) {
  9075. int diff = status->max_hp*(bl->type==BL_PC?10:15)/100;
  9076. if (status->hp - diff < status->max_hp>>2)
  9077. diff = status->hp - (status->max_hp>>2);
  9078. status_zap(bl, diff, 0);
  9079. }
  9080. // Fall through
  9081. case SC_STONE:
  9082. case SC_POISON:
  9083. case SC_BLEEDING:
  9084. case SC_BURNING:
  9085. tick_time = status_get_sc_interval(type);
  9086. val4 = tick - tick_time; // Remaining time
  9087. break;
  9088. case SC_TOXIN:
  9089. if (val3 == 1) // Target
  9090. tick_time = status_get_sc_interval(type);
  9091. else // Caster
  9092. tick_time = 1000;
  9093. val4 = tick - tick_time; // Remaining time
  9094. break;
  9095. case SC_DEATHHURT:
  9096. if (val3 == 1)
  9097. break;
  9098. tick_time = status_get_sc_interval(type);
  9099. val4 = tick - tick_time; // Remaining time
  9100. case SC_LEECHESEND:
  9101. if (val3 == 0)
  9102. break;
  9103. tick_time = status_get_sc_interval(type);
  9104. val4 = tick - tick_time; // Remaining time
  9105. break;
  9106. case SC_PYREXIA:
  9107. if (val3 == 1) { // Target
  9108. // Causes blind for duration of pyrexia, unreducable and unavoidable, but can be healed with e.g. green potion
  9109. status_change_start(src, bl, SC_BLIND, 10000, val1, 0, 0, 0, tick, SCSTART_NOAVOID | SCSTART_NOTICKDEF | SCSTART_NORATEDEF);
  9110. tick_time = status_get_sc_interval(type);
  9111. val4 = tick - tick_time; // Remaining time
  9112. } else // Caster
  9113. val2 = 15; // CRIT % and ATK % increase
  9114. break;
  9115. case SC_VENOMBLEED:
  9116. if (val3 == 0) // Caster
  9117. val2 = 30; // Reflect damage % reduction
  9118. break;
  9119. case SC_MAGICMUSHROOM:
  9120. if (val3 == 1) { // Target
  9121. tick_time = status_get_sc_interval(type);
  9122. val4 = tick - tick_time; // Remaining time
  9123. } else // Caster
  9124. val2 = 10; // After-cast delay % reduction
  9125. break;
  9126. case SC_CONFUSION:
  9127. if (!val4)
  9128. clif_emotion(bl,ET_QUESTION);
  9129. break;
  9130. case SC_S_LIFEPOTION:
  9131. case SC_L_LIFEPOTION:
  9132. if( val1 == 0 ) return 0;
  9133. // val1 = heal percent/amout
  9134. // val2 = seconds between heals
  9135. // val4 = total of heals
  9136. if( val2 < 1 ) val2 = 1;
  9137. if( (val4 = tick/(val2 * 1000)) < 1 )
  9138. val4 = 1;
  9139. tick_time = val2 * 1000; // [GodLesZ] tick time
  9140. break;
  9141. case SC_BOSSMAPINFO:
  9142. if( sd != NULL ) {
  9143. struct mob_data *boss_md = map_getmob_boss(bl->m); // Search for Boss on this Map
  9144. if( boss_md == NULL ) { // No MVP on this map
  9145. clif_bossmapinfo(sd, NULL, BOSS_INFO_NOT);
  9146. return 0;
  9147. }
  9148. val1 = boss_md->bl.id;
  9149. tick_time = 1000; // [GodLesZ] tick time
  9150. val4 = tick / tick_time;
  9151. }
  9152. break;
  9153. case SC_HIDING:
  9154. val2 = tick/1000;
  9155. tick_time = 1000; // [GodLesZ] tick time
  9156. val3 = 0; // Unused, previously speed adjustment
  9157. val4 = val1+3; // Seconds before SP substraction happen.
  9158. break;
  9159. case SC_CHASEWALK:
  9160. val2 = tick>0?tick:10000; // Interval at which SP is drained.
  9161. val3 = 35 - 5 * val1; // Speed adjustment.
  9162. if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_ROGUE)
  9163. val3 -= 40;
  9164. val4 = 10+val1*2; // SP cost.
  9165. if (map_flag_gvg2(bl->m) || map_getmapflag(bl->m, MF_BATTLEGROUND)) val4 *= 5;
  9166. break;
  9167. case SC_CLOAKING:
  9168. if (!sd) // Monsters should be able to walk with no penalties. [Skotlex]
  9169. val1 = 10;
  9170. tick_time = val2 = tick>0?tick:60000; // SP consumption rate.
  9171. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  9172. val3 = 0; // Unused, previously walk speed adjustment
  9173. // val4&1 signals the presence of a wall.
  9174. // val4&2 makes cloak not end on normal attacks [Skotlex]
  9175. // val4&4 makes cloak not end on using skills
  9176. if (bl->type == BL_PC || (bl->type == BL_MOB && ((TBL_MOB*)bl)->special_state.clone) ) // Standard cloaking.
  9177. val4 |= battle_config.pc_cloak_check_type&7;
  9178. else
  9179. val4 |= battle_config.monster_cloak_check_type&7;
  9180. break;
  9181. case SC_SIGHT: /* splash status */
  9182. case SC_RUWACH:
  9183. case SC_SIGHTBLASTER:
  9184. val3 = skill_get_splash(val2, val1); // Val2 should bring the skill-id.
  9185. val2 = tick/20;
  9186. tick_time = 20; // [GodLesZ] tick time
  9187. break;
  9188. case SC_AUTOGUARD:
  9189. if( !(flag&SCSTART_NOAVOID) ) {
  9190. struct map_session_data *tsd;
  9191. int i;
  9192. for( i = val2 = 0; i < val1; i++) {
  9193. int t = 5-(i>>1);
  9194. val2 += (t < 0)? 1:t;
  9195. }
  9196. if( bl->type&(BL_PC|BL_MER) ) {
  9197. if( sd ) {
  9198. for( i = 0; i < MAX_DEVOTION; i++ ) {
  9199. if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
  9200. status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  9201. }
  9202. }
  9203. else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
  9204. status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON);
  9205. }
  9206. }
  9207. break;
  9208. case SC_DEFENDER:
  9209. if (!(flag&SCSTART_NOAVOID)) {
  9210. val2 = 5 + 15*val1; // Damage reduction
  9211. val3 = 0; // Unused, previously speed adjustment
  9212. val4 = 250 - 50*val1; // Aspd adjustment
  9213. if (sd) {
  9214. struct map_session_data *tsd;
  9215. int i;
  9216. for (i = 0; i < MAX_DEVOTION; i++) { // See if there are devoted characters, and pass the status to them. [Skotlex]
  9217. if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])))
  9218. status_change_start(src,&tsd->bl,type,10000,val1,val2,val3,val4,tick,SCSTART_NOAVOID);
  9219. }
  9220. }
  9221. }
  9222. break;
  9223. case SC_TENSIONRELAX:
  9224. if (sd) {
  9225. pc_setsit(sd);
  9226. skill_sit(sd, true);
  9227. clif_sitting(&sd->bl);
  9228. }
  9229. val2 = 12; // SP cost
  9230. tick_time = 10000; // Decrease at 10secs intervals.
  9231. val3 = tick / tick_time;
  9232. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  9233. break;
  9234. case SC_PARRYING:
  9235. val2 = 20 + val1*3; // Block Chance
  9236. break;
  9237. case SC_WINDWALK:
  9238. val2 = (val1+1)/2; // Flee bonus is 1/1/2/2/3/3/4/4/5/5
  9239. break;
  9240. case SC_JOINTBEAT:
  9241. if( val2&BREAK_NECK )
  9242. sc_start2(src,bl,SC_BLEEDING,100,val1,val3,skill_get_time2(scdb->skill_id,val1));
  9243. break;
  9244. case SC_BERSERK:
  9245. if( val3 == SC__BLOODYLUST )
  9246. sc_start(src,bl,(sc_type)val3,100,val1,tick);
  9247. else
  9248. sc_start4(src,bl, SC_ENDURE, 100,10,0,0,1, tick);
  9249. // HP healing is performing after the calc_status call.
  9250. // Val2 holds HP penalty
  9251. if (!val4) val4 = skill_get_time2(scdb->skill_id,val1);
  9252. if (!val4) val4 = 10000; // Val4 holds damage interval
  9253. val3 = tick/val4; // val3 holds skill duration
  9254. tick_time = val4; // [GodLesZ] tick time
  9255. break;
  9256. case SC_GOSPEL:
  9257. if(val4 == BCT_SELF) { // Self effect
  9258. val2 = tick/10000;
  9259. tick_time = 10000; // [GodLesZ] tick time
  9260. status_change_clear_buffs(bl, SCCB_BUFFS|SCCB_DEBUFFS|SCCB_CHEM_PROTECT); // Remove buffs/debuffs
  9261. }
  9262. break;
  9263. case SC_MARIONETTE:
  9264. {
  9265. int stat;
  9266. val3 = 0;
  9267. val4 = 0;
  9268. stat = ( sd ? sd->status.str : status_get_base_status(bl)->str ) / 2; val3 |= cap_value(stat,0,0xFF)<<16;
  9269. stat = ( sd ? sd->status.agi : status_get_base_status(bl)->agi ) / 2; val3 |= cap_value(stat,0,0xFF)<<8;
  9270. stat = ( sd ? sd->status.vit : status_get_base_status(bl)->vit ) / 2; val3 |= cap_value(stat,0,0xFF);
  9271. stat = ( sd ? sd->status.int_: status_get_base_status(bl)->int_) / 2; val4 |= cap_value(stat,0,0xFF)<<16;
  9272. stat = ( sd ? sd->status.dex : status_get_base_status(bl)->dex ) / 2; val4 |= cap_value(stat,0,0xFF)<<8;
  9273. stat = ( sd ? sd->status.luk : status_get_base_status(bl)->luk ) / 2; val4 |= cap_value(stat,0,0xFF);
  9274. break;
  9275. }
  9276. case SC_MARIONETTE2:
  9277. {
  9278. int stat,max_stat;
  9279. // Fetch caster information
  9280. struct block_list *pbl = map_id2bl(val1);
  9281. struct status_change *psc = pbl?status_get_sc(pbl):NULL;
  9282. struct status_change_entry *psce = psc?psc->data[SC_MARIONETTE]:NULL;
  9283. // Fetch target's stats
  9284. struct status_data* status2 = status_get_status_data(bl); // Battle status
  9285. if (!psce)
  9286. return 0;
  9287. val3 = 0;
  9288. val4 = 0;
  9289. max_stat = battle_config.max_parameter; // Cap to 99 (default)
  9290. stat = (psce->val3 >>16)&0xFF; stat = min(stat, max_stat - status2->str ); val3 |= cap_value(stat,0,0xFF)<<16;
  9291. stat = (psce->val3 >> 8)&0xFF; stat = min(stat, max_stat - status2->agi ); val3 |= cap_value(stat,0,0xFF)<<8;
  9292. stat = (psce->val3 >> 0)&0xFF; stat = min(stat, max_stat - status2->vit ); val3 |= cap_value(stat,0,0xFF);
  9293. stat = (psce->val4 >>16)&0xFF; stat = min(stat, max_stat - status2->int_); val4 |= cap_value(stat,0,0xFF)<<16;
  9294. stat = (psce->val4 >> 8)&0xFF; stat = min(stat, max_stat - status2->dex ); val4 |= cap_value(stat,0,0xFF)<<8;
  9295. stat = (psce->val4 >> 0)&0xFF; stat = min(stat, max_stat - status2->luk ); val4 |= cap_value(stat,0,0xFF);
  9296. break;
  9297. }
  9298. case SC_SPIRIT:
  9299. //1st Transcendent Spirit works similar to Marionette Control
  9300. if(sd && val2 == SL_HIGH) {
  9301. int stat,max_stat;
  9302. struct status_data *status2 = status_get_base_status(bl);
  9303. val3 = 0;
  9304. val4 = 0;
  9305. max_stat = (status_get_lv(bl)-10<50)?status_get_lv(bl)-10:50;
  9306. stat = max(0, max_stat - status2->str); val3 |= cap_value(stat,0,0xFF)<<16;
  9307. stat = max(0, max_stat - status2->agi ); val3 |= cap_value(stat,0,0xFF)<<8;
  9308. stat = max(0, max_stat - status2->vit ); val3 |= cap_value(stat,0,0xFF);
  9309. stat = max(0, max_stat - status2->int_); val4 |= cap_value(stat,0,0xFF)<<16;
  9310. stat = max(0, max_stat - status2->dex ); val4 |= cap_value(stat,0,0xFF)<<8;
  9311. stat = max(0, max_stat - status2->luk ); val4 |= cap_value(stat,0,0xFF);
  9312. }
  9313. break;
  9314. case SC_REJECTSWORD:
  9315. val2 = 15*val1; // Reflect chance
  9316. val3 = 3; // Reflections
  9317. tick = INFINITE_TICK;
  9318. break;
  9319. case SC_MEMORIZE:
  9320. val2 = 5; // Memorized casts.
  9321. tick = INFINITE_TICK;
  9322. break;
  9323. #ifndef RENEWAL
  9324. case SC_GRAVITATION:
  9325. val2 = 50*val1; // aspd reduction
  9326. break;
  9327. #endif
  9328. case SC_REGENERATION:
  9329. if (val1 == 1)
  9330. val2 = 2;
  9331. else
  9332. val2 = val1; // HP Regerenation rate: 200% 200% 300%
  9333. val3 = val1; // SP Regeneration Rate: 100% 200% 300%
  9334. // If val4 comes set, this blocks regen rather than increase it.
  9335. break;
  9336. case SC_DEVOTION:
  9337. {
  9338. struct block_list *d_bl;
  9339. struct status_change *d_sc;
  9340. if( (d_bl = map_id2bl(val1)) && (d_sc = status_get_sc(d_bl)) && d_sc->count ) { // Inherits Status From Source
  9341. const enum sc_type types[] = { SC_AUTOGUARD, SC_DEFENDER, SC_REFLECTSHIELD, SC_ENDURE };
  9342. int i = (map_flag_gvg2(bl->m) || map_getmapflag(bl->m, MF_BATTLEGROUND))?2:3;
  9343. while( i >= 0 ) {
  9344. enum sc_type type2 = types[i];
  9345. if( d_sc->data[type2] )
  9346. status_change_start(d_bl, bl, type2, 10000, d_sc->data[type2]->val1, 0, 0, (type2 == SC_REFLECTSHIELD ? 1 : 0), skill_get_time(status_db.getSkill(type2),d_sc->data[type2]->val1), (type2 == SC_DEFENDER) ? SCSTART_NOAVOID : SCSTART_NOAVOID|SCSTART_NOICON);
  9347. i--;
  9348. }
  9349. }
  9350. break;
  9351. }
  9352. case SC_COMA: // Coma. Sends a char to 1HP. If val2, do not zap sp
  9353. status_zap(bl, status->hp-1, val2?0:status->sp);
  9354. return 1;
  9355. break;
  9356. case SC_CLOSECONFINE2:
  9357. {
  9358. struct block_list *src2 = val2?map_id2bl(val2):NULL;
  9359. struct status_change *sc2 = src2?status_get_sc(src2):NULL;
  9360. struct status_change_entry *sce2 = sc2?sc2->data[SC_CLOSECONFINE]:NULL;
  9361. if (src2 && sc2) {
  9362. if (!sce2) { // Start lock on caster.
  9363. #ifdef RENEWAL
  9364. val3 = 50; // Flee increase
  9365. #else
  9366. val3 = 10; // Flee increase
  9367. #endif
  9368. sc_start4(src2,src2,SC_CLOSECONFINE,100,val1,1,val3,0,tick+1000);
  9369. } else { // Increase count of locked enemies and refresh time.
  9370. (sce2->val2)++;
  9371. delete_timer(sce2->timer, status_change_timer);
  9372. sce2->timer = add_timer(gettick()+tick+1000, status_change_timer, src2->id, SC_CLOSECONFINE);
  9373. }
  9374. } else // Status failed.
  9375. return 0;
  9376. }
  9377. break;
  9378. case SC_KAITE:
  9379. val2 = 1+val1/5; // Number of bounces: 1 + skill_lv/5
  9380. break;
  9381. case SC_KAUPE:
  9382. switch (val1) {
  9383. case 3: // 33*3 + 1 -> 100%
  9384. val2++;
  9385. case 1:
  9386. case 2: // 33, 66%
  9387. val2 += 33*val1;
  9388. val3 = 1; // Dodge 1 attack total.
  9389. break;
  9390. default: // Custom. For high level mob usage, higher level means more blocks. [Skotlex]
  9391. val2 = 100;
  9392. val3 = val1-2;
  9393. break;
  9394. }
  9395. break;
  9396. case SC_COMBO:
  9397. {
  9398. // val1: Skill ID
  9399. // val2: When given, target (for autotargetting skills)
  9400. // val3: When set, this combo time should NOT delay attack/movement
  9401. // val3: If set to 2 this combo will delay ONLY attack
  9402. // val3: TK: Last used kick
  9403. // val4: TK: Combo time
  9404. struct unit_data *ud = unit_bl2ud(bl);
  9405. if ( ud && (!val3 || val3 == 2) ) {
  9406. tick += 300 * battle_config.combo_delay_rate/100;
  9407. ud->attackabletime = gettick()+tick;
  9408. if( !val3 )
  9409. unit_set_walkdelay(bl, gettick(), tick, 1);
  9410. }
  9411. val3 = 0;
  9412. val4 = tick;
  9413. break;
  9414. }
  9415. case SC_EARTHSCROLL:
  9416. val2 = 11-val1; // Chance to consume: 11-skill_lv%
  9417. break;
  9418. case SC_RUN:
  9419. {
  9420. //Store time at which you started running.
  9421. t_tick currenttick = gettick();
  9422. // Note: this int64 value is stored in two separate int32 variables (FIXME)
  9423. val3 = (int)(currenttick & 0x00000000ffffffffLL);
  9424. val4 = (int)((currenttick & 0xffffffff00000000LL) >> 32);
  9425. tick = INFINITE_TICK;
  9426. break;
  9427. }
  9428. case SC_KAAHI:
  9429. val2 = 200*val1; // HP heal
  9430. val3 = 5*val1; // SP cost
  9431. break;
  9432. case SC_BLESSING:
  9433. if (bl->type == BL_PC || (!undead_flag && status->race != RC_DEMON))
  9434. val2 = val1;
  9435. else
  9436. val2 = 0; // 0 -> Half stat.
  9437. break;
  9438. case SC_TRICKDEAD:
  9439. if (vd) vd->dead_sit = 1;
  9440. tick = INFINITE_TICK;
  9441. break;
  9442. case SC_CONCENTRATE:
  9443. val2 = 2 + val1;
  9444. if (sd) { // Store the card-bonus data that should not count in the %
  9445. val3 = sd->indexed_bonus.param_bonus[1]; // Agi
  9446. val4 = sd->indexed_bonus.param_bonus[4]; // Dex
  9447. } else
  9448. val3 = val4 = 0;
  9449. break;
  9450. case SC_MAXOVERTHRUST:
  9451. val2 = 20*val1; // Power increase
  9452. break;
  9453. case SC_OVERTHRUST:
  9454. case SC_ADRENALINE2:
  9455. case SC_ADRENALINE:
  9456. case SC_WEAPONPERFECTION:
  9457. {
  9458. struct map_session_data * s_sd = BL_CAST(BL_PC, src);
  9459. if (type == SC_OVERTHRUST) {
  9460. // val2 holds if it was casted on self, or is bonus received from others
  9461. #ifdef RENEWAL
  9462. val3 = (val2) ? 5 * val1 : (val1 > 4) ? 15 : (val1 > 2) ? 10 : 5; // Power increase
  9463. #else
  9464. val3 = (val2) ? 5 * val1 : 5; // Power increase
  9465. #endif
  9466. }
  9467. else if (type == SC_ADRENALINE2 || type == SC_ADRENALINE) {
  9468. val3 = (val2) ? 300 : 200; // Aspd increase
  9469. }
  9470. if (s_sd && pc_checkskill(s_sd, BS_HILTBINDING) > 0)
  9471. tick += tick / 10; //If caster has Hilt Binding, duration increases by 10%
  9472. }
  9473. break;
  9474. case SC_CONCENTRATION:
  9475. #ifdef RENEWAL
  9476. val2 = 5 + val1 * 2; // Batk/Watk Increase
  9477. val4 = 5 + val1 * 2; // Def reduction
  9478. #else
  9479. val2 = 5*val1; // Batk/Watk Increase
  9480. val4 = 5*val1; // Def reduction
  9481. #endif
  9482. val3 = 10*val1; // Hit Increase
  9483. sc_start(src, bl, SC_ENDURE, 100, 1, tick); // Level 1 Endure effect
  9484. break;
  9485. case SC_ANGELUS:
  9486. val2 = 5*val1; // def increase
  9487. break;
  9488. case SC_IMPOSITIO:
  9489. val2 = 5*val1; // WATK/MATK increase
  9490. break;
  9491. case SC_MELTDOWN:
  9492. val2 = 100*val1; // Chance to break weapon
  9493. val3 = 70*val1; // Change to break armor
  9494. break;
  9495. case SC_TRUESIGHT:
  9496. val2 = 10*val1; // Critical increase
  9497. val3 = 3*val1; // Hit increase
  9498. break;
  9499. case SC_SUN_COMFORT:
  9500. val2 = (status_get_lv(bl) + status->dex + status->luk)/2; // def increase
  9501. break;
  9502. case SC_MOON_COMFORT:
  9503. val2 = (status_get_lv(bl) + status->dex + status->luk)/10; // flee increase
  9504. break;
  9505. case SC_STAR_COMFORT:
  9506. val2 = (status_get_lv(bl) + status->dex + status->luk); // Aspd increase
  9507. break;
  9508. case SC_QUAGMIRE:
  9509. val2 = (sd?5:10)*val1; // Agi/Dex decrease.
  9510. break;
  9511. // gs_something1 [Vicious]
  9512. case SC_GATLINGFEVER:
  9513. val2 = 20*val1; // Aspd increase
  9514. val3 = 20+10*val1; // Atk increase
  9515. val4 = 5*val1; // Flee decrease
  9516. break;
  9517. case SC_FLING:
  9518. if (bl->type == BL_PC)
  9519. val2 = 0; // No armor reduction to players.
  9520. else
  9521. val2 = 5*val1; // Def reduction
  9522. val3 = 5*val1; // Def2 reduction
  9523. break;
  9524. case SC_PROVOKE:
  9525. val2 = 2+3*val1; // Atk increase
  9526. val3 = 5+5*val1; // Def reduction.
  9527. // val4 signals autoprovoke.
  9528. break;
  9529. case SC_AVOID:
  9530. // val2 = 10*val1; // Speed change rate.
  9531. break;
  9532. case SC_DEFENCE:
  9533. #ifdef RENEWAL
  9534. val2 = 5 + (val1 * 5); // Vit bonus
  9535. #else
  9536. val2 = 2*val1; // Def bonus
  9537. #endif
  9538. break;
  9539. case SC_BLOODLUST:
  9540. val2 = 20+10*val1; // Atk rate change.
  9541. val3 = 3*val1; // Leech chance
  9542. val4 = 20; // Leech percent
  9543. break;
  9544. case SC_FLEET:
  9545. val2 = 30*val1; // Aspd change
  9546. val3 = 5+5*val1; // bAtk/wAtk rate change
  9547. break;
  9548. case SC_MINDBREAKER:
  9549. val2 = 20*val1; // matk increase.
  9550. val3 = 12*val1; // mdef2 reduction.
  9551. break;
  9552. case SC_JAILED:
  9553. // Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time.
  9554. tick = val1>0?1000:250;
  9555. if (sd) {
  9556. if (sd->mapindex != val2) {
  9557. int pos = (bl->x&0xFFFF)|(bl->y<<16), // Current Coordinates
  9558. map_idx = sd->mapindex; // Current Map
  9559. // 1. Place in Jail (val2 -> Jail Map, val3 -> x, val4 -> y
  9560. pc_setpos(sd,(unsigned short)val2,val3,val4, CLR_TELEPORT);
  9561. // 2. Set restore point (val3 -> return map, val4 return coords
  9562. val3 = map_idx;
  9563. val4 = pos;
  9564. } else if (!val3 || val3 == sd->mapindex) { // Use save point.
  9565. val3 = sd->status.save_point.map;
  9566. val4 = (sd->status.save_point.x&0xFFFF)
  9567. |(sd->status.save_point.y<<16);
  9568. }
  9569. }
  9570. break;
  9571. case SC_UTSUSEMI:
  9572. val2=(val1+1)/2; // Number of hits blocked
  9573. val3=skill_get_blewcount(NJ_UTSUSEMI, val1); // knockback value.
  9574. break;
  9575. case SC_BUNSINJYUTSU:
  9576. val2=(val1+1)/2; // Number of hits blocked
  9577. break;
  9578. case SC_CHANGE:
  9579. val2= 30*val1; // Vit increase
  9580. val3= 20*val1; // Int increase
  9581. break;
  9582. case SC_SWOO:
  9583. if(status_has_mode(status,MD_STATUSIMMUNE))
  9584. tick /= 5; // !TODO: Reduce skill's duration. But for how long?
  9585. break;
  9586. case SC_ARMOR:
  9587. // NPC_DEFENDER:
  9588. val2 = 80; // Damage reduction
  9589. // Attack requirements to be blocked:
  9590. val3 = BF_LONG; // Range
  9591. val4 = BF_WEAPON|BF_MISC; // Type
  9592. break;
  9593. case SC_ENCHANTARMS:
  9594. // Make sure the received element is valid.
  9595. if (val1 >= ELE_ALL)
  9596. val1 = val1%ELE_ALL;
  9597. else if (val1 < 0)
  9598. val1 = rnd()%ELE_ALL;
  9599. break;
  9600. case SC_CRITICALWOUND:
  9601. val2 = 20*val1; // Heal effectiveness decrease
  9602. break;
  9603. case SC_MAGICMIRROR:
  9604. // Level 1 ~ 5 & 6 ~ 10 has different duration
  9605. // Level 6 ~ 10 use effect of level 1 ~ 5
  9606. val1 = 1 + ((val1-1)%5);
  9607. case SC_SLOWCAST:
  9608. val2 = 20*val1; // Magic reflection/cast rate
  9609. break;
  9610. case SC_ARMORCHANGE:
  9611. if (val2 == NPC_ANTIMAGIC) { // Boost mdef
  9612. val2 =-20;
  9613. val3 = 20;
  9614. } else { // Boost def
  9615. val2 = 20;
  9616. val3 =-20;
  9617. }
  9618. // Level 1 ~ 5 & 6 ~ 10 has different duration
  9619. // Level 6 ~ 10 use effect of level 1 ~ 5
  9620. val1 = 1 + ((val1-1)%5);
  9621. val2 *= val1; // 20% per level
  9622. val3 *= val1;
  9623. break;
  9624. case SC_EXPBOOST:
  9625. case SC_JEXPBOOST:
  9626. case SC_JP_EVENT04:
  9627. if (val1 < 0)
  9628. val1 = 0;
  9629. break;
  9630. case SC_INCFLEE2:
  9631. case SC_INCCRI:
  9632. val2 = val1*10; // Actual boost (since 100% = 1000)
  9633. break;
  9634. case SC_SUFFRAGIUM:
  9635. #ifdef RENEWAL
  9636. val2 = 5 + val1 * 5; // Speed cast decrease
  9637. #else
  9638. val2 = 15 * val1; // Speed cast decrease
  9639. #endif
  9640. break;
  9641. case SC_INCHEALRATE:
  9642. if (val1 < 1)
  9643. val1 = 1;
  9644. break;
  9645. case SC_DOUBLECAST:
  9646. val2 = 30+10*val1; // Trigger rate
  9647. break;
  9648. case SC_KAIZEL:
  9649. val2 = 10*val1; // % of life to be revived with
  9650. break;
  9651. // case SC_ARMOR_ELEMENT_WATER:
  9652. // case SC_ARMOR_ELEMENT_EARTH:
  9653. // case SC_ARMOR_ELEMENT_FIRE:
  9654. // case SC_ARMOR_ELEMENT_WIND:
  9655. // case SC_ARMOR_RESIST:
  9656. // Mod your resistance against elements:
  9657. // val1 = water | val2 = earth | val3 = fire | val4 = wind
  9658. // break;
  9659. // case ????:
  9660. // Place here SCs that have no SCB_* data, no skill associated, no ICON
  9661. // associated, and yet are not wrong/unknown. [Skotlex]
  9662. // break;
  9663. case SC_MERC_FLEEUP:
  9664. case SC_MERC_ATKUP:
  9665. case SC_MERC_HITUP:
  9666. val2 = 15 * val1;
  9667. break;
  9668. case SC_MERC_HPUP:
  9669. case SC_MERC_SPUP:
  9670. val2 = 5 * val1;
  9671. break;
  9672. case SC_REBIRTH:
  9673. val2 = 20*val1; // % of life to be revived with
  9674. break;
  9675. case SC_MANU_DEF:
  9676. case SC_MANU_ATK:
  9677. case SC_MANU_MATK:
  9678. val2 = 1; // Manuk group
  9679. break;
  9680. case SC_SPL_DEF:
  9681. case SC_SPL_ATK:
  9682. case SC_SPL_MATK:
  9683. val2 = 2; // Splendide group
  9684. break;
  9685. /* General */
  9686. case SC_FEAR:
  9687. status_change_start(src,bl,SC_ANKLE,10000,val1,0,0,0,2000,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF);
  9688. break;
  9689. /* Rune Knight */
  9690. case SC_DEATHBOUND:
  9691. val2 = 500 + 100 * val1;
  9692. break;
  9693. case SC_STONEHARDSKIN:
  9694. if (!status_charge(bl, status->hp / 5, 0)) // 20% of HP
  9695. return 0;
  9696. if (sd)
  9697. val1 = sd->status.job_level * pc_checkskill(sd, RK_RUNEMASTERY) / 4; // DEF/MDEF Increase
  9698. break;
  9699. case SC_REFRESH:
  9700. status_heal(bl, status_get_max_hp(bl) * 25 / 100, 0, 1);
  9701. status_change_clear_buffs(bl, SCCB_REFRESH);
  9702. break;
  9703. case SC_MILLENNIUMSHIELD:
  9704. {
  9705. int8 chance = rnd()%100;
  9706. val2 = ((chance < 20) ? 4 : (chance < 50) ? 3 : 2); // Shield count
  9707. val3 = 1000; // Shield HP
  9708. clif_millenniumshield(bl, val2);
  9709. }
  9710. break;
  9711. case SC_ABUNDANCE:
  9712. val4 = tick / 10000;
  9713. tick_time = 10000; // [GodLesZ] tick time
  9714. break;
  9715. case SC_GIANTGROWTH:
  9716. val2 = 30; // Damage success rate and STR increase
  9717. break;
  9718. case SC_LUXANIMA:
  9719. val2 = 15; // Storm Blast success %
  9720. val3 = 30; // Damage/HP/SP % increase
  9721. break;
  9722. /* Arch Bishop */
  9723. case SC_RENOVATIO:
  9724. val4 = tick / 5000;
  9725. tick_time = 5000;
  9726. break;
  9727. case SC_SECRAMENT:
  9728. val2 = 10 * val1;
  9729. break;
  9730. case SC_VENOMIMPRESS:
  9731. val2 = 10 * val1;
  9732. break;
  9733. case SC_WEAPONBLOCKING:
  9734. val2 = 10 + 2 * val1; // Chance
  9735. val4 = tick / 5000;
  9736. tick_time = 5000; // [GodLesZ] tick time
  9737. break;
  9738. case SC_OBLIVIONCURSE:
  9739. if (val3 == 0)
  9740. break;
  9741. val4 = tick / 3000;
  9742. tick_time = 3000; // [GodLesZ] tick time
  9743. break;
  9744. case SC_CLOAKINGEXCEED:
  9745. val2 = (val1 + 1) / 2; // Hits
  9746. val3 = (val1 - 1) * 10; // Walk speed
  9747. if (bl->type == BL_PC)
  9748. val4 |= battle_config.pc_cloak_check_type&7;
  9749. else
  9750. val4 |= battle_config.monster_cloak_check_type&7;
  9751. tick_time = 1000; // [GodLesZ] tick time
  9752. break;
  9753. case SC_HALLUCINATIONWALK:
  9754. case SC_NPC_HALLUCINATIONWALK:
  9755. val2 = 50 * val1; // Evasion rate of physical attacks. Flee
  9756. val3 = 10 * val1; // Evasion rate of magical attacks.
  9757. break;
  9758. case SC_MARSHOFABYSS:
  9759. if( bl->type == BL_PC )
  9760. val2 = 3 * val1; // AGI and DEX Reduction
  9761. else // BL_MOB
  9762. val2 = 6 * val1; // AGI and DEX Reduction
  9763. val3 = 10 * val1; // Movement Speed Reduction
  9764. break;
  9765. case SC_FREEZE_SP:
  9766. // val2 = sp drain per 10 seconds
  9767. tick_time = 10000; // [GodLesZ] tick time
  9768. break;
  9769. case SC_SPHERE_1:
  9770. case SC_SPHERE_2:
  9771. case SC_SPHERE_3:
  9772. case SC_SPHERE_4:
  9773. case SC_SPHERE_5:
  9774. if( !sd )
  9775. return 0; // Should only work on players.
  9776. val4 = tick / 1000;
  9777. if( val4 < 1 )
  9778. val4 = 1;
  9779. tick_time = 1000; // [GodLesZ] tick time
  9780. break;
  9781. case SC_SHAPESHIFT:
  9782. switch( val1 ) {
  9783. case 1: val2 = ELE_FIRE; break;
  9784. case 2: val2 = ELE_EARTH; break;
  9785. case 3: val2 = ELE_WIND; break;
  9786. case 4: val2 = ELE_WATER; break;
  9787. }
  9788. break;
  9789. case SC_ELECTRICSHOCKER:
  9790. case SC_CRYSTALIZE:
  9791. val4 = tick / 1000;
  9792. if( val4 < 1 )
  9793. val4 = 1;
  9794. tick_time = 1000; // [GodLesZ] tick time
  9795. break;
  9796. case SC_MEIKYOUSISUI:
  9797. val2 = val1 * 2; // % HP each sec
  9798. val3 = val1; // % SP each sec
  9799. val4 = tick / 1000;
  9800. if( val4 < 1 )
  9801. val4 = 1;
  9802. tick_time = 1000;
  9803. break;
  9804. case SC_CAMOUFLAGE:
  9805. val4 = tick/1000;
  9806. tick_time = 1000; // [GodLesZ] tick time
  9807. break;
  9808. case SC_WUGDASH:
  9809. {
  9810. //Store time at which you started running.
  9811. t_tick currenttick = gettick();
  9812. // Note: this int64 value is stored in two separate int32 variables (FIXME)
  9813. val3 = (int)(currenttick&0x00000000ffffffffLL);
  9814. val4 = (int)((currenttick&0xffffffff00000000LL)>>32);
  9815. tick = INFINITE_TICK;
  9816. break;
  9817. }
  9818. case SC__SHADOWFORM:
  9819. {
  9820. struct map_session_data * s_sd = map_id2sd(val2);
  9821. if( s_sd )
  9822. s_sd->shadowform_id = bl->id;
  9823. val4 = tick / 1000;
  9824. tick_time = 1000; // [GodLesZ] tick time
  9825. }
  9826. break;
  9827. case SC__STRIPACCESSORY:
  9828. if (!sd)
  9829. val2 = 20;
  9830. break;
  9831. case SC__INVISIBILITY:
  9832. val2 = 50 - 10 * val1; // ASPD
  9833. val3 = 20 * val1; // CRITICAL
  9834. val4 = tick / 1000;
  9835. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  9836. tick_time = 1000; // [GodLesZ] tick time
  9837. break;
  9838. case SC__ENERVATION:
  9839. val2 = 20 + 10 * val1; // ATK Reduction
  9840. if (sd) {
  9841. pc_delspiritball(sd,sd->spiritball,0);
  9842. pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type);
  9843. }
  9844. break;
  9845. case SC__GROOMY:
  9846. val2 = 20 + 10 * val1; // ASPD
  9847. val3 = 20 * val1; // HIT
  9848. if( sd ) { // Removes Animals
  9849. if( pc_isriding(sd) ) pc_setriding(sd, 0);
  9850. if( pc_isridingdragon(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_DRAGON);
  9851. if( pc_iswug(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_WUG);
  9852. if( pc_isridingwug(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_WUGRIDER);
  9853. if( pc_isfalcon(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_FALCON);
  9854. if( sd->status.pet_id > 0 ) pet_return_egg(sd, sd->pd);
  9855. if( hom_is_active(sd->hd) ) hom_vaporize(sd, HOM_ST_ACTIVE);
  9856. //if( sd->md ) mercenary_delete(sd->md,3); // Are Mercenaries removed? [aleos]
  9857. }
  9858. break;
  9859. case SC__LAZINESS:
  9860. val2 = 10 + 10 * val1; // Cast Increase
  9861. val3 = 10 * val1; // Flee Reduction
  9862. break;
  9863. case SC__UNLUCKY:
  9864. {
  9865. sc_type rand_eff;
  9866. switch(rnd() % 3) {
  9867. case 1: rand_eff = SC_BLIND; break;
  9868. case 2: rand_eff = SC_SILENCE; break;
  9869. default: rand_eff = SC_POISON; break;
  9870. }
  9871. val2 = 10 * val1; // Crit and Flee2 Reduction
  9872. status_change_start(src,bl,rand_eff,10000,val1,0,(rand_eff == SC_POISON ? src->id : 0),0,tick,SCSTART_NOTICKDEF|SCSTART_NORATEDEF);
  9873. break;
  9874. }
  9875. case SC__WEAKNESS:
  9876. val2 = 10 * val1;
  9877. // Bypasses coating protection and MADO
  9878. sc_start(src,bl,SC_STRIPWEAPON,100,val1,tick);
  9879. sc_start(src,bl,SC_STRIPSHIELD,100,val1,tick);
  9880. break;
  9881. case SC_GN_CARTBOOST:
  9882. if( val1 < 3 )
  9883. val2 = 50;
  9884. else if( val1 > 2 && val1 < 5 )
  9885. val2 = 75;
  9886. else
  9887. val2 = 100;
  9888. break;
  9889. case SC_PROPERTYWALK:
  9890. val3 = 0;
  9891. break;
  9892. case SC_STRIKING:
  9893. // val2 = watk bonus already calc
  9894. val3 = 6 - val1;// spcost = 6 - level (lvl1:5 ... lvl 5: 1)
  9895. val4 = tick / 1000;
  9896. tick_time = 1000; // [GodLesZ] tick time
  9897. break;
  9898. case SC_WARMER:
  9899. val4 = tick / 3000;
  9900. tick = INFINITE_TICK; // Duration sent to the client should be infinite
  9901. tick_time = 3000;
  9902. break;
  9903. case SC_HELLS_PLANT:
  9904. tick_time = status_get_sc_interval(type);
  9905. val4 = tick - tick_time; // Remaining time
  9906. break;
  9907. case SC_SWINGDANCE:
  9908. val3 = 3 * val1 + val2; // Walk speed and aspd reduction.
  9909. break;
  9910. case SC_SYMPHONYOFLOVER:
  9911. val3 = 2 * val1 + val2 + (sd?sd->status.job_level:50) / 4; // MDEF Increase
  9912. break;
  9913. case SC_MOONLITSERENADE: // MATK Increase
  9914. case SC_RUSHWINDMILL: // ATK Increase
  9915. val3 = 4 + val1 * 3 + val2 + (sd?sd->status.job_level:50) / 5;
  9916. break;
  9917. case SC_ECHOSONG:
  9918. val3 = 6 * val1 + val2 + (sd?sd->status.job_level:50) / 4; // DEF Increase
  9919. break;
  9920. case SC_HARMONIZE:
  9921. val2 = 5 + 5 * val1;
  9922. break;
  9923. case SC_VOICEOFSIREN:
  9924. val4 = tick / 2000;
  9925. tick_time = 2000; // [GodLesZ] tick time
  9926. break;
  9927. case SC_DEEPSLEEP:
  9928. val4 = tick / 2000;
  9929. tick_time = 2000; // [GodLesZ] tick time
  9930. break;
  9931. case SC_SIRCLEOFNATURE:
  9932. val2 = 50 * val1; // HP recovery rate
  9933. break;
  9934. case SC_SONGOFMANA:
  9935. status_heal(bl, 0, status->max_sp * (val1 <= 2 ? 10 : val1 <= 4 ? 15 : 20) / 100, 1);
  9936. val3 = 50 * val1;
  9937. break;
  9938. case SC_SATURDAYNIGHTFEVER:
  9939. if (!val4) val4 = skill_get_time2(scdb->skill_id,val1);
  9940. if (!val4) val4 = 3000;
  9941. val3 = tick/val4;
  9942. tick_time = val4; // [GodLesZ] tick time
  9943. break;
  9944. case SC_GLOOMYDAY:
  9945. val2 = 20 + 5 * val1; // Flee reduction.
  9946. val3 = 15 + 5 * val1; // ASPD reduction.
  9947. if( sd && rnd()%100 < val1 ) { // (Skill Lv) %
  9948. val4 = 1; // Reduce walk speed by half.
  9949. if( pc_isriding(sd) ) pc_setriding(sd, 0);
  9950. if( pc_isridingdragon(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_DRAGON);
  9951. }
  9952. break;
  9953. case SC_GLOOMYDAY_SK:
  9954. // Random number between [15 ~ (Voice Lesson Skill Level x 5) + (Skill Level x 10)] %.
  9955. val2 = 15 + rnd()%( (sd?pc_checkskill(sd, WM_LESSON)*5:0) + val1*10 );
  9956. break;
  9957. case SC_SITDOWN_FORCE:
  9958. case SC_BANANA_BOMB_SITDOWN:
  9959. if( sd && !pc_issit(sd) ) {
  9960. pc_setsit(sd);
  9961. skill_sit(sd, true);
  9962. clif_sitting(bl);
  9963. }
  9964. break;
  9965. case SC_DANCEWITHWUG:
  9966. val3 = 5 * val1; // ASPD Increase
  9967. val4 = 20 + 10 * val1; // Fixed Cast Time Reduction
  9968. break;
  9969. case SC_LERADSDEW:
  9970. val3 = 2 + 3 * val1 + min(3 * val2, 25); // MaxHP Increase
  9971. break;
  9972. case SC_MELODYOFSINK:
  9973. val2 = 10 * val1; // INT Reduction.
  9974. val3 = 2 + 2 * val1; // MaxSP reduction
  9975. break;
  9976. case SC_BEYONDOFWARCRY:
  9977. val2 = 10 + 10 * val1; // STR Reduction
  9978. val3 = 4 * val1; // MaxHP Reduction
  9979. break;
  9980. case SC_UNLIMITEDHUMMINGVOICE:
  9981. val3 = 4 * val1 + min(3 * val2, 15); // !TODO: What's the Lesson bonus?
  9982. break;
  9983. case SC_REFLECTDAMAGE:
  9984. val2 = 10 * val1; // Reflect reduction amount
  9985. val3 = val1*5 + 25; // Number of reflects
  9986. val4 = tick/1000; // Number of SP cycles (duration)
  9987. tick_time = 1000; // [GodLesZ] tick time
  9988. break;
  9989. case SC_FORCEOFVANGUARD:
  9990. val2 = 8 + 12 * val1; // Chance
  9991. val3 = 5 + 2 * val1; // Max rage counters
  9992. tick = INFINITE_TICK; // Endless duration in the client
  9993. tick_time = 10000; // [GodLesZ] tick time
  9994. break;
  9995. case SC_EXEEDBREAK:
  9996. val2 = 150 * val1;
  9997. if (sd) { // Players
  9998. short index = sd->equip_index[EQI_HAND_R];
  9999. if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON)
  10000. val2 += 15 * sd->status.job_level + sd->inventory_data[index]->weight / 10 * sd->inventory_data[index]->weapon_level * status_get_lv(bl) / 100;
  10001. } else // Monster
  10002. val2 += 750;
  10003. break;
  10004. case SC_PRESTIGE:
  10005. val2 = (status->int_ + status->luk) * val1 / 20 * status_get_lv(bl) / 200 + val1; // Chance to evade magic damage.
  10006. val3 = ((val1 * 15) + (10 * (sd?pc_checkskill(sd,CR_DEFENDER):skill_get_max(CR_DEFENDER)))) * status_get_lv(bl) / 100; // Defence added
  10007. break;
  10008. case SC_SHIELDSPELL_HP:
  10009. val2 = 3; // 3% HP every 3 seconds
  10010. tick_time = status_get_sc_interval(type);
  10011. val4 = tick - tick_time; // Remaining time
  10012. break;
  10013. case SC_SHIELDSPELL_SP:
  10014. val2 = 3; // 3% SP every 5 seconds
  10015. tick_time = status_get_sc_interval(type);
  10016. val4 = tick - tick_time; // Remaining time
  10017. break;
  10018. case SC_SHIELDSPELL_ATK:
  10019. val2 = 150; // WATK/MATK bonus
  10020. break;
  10021. case SC_BANDING:
  10022. val2 = (sd ? skill_banding_count(sd) : 1);
  10023. tick_time = 5000; // [GodLesZ] tick time
  10024. break;
  10025. case SC_MAGNETICFIELD:
  10026. tick_time = 1000; // [GodLesZ] tick time
  10027. val4 = tick / tick_time;
  10028. break;
  10029. case SC_INSPIRATION:
  10030. val2 = 40 * val1; // ATK/MATK
  10031. val3 = 6 * val1; //All stat bonus
  10032. val4 = tick / 5000;
  10033. tick_time = 5000; // [GodLesZ] tick time
  10034. status_change_clear_buffs(bl, SCCB_DEBUFFS); // Remove debuffs
  10035. break;
  10036. case SC_CRESCENTELBOW:
  10037. val2 = (sd?sd->status.job_level:50) / 2 + (50 + 5 * val1);
  10038. break;
  10039. case SC_LIGHTNINGWALK: // [(Job Level / 2) + (40 + 5 * Skill Level)] %
  10040. val1 = (sd?sd->status.job_level:2)/2 + 40 + 5 * val1;
  10041. break;
  10042. case SC_GT_ENERGYGAIN:
  10043. val2 = 10 + 5 * val1; // Sphere gain chance.
  10044. break;
  10045. case SC_GT_CHANGE:
  10046. // Take note there is no def increase as skill desc says. [malufett]
  10047. val2 = val1 * 8; // ATK increase
  10048. val3 = status->agi * val1 / 60; // ASPD increase: [(Target AGI x Skill Level) / 60] %
  10049. break;
  10050. case SC_GT_REVITALIZE:
  10051. // Take note there is no vit, aspd, speed increase as skill desc says. [malufett]
  10052. val2 = 2 * val1; // MaxHP: [(Skill Level * 2)]%
  10053. val3 = val1 * 30 + 50; // Natural HP recovery increase: [(Skill Level x 30) + 50] %
  10054. // The stat def is not shown in the status window and it is processed differently
  10055. val4 = val1 * 20; // STAT DEF increase
  10056. break;
  10057. case SC_PYROTECHNIC_OPTION:
  10058. val2 = 60; // Eatk Renewal (Atk2)
  10059. break;
  10060. case SC_HEATER_OPTION:
  10061. val2 = 120; // Eatk Renewal (Atk2)
  10062. val3 = ELE_FIRE; // Change into fire element.
  10063. break;
  10064. case SC_TROPIC_OPTION:
  10065. val2 = 180; // Eatk Renewal (Atk2)
  10066. val3 = MG_FIREBOLT;
  10067. break;
  10068. case SC_AQUAPLAY_OPTION:
  10069. val2 = 40;
  10070. break;
  10071. case SC_COOLER_OPTION:
  10072. val2 = 80;
  10073. val3 = ELE_WATER; // Change into water element.
  10074. break;
  10075. case SC_CHILLY_AIR_OPTION:
  10076. val2 = 120; // Matk. Renewal (Matk1)
  10077. val3 = MG_COLDBOLT;
  10078. break;
  10079. case SC_WIND_STEP_OPTION:
  10080. val2 = 50; // % Increase speed and flee.
  10081. break;
  10082. case SC_BLAST_OPTION:
  10083. val2 = 20;
  10084. val3 = ELE_WIND; // Change into wind element.
  10085. break;
  10086. case SC_WILD_STORM_OPTION:
  10087. val2 = MG_LIGHTNINGBOLT;
  10088. break;
  10089. case SC_PETROLOGY_OPTION:
  10090. val2 = 5; //HP Rate bonus
  10091. val3 = 50;
  10092. break;
  10093. case SC_SOLID_SKIN_OPTION:
  10094. val2 = 33; //% Increase DEF
  10095. break;
  10096. case SC_CURSED_SOIL_OPTION:
  10097. val2 = 10; //HP rate bonus
  10098. val3 = ELE_EARTH; // Change into earth element.
  10099. break;
  10100. case SC_UPHEAVAL_OPTION:
  10101. val2 = 15; //HP rate bonus
  10102. val3 = WZ_EARTHSPIKE;
  10103. break;
  10104. case SC_CIRCLE_OF_FIRE_OPTION:
  10105. val2 = 300;
  10106. break;
  10107. case SC_WATER_SCREEN_OPTION:
  10108. tick_time = 10000;
  10109. break;
  10110. case SC_FIRE_CLOAK_OPTION:
  10111. case SC_WATER_DROP_OPTION:
  10112. case SC_WIND_CURTAIN_OPTION:
  10113. case SC_STONE_SHIELD_OPTION:
  10114. val2 = 100; // Elemental modifier.
  10115. break;
  10116. case SC_TROPIC:
  10117. case SC_CHILLY_AIR:
  10118. case SC_WILD_STORM:
  10119. case SC_UPHEAVAL:
  10120. val2 += 10;
  10121. case SC_HEATER:
  10122. case SC_COOLER:
  10123. case SC_BLAST:
  10124. case SC_CURSED_SOIL:
  10125. val2 += 10;
  10126. case SC_PYROTECHNIC:
  10127. case SC_AQUAPLAY:
  10128. case SC_GUST:
  10129. case SC_PETROLOGY:
  10130. val2 += 5;
  10131. val3 += 9000;
  10132. case SC_CIRCLE_OF_FIRE:
  10133. case SC_FIRE_CLOAK:
  10134. case SC_WATER_DROP:
  10135. case SC_WATER_SCREEN:
  10136. case SC_WIND_CURTAIN:
  10137. case SC_WIND_STEP:
  10138. case SC_STONE_SHIELD:
  10139. case SC_SOLID_SKIN:
  10140. val2 += 5;
  10141. val3 += 1000;
  10142. tick_time = val3; // [GodLesZ] tick time
  10143. break;
  10144. case SC_WATER_BARRIER:
  10145. val2 = 30; // Reductions. Atk2 and Flee1
  10146. break;
  10147. case SC_ZEPHYR:
  10148. val2 = 25; // Flee.
  10149. break;
  10150. case SC_TIDAL_WEAPON:
  10151. val2 = 20; // Increase Elemental's attack.
  10152. break;
  10153. case SC_ROCK_CRUSHER:
  10154. case SC_ROCK_CRUSHER_ATK:
  10155. case SC_POWER_OF_GAIA:
  10156. val2 = 33; //Def rate bonus/Speed rate reduction
  10157. val3 = 20; //HP rate bonus
  10158. break;
  10159. case SC_TEARGAS:
  10160. val2 = status_get_max_hp(bl) * 5 / 100; // Drain 5% HP
  10161. val4 = tick / 2000;
  10162. tick_time = 2000;
  10163. break;
  10164. case SC_TEARGAS_SOB:
  10165. val4 = tick / 3000;
  10166. tick_time = 3000;
  10167. break;
  10168. case SC_STOMACHACHE:
  10169. val2 = 8; // SP consume.
  10170. val4 = tick / 10000;
  10171. tick_time = 10000; // [GodLesZ] tick time
  10172. break;
  10173. case SC_PROMOTE_HEALTH_RESERCH:
  10174. //val1: 1 = Regular Potion, 2 = Thrown Potion
  10175. //val2: 1 = Small Potion, 2 = Medium Potion, 3 = Large Potion
  10176. //val3: MaxHP Increase By Fixed Amount
  10177. if (val1 == 1) // If potion was normally used, take the user's BaseLv
  10178. val3 = 1000 * val2 - 500 + status_get_lv(bl) * 10 / 3;
  10179. else if (val1 == 2) // If potion was thrown at someone, take the thrower's BaseLv
  10180. val3 = 1000 * val2 - 500 + status_get_lv(src) * 10 / 3;
  10181. if (val3 <= 0) // Prevents a negeative value from happening
  10182. val3 = 0;
  10183. break;
  10184. case SC_ENERGY_DRINK_RESERCH:
  10185. //val1: 1 = Regular Potion, 2 = Thrown Potion
  10186. //val2: 1 = Small Potion, 2 = Medium Potion, 3 = Large Potion
  10187. //val3: MaxSP Increase By Percentage Amount
  10188. if (val1 == 1) // If potion was normally used, take the user's BaseLv
  10189. val3 = status_get_lv(bl) / 10 + 5 * val2 - 10;
  10190. else if (val1 == 2) // If potion was thrown at someone, take the thrower's BaseLv
  10191. val3 = status_get_lv(src) / 10 + 5 * val2 - 10;
  10192. if (val3 <= 0) // Prevents a negeative value from happening
  10193. val3 = 0;
  10194. break;
  10195. case SC_KYOUGAKU:
  10196. val2 = 2*val1 + rnd()%val1;
  10197. clif_status_change(bl,EFST_ACTIVE_MONSTER_TRANSFORM,1,0,1002,0,0);
  10198. break;
  10199. case SC_KAGEMUSYA:
  10200. val2 = 20; // Damage increase bonus
  10201. val3 = val1 * 2;
  10202. tick_time = 1000;
  10203. val4 = tick / tick_time;
  10204. break;
  10205. case SC_ZANGETSU:
  10206. if( status_get_hp(bl) % 2 == 0 )
  10207. val2 = (status_get_lv(bl) / 3) + (20 * val1); //+Watk
  10208. else
  10209. val2 -= (status_get_lv(bl) / 3) + (30 * val1); //-Watk
  10210. if( status_get_sp(bl) % 2 == 0 )
  10211. val3 = (status_get_lv(bl) / 3) + (20 * val1); //+Matk
  10212. else
  10213. val3 -= (status_get_lv(bl) / 3) + (30 * val1); //-Matk
  10214. break;
  10215. case SC_GENSOU:
  10216. {
  10217. int hp = status_get_hp(bl), lv = 5;
  10218. short per = 100 / (status_get_max_hp(bl) / hp);
  10219. if( per <= 15 )
  10220. lv = 1;
  10221. else if( per <= 30 )
  10222. lv = 2;
  10223. else if( per <= 50 )
  10224. lv = 3;
  10225. else if( per <= 75 )
  10226. lv = 4;
  10227. if( hp % 2 == 0)
  10228. status_heal(bl, hp * (6-lv) * 4 / 100, status_get_sp(bl) * (6-lv) * 3 / 100, 1);
  10229. else
  10230. status_zap(bl, hp * (lv*4) / 100, status_get_sp(bl) * (lv*3) / 100);
  10231. }
  10232. break;
  10233. case SC_ANGRIFFS_MODUS:
  10234. val2 = 50 + 20 * val1; // atk bonus
  10235. val3 = 25 + 10 * val1; // Flee reduction.
  10236. val4 = tick/1000; // hp/sp reduction timer
  10237. tick_time = 1000;
  10238. break;
  10239. case SC_GOLDENE_FERSE:
  10240. val2 = 10 + 10*val1; // flee bonus
  10241. val3 = 6 + 4 * val1; // Aspd Bonus
  10242. val4 = 2 + 2 * val1; // Chance of holy attack
  10243. break;
  10244. case SC_STONE_WALL:
  10245. val2 = 100 * val1; // DEF bonus
  10246. val3 = 30 * val1; // MDEF bonus
  10247. break;
  10248. case SC_OVERED_BOOST:
  10249. val2 = 400 + 40 * val1; // flee bonus
  10250. val3 = 180 + 2 * val1; // aspd bonus
  10251. val4 = 50; // def reduc %
  10252. break;
  10253. case SC_GRANITIC_ARMOR:
  10254. val2 = 2*val1; // dmg reduction
  10255. val3 = 6*val1; // dmg taken on status end (6%:12%:18%:24%:30%)
  10256. val4 = 5*val1; // unknow formula
  10257. break;
  10258. case SC_MAGMA_FLOW:
  10259. val2 = 3*val1; // Activation chance
  10260. break;
  10261. case SC_PYROCLASTIC:
  10262. val2 += 100 + 10*val1; // atk bonus // !TODO: Confirm formula
  10263. break;
  10264. case SC_PARALYSIS: // [Lighta] need real info
  10265. val2 = 2*val1; // def reduction
  10266. val3 = 500*val1; // varcast augmentation
  10267. break;
  10268. case SC_LIGHT_OF_REGENE: // Yommy leak need confirm
  10269. val2 = 20 * val1; // hp reco on death %
  10270. break;
  10271. case SC_PAIN_KILLER: // Yommy leak need confirm
  10272. val2 = min((( 200 * val1 ) * status_get_lv(src)) / 150, 1000); // dmg reduction linear. upto a maximum of 1000 [iRO Wiki]
  10273. if(sc->data[SC_PARALYSIS])
  10274. sc_start(src,bl, SC_ENDURE, 100, val1, tick); // Start endure for same duration
  10275. break;
  10276. case SC_STYLE_CHANGE:
  10277. tick = INFINITE_TICK; // Infinite duration
  10278. break;
  10279. case SC_CBC:
  10280. val3 = 10; // Drain sp % dmg
  10281. val4 = tick/1000; // dmg each sec
  10282. tick = 1000;
  10283. break;
  10284. case SC_EQC:
  10285. val2 = 5 * val1; // def % reduc
  10286. val3 = 2 * val1; // HP drain %
  10287. break;
  10288. case SC_ASH:
  10289. val2 = 0; // hit % reduc
  10290. val3 = 0; // def % reduc
  10291. val4 = 0; // atk flee & reduc
  10292. if (!status_bl_has_mode(bl,MD_STATUSIMMUNE)) {
  10293. val2 = 50;
  10294. if (status_get_race(bl) == RC_PLANT) // plant type
  10295. val3 = 50;
  10296. if (status_get_element(bl) == ELE_WATER) // defense water type
  10297. val4 = 50;
  10298. }
  10299. break;
  10300. case SC_FULL_THROTTLE:
  10301. val2 = ( val1 == 1 ? 6 : 6 - val1 );
  10302. val3 = 20; //+% AllStats
  10303. tick_time = 1000;
  10304. val4 = tick / tick_time;
  10305. break;
  10306. case SC_REBOUND:
  10307. tick_time = 2000;
  10308. val4 = tick / tick_time;
  10309. clif_emotion(bl, ET_SWEAT);
  10310. break;
  10311. case SC_KINGS_GRACE:
  10312. val2 = 3 + val1; //HP Recover rate
  10313. tick_time = 1000;
  10314. val4 = tick / tick_time;
  10315. break;
  10316. case SC_TELEKINESIS_INTENSE:
  10317. val2 = 10 * val1; // sp consum / casttime reduc %
  10318. val3 = 40 * val1; // magic dmg bonus
  10319. break;
  10320. case SC_OFFERTORIUM:
  10321. val2 = 30 * val1; // heal power bonus
  10322. val3 = 100 + 20 * val1; // sp cost inc
  10323. break;
  10324. case SC_FRIGG_SONG:
  10325. val2 = 5 * val1; // maxhp bonus
  10326. val3 = 80 + 20 * val1; // healing
  10327. tick_time = 1000;
  10328. val4 = tick / tick_time;
  10329. break;
  10330. case SC_FLASHCOMBO:
  10331. val2 = 20 * val1 + 20; // atk bonus
  10332. break;
  10333. case SC_DARKCROW:
  10334. val2 = 30 * val1; // ATK bonus
  10335. break;
  10336. case SC_UNLIMIT:
  10337. val2 = 50 * val1;
  10338. break;
  10339. case SC_MONSTER_TRANSFORM:
  10340. case SC_ACTIVE_MONSTER_TRANSFORM:
  10341. if( !mobdb_checkid(val1) )
  10342. val1 = MOBID_PORING; // Default poring
  10343. break;
  10344. #ifndef RENEWAL
  10345. case SC_APPLEIDUN:
  10346. {
  10347. struct map_session_data * s_sd = BL_CAST(BL_PC, src);
  10348. val2 = (5 + 2 * val1) + (status_get_vit(src) / 10); //HP Rate: (5 + 2 * skill_lv) + (vit/10) + (BA_MUSICALLESSON level)
  10349. if (s_sd)
  10350. val2 += pc_checkskill(s_sd, BA_MUSICALLESSON) / 2;
  10351. break;
  10352. }
  10353. #endif
  10354. case SC_EPICLESIS:
  10355. val2 = 5 * val1; //HP rate bonus
  10356. break;
  10357. case SC_ILLUSIONDOPING:
  10358. val2 = 50; // -Hit
  10359. break;
  10360. case SC_OVERHEAT:
  10361. case SC_OVERHEAT_LIMITPOINT:
  10362. case SC_STEALTHFIELD:
  10363. tick_time = tick;
  10364. tick = INFINITE_TICK;
  10365. break;
  10366. case SC_STEALTHFIELD_MASTER:
  10367. tick_time = val3 = 2000 + 1000 * val1;
  10368. val4 = tick / tick_time;
  10369. break;
  10370. case SC_VACUUM_EXTREME:
  10371. // Suck target at n second, only if the n second is lower than the duration
  10372. // Does not suck targets on no-knockback maps
  10373. if (val4 < tick && unit_blown_immune(bl, 0x9) == UB_KNOCKABLE) {
  10374. tick_time = val4;
  10375. val4 = tick - tick_time;
  10376. } else
  10377. val4 = 0;
  10378. break;
  10379. case SC_FIRE_INSIGNIA:
  10380. case SC_WATER_INSIGNIA:
  10381. case SC_WIND_INSIGNIA:
  10382. case SC_EARTH_INSIGNIA:
  10383. tick_time = 5000;
  10384. val4 = tick / tick_time;
  10385. break;
  10386. case SC_NEUTRALBARRIER:
  10387. val2 = 10 + val1 * 5; // Def/Mdef
  10388. tick = INFINITE_TICK;
  10389. break;
  10390. case SC_MAGIC_POISON:
  10391. val2 = 50; // Attribute Reduction
  10392. break;
  10393. /* Rebellion */
  10394. case SC_B_TRAP:
  10395. val2 = src->id;
  10396. val3 = val1 * 25; // -movespeed TODO: Figure out movespeed rate
  10397. break;
  10398. case SC_C_MARKER:
  10399. case SC_BURNT:
  10400. // val1 = skill_lv
  10401. // val2 = src_id
  10402. val3 = 10; // -10 flee
  10403. //Start timer to send mark on mini map
  10404. val4 = tick/1000;
  10405. tick_time = 1000; // Sends every 1 seconds
  10406. break;
  10407. case SC_H_MINE:
  10408. val2 = src->id;
  10409. break;
  10410. case SC_HEAT_BARREL:
  10411. {
  10412. uint8 n = 10;
  10413. if (sd)
  10414. n = (uint8)sd->spiritball_old;
  10415. //kRO Update 2016-05-25
  10416. val2 = n * 5; // -fixed casttime
  10417. val3 = (6 + val1 * 2) * n; // ATK
  10418. val4 = 25 + val1 * 5; // -hit
  10419. }
  10420. break;
  10421. case SC_P_ALTER:
  10422. {
  10423. uint8 n = 10;
  10424. if (sd)
  10425. n = (uint8)sd->spiritball_old;
  10426. val2 = 10 * n; // +atk
  10427. val3 = (status->max_hp * (val1 * 5) / 100); // Barrier HP
  10428. }
  10429. break;
  10430. case SC_E_CHAIN:
  10431. val2 = 10;
  10432. if (sd)
  10433. val2 = sd->spiritball_old;
  10434. break;
  10435. case SC_ANTI_M_BLAST:
  10436. val2 = val1 * 10;
  10437. break;
  10438. case SC_CATNIPPOWDER:
  10439. val2 = 50; // WATK%, MATK%
  10440. val3 = 25 * val1; // Move speed reduction
  10441. if (bl->type == BL_PC && pc_checkskill(sd, SU_SPIRITOFLAND))
  10442. val4 = status_get_lv(src) / 12;
  10443. break;
  10444. case SC_BITESCAR: {
  10445. const struct status_data *b_status = status_get_base_status(src); // Base Status
  10446. val2 = (status_get_max_hp(bl) * (val1 + (b_status->dex / 25))) / status_get_max_hp(bl); // MHP% damage
  10447. tick_time = 1000;
  10448. val4 = tick / tick_time;
  10449. }
  10450. break;
  10451. case SC_ARCLOUSEDASH:
  10452. val2 = 15 + 5 * val1; // AGI
  10453. val3 = 25; // Move speed increase
  10454. if (sd && (sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER)
  10455. val4 = 10; // Ranged ATK increase
  10456. break;
  10457. case SC_SHRIMP:
  10458. val2 = 10; // BATK%, MATK%
  10459. break;
  10460. case SC_FRESHSHRIMP: {
  10461. int min = 0, max = 0;
  10462. #ifdef RENEWAL
  10463. min = status_base_matk_min(src, status, status_get_lv(src));
  10464. max = status_base_matk_max(src, status, status_get_lv(src));
  10465. if (status->rhw.matk > 0) {
  10466. int wMatk, variance;
  10467. wMatk = status->rhw.matk;
  10468. variance = wMatk * status->rhw.wlv / 10;
  10469. min += wMatk - variance;
  10470. max += wMatk + variance;
  10471. }
  10472. #endif
  10473. if (sd && sd->right_weapon.overrefine > 0) {
  10474. min++;
  10475. max += sd->right_weapon.overrefine - 1;
  10476. }
  10477. val2 += min + 178; // Heal
  10478. if (max > min)
  10479. val2 += rnd() % (max - min); // Heal
  10480. if (sd) {
  10481. if (pc_checkskill(sd, SU_POWEROFSEA) > 0) {
  10482. val2 += val2 * 10 / 100;
  10483. if (pc_checkskill_summoner(sd, SUMMONER_POWER_SEA) >= 20)
  10484. val2 += val2 * 20 / 100;
  10485. }
  10486. if (pc_checkskill(sd, SU_SPIRITOFSEA) > 0)
  10487. val2 *= 2; // Doubles HP
  10488. }
  10489. tick_time = 10000 - ((val1 - 1) * 1000);
  10490. val4 = tick / tick_time;
  10491. }
  10492. break;
  10493. case SC_TUNAPARTY:
  10494. val2 = (status->max_hp * (val1 * 10) / 100); // Max HP% to absorb
  10495. if (sd && pc_checkskill(sd, SU_SPIRITOFSEA))
  10496. val2 <<= 1; // Double the shield life
  10497. break;
  10498. case SC_HISS:
  10499. val2 = 50; // Perfect Dodge
  10500. sc_start(src, bl, SC_DORAM_WALKSPEED, 100, 50, skill_get_time2(SU_HISS, val1));
  10501. break;
  10502. case SC_GROOMING:
  10503. val2 = 100; // Flee
  10504. break;
  10505. case SC_CHATTERING:
  10506. val2 = 100; // eATK, eMATK
  10507. sc_start(src, bl, SC_DORAM_WALKSPEED, 100, 50, skill_get_time2(SU_CHATTERING, val1));
  10508. break;
  10509. case SC_SWORDCLAN:
  10510. case SC_ARCWANDCLAN:
  10511. case SC_GOLDENMACECLAN:
  10512. case SC_CROSSBOWCLAN:
  10513. case SC_JUMPINGCLAN:
  10514. tick = INFINITE_TICK;
  10515. status_change_start(src,bl,SC_CLAN_INFO,10000,0,val2,0,0,INFINITE_TICK,flag);
  10516. break;
  10517. case SC_DORAM_BUF_01:
  10518. case SC_DORAM_BUF_02:
  10519. tick_time = 10000; // every 10 seconds
  10520. if( (val4 = tick/tick_time) < 1 )
  10521. val4 = 1;
  10522. break;
  10523. case SC_GLASTHEIM_ATK:
  10524. val1 = 100; // Undead/Demon MDEF ignore rate
  10525. break;
  10526. case SC_GLASTHEIM_HEAL:
  10527. val1 = 100; // Heal Power rate bonus
  10528. val2 = 50; // Received heal rate bonus
  10529. break;
  10530. case SC_GLASTHEIM_HIDDEN:
  10531. val1 = 90; // Damage rate reduction bonus
  10532. break;
  10533. case SC_GLASTHEIM_STATE:
  10534. val1 = 20; // All-stat bonus
  10535. break;
  10536. case SC_GLASTHEIM_ITEMDEF:
  10537. val1 = 200; // DEF bonus
  10538. val2 = 50; // MDEF bonus
  10539. break;
  10540. case SC_GLASTHEIM_HPSP:
  10541. val1 = 10000; // HP bonus
  10542. val2 = 1000; // SP bonus
  10543. break;
  10544. case SC_ANCILLA:
  10545. val1 = 15; // Heal Power rate bonus
  10546. val2 = 30; // SP Recovery rate bonus
  10547. break;
  10548. case SC_HELPANGEL:
  10549. tick_time = 1000;
  10550. val4 = tick / tick_time;
  10551. break;
  10552. case SC_EMERGENCY_MOVE:
  10553. val2 = 25; // Movement speed increase
  10554. break;
  10555. case SC_SUNSTANCE:
  10556. val2 = 2 + val1; // ATK Increase
  10557. tick = INFINITE_TICK;
  10558. break;
  10559. case SC_LUNARSTANCE:
  10560. val2 = 2 + val1; // MaxHP Increase
  10561. tick = INFINITE_TICK;
  10562. break;
  10563. case SC_STARSTANCE:
  10564. val2 = 4 + 2 * val1; // ASPD Increase
  10565. tick = INFINITE_TICK;
  10566. break;
  10567. case SC_DIMENSION1:
  10568. case SC_DIMENSION2:
  10569. if (sd)
  10570. pc_addspiritball(sd, skill_get_time2(SJ_BOOKOFDIMENSION, 1), 2);
  10571. break;
  10572. case SC_UNIVERSESTANCE:
  10573. val2 = 2 + val1; // All Stats Increase
  10574. tick = INFINITE_TICK;
  10575. break;
  10576. case SC_NEWMOON:
  10577. val2 = 7; // Number of Regular Attacks Until Reveal
  10578. tick_time = 1000;
  10579. val4 = tick / tick_time;
  10580. break;
  10581. case SC_FALLINGSTAR:
  10582. val2 = 8 + 2 * (1 + val1) / 2; // Autocast Chance
  10583. if (val1 >= 7)
  10584. val2 += 1; // Make it 15% at level 7.
  10585. break;
  10586. case SC_CREATINGSTAR:
  10587. tick_time = 500;
  10588. val4 = tick / tick_time;
  10589. break;
  10590. case SC_LIGHTOFSUN:
  10591. case SC_LIGHTOFMOON:
  10592. case SC_LIGHTOFSTAR:
  10593. val2 = 5 * val1; // Skill Damage Increase.
  10594. break;
  10595. case SC_SOULGOLEM:
  10596. val2 = 60 * val1; // DEF Increase
  10597. val3 = 15 + 5 * val1; // MDEF Increase
  10598. break;
  10599. case SC_SOULSHADOW:
  10600. val2 = (1 + val1) / 2; // ASPD Increase
  10601. val3 = 10 + 2 * val1; // CRIT Increase
  10602. break;
  10603. case SC_SOULFALCON:
  10604. val2 = 10 * val1; // WATK Increase
  10605. val3 = 10; // HIT Increase
  10606. if (val1 >= 3)
  10607. val3 += 3;
  10608. else if (val1 >= 5)
  10609. val3 += 5;
  10610. break;
  10611. case SC_SOULFAIRY:
  10612. val2 = 10 * val1; // MATK Increase
  10613. val3 = 5; // Variable Cast Time Reduction
  10614. if (val1 >= 3)
  10615. val3 += 2;
  10616. else if (val1 >= 5)
  10617. val3 += 5;
  10618. break;
  10619. case SC_SOULUNITY:
  10620. tick_time = 3000;
  10621. val4 = tick / tick_time;
  10622. break;
  10623. case SC_SOULDIVISION:
  10624. val2 = 10 * val1; // Skill Aftercast Increase
  10625. break;
  10626. case SC_SOULREAPER:
  10627. val2 = 10 + 5 * val1; // Chance of Getting A Soul Sphere.
  10628. break;
  10629. case SC_SOULCOLLECT:
  10630. val2 = 5 + 3 * val2; // Max Soul Sphere's.
  10631. val3 = tick > 0 ? tick : 60000;
  10632. tick_time = tick;
  10633. tick = INFINITE_TICK;
  10634. break;
  10635. case SC_SP_SHA:
  10636. val2 = 50; // Move speed reduction
  10637. break;
  10638. case SC_SERVANTWEAPON:
  10639. if( sd ){
  10640. // Generate 5 servants on start
  10641. pc_addservantball( *sd, MAX_SERVANTBALL );
  10642. }
  10643. tick_time = skill_get_time2(DK_SERVANTWEAPON,val1); // Servant Regen Interval
  10644. if (tick_time < 500)
  10645. tick_time = 500; // Avoid being brought down to 0.
  10646. val4 = tick - tick_time; // Remaining Time
  10647. break;
  10648. case SC_VIGOR: {
  10649. uint8 hp_loss[10] = { 15, 14, 12, 11, 9, 8, 6, 5, 3, 2 };
  10650. val2 = hp_loss[val1- 1];
  10651. }
  10652. break;
  10653. case SC_POWERFUL_FAITH:
  10654. val2 = 5 + 5 * val1;// ATK Increase
  10655. val3 = 5 + 2 * val1;// PAtk Increase
  10656. break;
  10657. case SC_FIRM_FAITH:
  10658. val2 = 2 * val1;// MaxHP Increase
  10659. val3 = 8 * val1;// Res Increase
  10660. break;
  10661. case SC_SINCERE_FAITH:
  10662. val2 = (1 + val1) / 2;// ASPD Increase
  10663. val3 = 4 * val1;// Perfect Hit Increase
  10664. break;
  10665. case SC_GUARD_STANCE:
  10666. val2 = 50 + 50 * val1;// DEF Increase
  10667. val3 = 50 * val1;// ATK Decrease
  10668. tick = INFINITE_TICK;
  10669. break;
  10670. case SC_GUARDIAN_S:
  10671. val2 = status->max_hp * (50 * val1) / 100;// Barrier HP
  10672. break;
  10673. case SC_REBOUND_S:
  10674. val2 = 10 * val1;// Reduced Damage From Devotion
  10675. if (val2 > 99)
  10676. val2 = 99;// Lets not let it reduce above 99.
  10677. break;
  10678. case SC_ATTACK_STANCE:
  10679. val2 = 40 * val1;// DEF Decrease
  10680. val3 = 5 + 5 * val1;// ATK Increase
  10681. tick = INFINITE_TICK;
  10682. break;
  10683. case SC_HOLY_S:
  10684. val2 = 5 + 2 * val1;// Damage Reduction / Holy Damage Increase
  10685. break;
  10686. case SC_MEDIALE:
  10687. val2 = 2 * val1;// Heal Rate
  10688. val4 = tick / 2000;
  10689. tick_time = 2000;
  10690. break;
  10691. case SC_A_VITA:
  10692. case SC_A_TELUM:
  10693. val2 = 5 * val1;// Res/MRes Pierce Percentage
  10694. break;
  10695. case SC_PRE_ACIES:
  10696. val2 = 2 * val1;// CRate Increase
  10697. break;
  10698. case SC_COMPETENTIA:
  10699. val2 = 10 * val1;// PAtk/SMatk Increase - Unconfirmed if this is official formula but its 50 at Lv 5. [Rytech]
  10700. break;
  10701. case SC_RELIGIO:
  10702. case SC_BENEDICTUM:
  10703. val2 = 2 * val1;// Trait Stats Increase
  10704. break;
  10705. case SC_DANCING_KNIFE:
  10706. val4 = tick / 300;
  10707. tick_time = 300;
  10708. break;
  10709. case SC_POTENT_VENOM:
  10710. val2 = 3 * val1;// Res Pierce Percentage
  10711. break;
  10712. case SC_SHADOW_WEAPON:
  10713. val2 = val1;// Success Chance of Shadow Scar
  10714. break;
  10715. case SC_A_MACHINE:
  10716. val4 = tick / 1000;
  10717. tick_time = 1000;
  10718. break;
  10719. case SC_D_MACHINE:
  10720. val2 = 200 + 50 * val1;// DEF Increase
  10721. val3 = 20 * val1;// Res Increase
  10722. break;
  10723. case SC_SHADOW_STRIP:
  10724. if (!sd)// Res/MRes on mobs only.
  10725. val2 = 25;// Need official reduction amount.
  10726. break;
  10727. case SC_ABYSSFORCEWEAPON:
  10728. if( sd ){
  10729. // Generate 5 abyss spheres on start.
  10730. pc_addabyssball( *sd, MAX_ABYSSBALL );
  10731. }
  10732. tick_time = skill_get_time2(ABC_FROM_THE_ABYSS, val1);// Abyss Regen Interval
  10733. if (tick_time < 500)
  10734. tick_time = 500;// Avoid being brought down to 0.
  10735. val4 = tick - tick_time;// Remaining Time
  10736. break;
  10737. case SC_ABYSS_SLAYER:
  10738. val2 = 10 + 2 * val1;// PAtk/SMatk Increase
  10739. val3 = 100 + 20 * val1;// Hit Increase
  10740. break;
  10741. case SC_WINDSIGN:
  10742. val2 = 8 + 6 * val1;// Chance to gain AP on attack.
  10743. if (val1 == 5)// Its 40% on level 5.
  10744. val2 += 2;
  10745. break;
  10746. case SC_CALAMITYGALE:// Unlimit runs along with this.
  10747. sc_start(bl, bl, SC_UNLIMIT, 100, 5, skill_get_time(RA_UNLIMIT, 5));
  10748. break;
  10749. case SC_GEF_NOCTURN:// MRes Reduction. Official formula unknown.
  10750. case SC_AIN_RHAPSODY:// Res Reduction. Official formula unknown.
  10751. val2 = 10 * val1;// Res/MRes Decrease
  10752. if (val3&2)// Bonus if partner is found in party.
  10753. val2 *= 2;
  10754. break;
  10755. case SC_MUSICAL_INTERLUDE:
  10756. val2 = 5 + 5 * val1;// Res Increase
  10757. if (val3&2)// Bonus if partner is found in party.
  10758. val2 *= 2;
  10759. break;
  10760. case SC_JAWAII_SERENADE:
  10761. val2 = 3 * val1;// SMatk Increase
  10762. if (val3 & 2)// Bonus if partner is found in party.
  10763. val2 *= 2;
  10764. break;
  10765. case SC_PRON_MARCH:
  10766. val2 = 3 * val1;// PAtk Increase
  10767. if (val3 & 2)// Bonus if partner is found in party.
  10768. val2 *= 2;
  10769. break;
  10770. case SC_SPELL_ENCHANTING:
  10771. val2 = 4 * val1;// SMatk Increase
  10772. break;
  10773. case SC_FLAMETECHNIC:
  10774. case SC_FLAMEARMOR:
  10775. case SC_COLD_FORCE:
  10776. case SC_CRYSTAL_ARMOR:
  10777. case SC_GRACE_BREEZE:
  10778. case SC_EYES_OF_STORM:
  10779. case SC_EARTH_CARE:
  10780. case SC_STRONG_PROTECTION:
  10781. case SC_DEEP_POISONING:
  10782. case SC_POISON_SHIELD:
  10783. val2 += 10;
  10784. val3 += 10000;
  10785. tick_time = val3;
  10786. break;
  10787. case SC_FLAMETECHNIC_OPTION:
  10788. val3 = ELE_FIRE;
  10789. break;
  10790. case SC_COLD_FORCE_OPTION:
  10791. val3 = ELE_WATER;
  10792. break;
  10793. case SC_GRACE_BREEZE_OPTION:
  10794. val3 = ELE_WIND;
  10795. break;
  10796. case SC_EARTH_CARE_OPTION:
  10797. val3 = ELE_EARTH;
  10798. break;
  10799. case SC_DEEP_POISONING_OPTION:
  10800. val3 = ELE_POISON;
  10801. break;
  10802. default:
  10803. 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->end.empty() && scdb->endreturn.empty() && scdb->fail.empty()) {
  10804. // Status change with no calc, no icon, and no skill associated...?
  10805. 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);
  10806. return 0;
  10807. }
  10808. } else // Special considerations when loading SC data.
  10809. switch( type ) {
  10810. case SC_WEDDING:
  10811. case SC_XMAS:
  10812. case SC_SUMMER:
  10813. case SC_HANBOK:
  10814. case SC_OKTOBERFEST:
  10815. case SC_DRESSUP:
  10816. if( !vd )
  10817. break;
  10818. clif_changelook(bl,LOOK_BASE,vd->class_);
  10819. clif_changelook(bl,LOOK_WEAPON,0);
  10820. clif_changelook(bl,LOOK_SHIELD,0);
  10821. clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color);
  10822. clif_changelook(bl,LOOK_BODY2,0);
  10823. break;
  10824. case SC_STONE:
  10825. case SC_STONEWAIT:
  10826. case SC_POISON:
  10827. case SC_DPOISON:
  10828. case SC_BLEEDING:
  10829. case SC_BURNING:
  10830. case SC_TOXIN:
  10831. tick_time = tick;
  10832. tick = tick_time + max(val4, 0);
  10833. break;
  10834. case SC_DEATHHURT:
  10835. if (val3 == 1)
  10836. break;
  10837. tick_time = tick;
  10838. tick = tick_time + max(val4, 0);
  10839. case SC_MAGICMUSHROOM:
  10840. case SC_PYREXIA:
  10841. case SC_LEECHESEND:
  10842. if (val3 == 0)
  10843. break;
  10844. tick_time = tick;
  10845. tick = tick_time + max(val4, 0);
  10846. break;
  10847. case SC_SWORDCLAN:
  10848. case SC_ARCWANDCLAN:
  10849. case SC_GOLDENMACECLAN:
  10850. case SC_CROSSBOWCLAN:
  10851. case SC_JUMPINGCLAN:
  10852. case SC_CLAN_INFO:
  10853. // If the player still has a clan status, but was removed from his clan
  10854. if( sd && sd->status.clan_id == 0 ){
  10855. return 0;
  10856. }
  10857. break;
  10858. case SC_SERVANTWEAPON:
  10859. case SC_ABYSSFORCEWEAPON:
  10860. tick_time = tick;
  10861. tick = tick_time + max(val4, 0);
  10862. break;
  10863. }
  10864. if (sd && current_equip_combo_pos > 0 && tick == INFINITE_TICK) {
  10865. 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);
  10866. return 0;
  10867. }
  10868. /* [Ind] */
  10869. if (scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC]) {
  10870. int dval1 = 0, dval2 = 0, dval3 = 0;
  10871. switch (type) {
  10872. case SC_ALL_RIDING:
  10873. dval1 = 1;
  10874. break;
  10875. case SC_CLAN_INFO:
  10876. dval1 = val1;
  10877. dval2 = val2;
  10878. dval3 = val3;
  10879. break;
  10880. default: /* All others: just copy val1 */
  10881. dval1 = val1;
  10882. break;
  10883. }
  10884. status_display_add(bl,type,dval1,dval2,dval3);
  10885. }
  10886. //SC that force player to stand if is sitting
  10887. if (scdb->flag[SCF_SETSTAND] && sd && pc_issit(sd))
  10888. pc_setstand(sd, true);
  10889. //SC that make stop attacking [LuzZza]
  10890. if (scdb->flag[SCF_STOPATTACKING])
  10891. unit_stop_attack(bl);
  10892. //SC that make stop walking
  10893. if (scdb->flag[SCF_STOPWALKING]) {
  10894. switch (type) {
  10895. case SC_ANKLE:
  10896. if (battle_config.skill_trap_type || !map_flag_gvg(bl->m))
  10897. unit_stop_walking(bl, 1);
  10898. break;
  10899. case SC__MANHOLE:
  10900. if (bl->type == BL_PC || !unit_blown_immune(bl,0x1))
  10901. unit_stop_walking(bl,1);
  10902. break;
  10903. case SC_VACUUM_EXTREME:
  10904. if (bl->type != BL_PC && unit_blown_immune(bl, 0x1) == UB_KNOCKABLE) {
  10905. unit_stop_walking(bl,1);
  10906. unit_stop_attack(bl);
  10907. }
  10908. break;
  10909. case SC_FREEZE:
  10910. case SC_STUN:
  10911. case SC_STONE:
  10912. if (sc->data[SC_DANCING]) {
  10913. unit_stop_walking(bl, 1);
  10914. status_change_end(bl, SC_DANCING, INVALID_TIMER);
  10915. }
  10916. break;
  10917. default:
  10918. if (!unit_blown_immune(bl,0x1))
  10919. unit_stop_walking(bl,1);
  10920. break;
  10921. }
  10922. }
  10923. //SC that make stop casting
  10924. if (battle_config.sc_castcancel&bl->type && scdb->flag[SCF_STOPCASTING])
  10925. unit_skillcastcancel(bl,0);
  10926. sc->opt1 = scdb->opt1;
  10927. sc->opt2 |= scdb->opt2;
  10928. sc->opt3 |= scdb->opt3;
  10929. sc->option |= scdb->look;
  10930. std::bitset<SCF_MAX> opt_flag = scdb->flag;
  10931. uint16 disable_opt_flag = false;
  10932. switch(type) {
  10933. case SC_DANCING:
  10934. if ((val1&0xFFFF) != CG_MOONLIT)
  10935. sc->opt3 |= OPT3_MOONLIT;
  10936. break;
  10937. case SC_INCATKRATE:
  10938. // Simulate Explosion Spirits effect for NPC_POWERUP [Skotlex]
  10939. if (bl->type != BL_MOB) {
  10940. disable_opt_flag = true;
  10941. break;
  10942. }
  10943. break;
  10944. }
  10945. // On Aegis, when turning on a status change, first goes the option packet, then the sc packet.
  10946. if (!disable_opt_flag && (opt_flag[SCF_SENDOPTION] || opt_flag[SCF_ONTOUCH] || opt_flag[SCF_UNITMOVE] || opt_flag[SCF_NONPLAYER] || opt_flag[SCF_SENDLOOK])) {
  10947. clif_changeoption(bl);
  10948. if(sd && opt_flag[SCF_SENDLOOK]) {
  10949. clif_changelook(bl,LOOK_BASE,vd->class_);
  10950. clif_changelook(bl,LOOK_WEAPON,0);
  10951. clif_changelook(bl,LOOK_SHIELD,0);
  10952. clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color);
  10953. }
  10954. }
  10955. if (calc_flag[SCB_DYE]) { // Reset DYE color
  10956. if (vd && vd->cloth_color) {
  10957. val4 = vd->cloth_color;
  10958. clif_changelook(bl,LOOK_CLOTHES_COLOR,0);
  10959. }
  10960. calc_flag.reset(SCB_DYE);
  10961. }
  10962. /*if (calc_flag[SCB_BODY])// Might be needed in the future. [Rytech]
  10963. { //Reset body style
  10964. if (vd && vd->body_style)
  10965. {
  10966. val4 = vd->body_style;
  10967. clif_changelook(bl,LOOK_BODY2,0);
  10968. }
  10969. calc_flag.reset(SCB_BODY);
  10970. }*/
  10971. if (!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED && scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC])) {
  10972. int status_icon = scdb->icon;
  10973. #if PACKETVER < 20151104
  10974. if (status_icon == EFST_WEAPONPROPERTY)
  10975. status_icon = EFST_ATTACK_PROPERTY_NOTHING + val1; // Assign status icon for older clients
  10976. #endif
  10977. 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);
  10978. }
  10979. // Used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first.
  10980. if( tick_time )
  10981. tick = tick_time;
  10982. // Don't trust the previous sce assignment, in case the SC ended somewhere between there and here.
  10983. if((sce=sc->data[type])) { // reuse old sc
  10984. if( sce->timer != INVALID_TIMER )
  10985. delete_timer(sce->timer, status_change_timer);
  10986. sc_isnew = false;
  10987. } else { // New sc
  10988. ++(sc->count);
  10989. sce = sc->data[type] = ers_alloc(sc_data_ers, struct status_change_entry);
  10990. }
  10991. sce->val1 = val1;
  10992. sce->val2 = val2;
  10993. sce->val3 = val3;
  10994. sce->val4 = val4;
  10995. if (tick >= 0)
  10996. sce->timer = add_timer(gettick() + tick, status_change_timer, bl->id, type);
  10997. else
  10998. sce->timer = INVALID_TIMER; // Infinite duration
  10999. if (calc_flag.any()) {
  11000. if (sd) {
  11001. switch(type) {
  11002. // Statuses that adjust HP/SP and heal after starting
  11003. case SC_BERSERK:
  11004. case SC_MERC_HPUP:
  11005. case SC_MERC_SPUP:
  11006. status_calc_bl_(bl, calc_flag, SCO_FORCE);
  11007. break;
  11008. default:
  11009. status_calc_bl_(bl, calc_flag);
  11010. break;
  11011. }
  11012. } else
  11013. status_calc_bl_(bl, calc_flag);
  11014. }
  11015. // Non-zero
  11016. if (sc_isnew && scdb->state.any())
  11017. status_calc_state(bl, sc, scdb->state, true);
  11018. if (sd) {
  11019. if (sd->pd)
  11020. pet_sc_check(sd, type); // Skotlex: Pet Status Effect Healing
  11021. switch (type) {
  11022. case SC_BERSERK:
  11023. case SC_MERC_HPUP:
  11024. case SC_MERC_SPUP:
  11025. status_calc_pc(sd, SCO_FORCE);
  11026. break;
  11027. default:
  11028. if (!sd->state.connect_new)
  11029. status_calc_pc(sd, SCO_NONE);
  11030. break;
  11031. }
  11032. }
  11033. // 1st thing to execute when loading status
  11034. switch (type) {
  11035. case SC_BERSERK:
  11036. if (!(sce->val2)) { // Don't heal if already set
  11037. status_heal(bl, status->max_hp, 0, 1); // Do not use percent_heal as this healing must override BERSERK's block.
  11038. status_set_sp(bl, 0, 0); // Damage all SP
  11039. }
  11040. sce->val2 = 5 * status->max_hp / 100;
  11041. break;
  11042. case SC_RUN:
  11043. {
  11044. struct unit_data *ud = unit_bl2ud(bl);
  11045. if( ud )
  11046. ud->state.running = unit_run(bl, NULL, SC_RUN);
  11047. }
  11048. break;
  11049. case SC_BOSSMAPINFO:
  11050. if (sd)
  11051. clif_bossmapinfo(sd, map_id2boss(sce->val1), BOSS_INFO_ALIVE_WITHMSG); // First Message
  11052. break;
  11053. case SC_FULL_THROTTLE:
  11054. case SC_MERC_HPUP:
  11055. status_percent_heal(bl, 100, 0); // Recover Full HP
  11056. break;
  11057. case SC_MERC_SPUP:
  11058. status_percent_heal(bl, 0, 100); // Recover Full SP
  11059. break;
  11060. case SC_WUGDASH:
  11061. {
  11062. struct unit_data *ud = unit_bl2ud(bl);
  11063. if( ud )
  11064. ud->state.running = unit_run(bl, sd, SC_WUGDASH);
  11065. }
  11066. break;
  11067. case SC_COMBO:
  11068. switch(sce->val1) {
  11069. case TK_STORMKICK:
  11070. skill_combo_toggle_inf(bl, TK_JUMPKICK, 0);
  11071. clif_skill_nodamage(bl,bl,TK_READYSTORM,1,1);
  11072. break;
  11073. case TK_DOWNKICK:
  11074. skill_combo_toggle_inf(bl, TK_JUMPKICK, 0);
  11075. clif_skill_nodamage(bl,bl,TK_READYDOWN,1,1);
  11076. break;
  11077. case TK_TURNKICK:
  11078. skill_combo_toggle_inf(bl, TK_JUMPKICK, 0);
  11079. clif_skill_nodamage(bl,bl,TK_READYTURN,1,1);
  11080. break;
  11081. case TK_COUNTER:
  11082. skill_combo_toggle_inf(bl, TK_JUMPKICK, 0);
  11083. clif_skill_nodamage(bl,bl,TK_READYCOUNTER,1,1);
  11084. break;
  11085. default: // Rest just toggle inf to enable autotarget
  11086. skill_combo_toggle_inf(bl,sce->val1,INF_SELF_SKILL);
  11087. break;
  11088. }
  11089. break;
  11090. case SC_C_MARKER:
  11091. //Send mini-map, don't wait for first timer triggered
  11092. if (src->type == BL_PC && (sd = map_id2sd(src->id)))
  11093. clif_crimson_marker(sd, bl, false);
  11094. break;
  11095. case SC_ITEMSCRIPT: // Shows Buff Icons
  11096. if (sd)
  11097. clif_status_change(bl, (efst_type)val2, 1, tick, 0, 0, 0);
  11098. break;
  11099. case SC_GVG_GIANT:
  11100. case SC_GVG_GOLEM:
  11101. case SC_GVG_STUN:
  11102. case SC_GVG_STONE:
  11103. case SC_GVG_FREEZ:
  11104. case SC_GVG_SLEEP:
  11105. case SC_GVG_CURSE:
  11106. case SC_GVG_SILENCE:
  11107. case SC_GVG_BLIND:
  11108. if (val1 || val2)
  11109. status_zap(bl, val1 ? val1 : 0, val2 ? val2 : 0);
  11110. break;
  11111. }
  11112. if( opt_flag[SCF_ONTOUCH] && sd && !sd->npc_ontouch_.empty() )
  11113. npc_touchnext_areanpc(sd,false); // Run OnTouch_ on next char in range
  11114. return 1;
  11115. }
  11116. /**
  11117. * End all statuses except those listed
  11118. * TODO: May be useful for dispel instead resetting a list there
  11119. * @param src: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
  11120. * @param type: Changes behaviour of the function
  11121. * 0: PC killed -> Place here statuses that do not dispel on death.
  11122. * 1: If for some reason status_change_end decides to still keep the status when quitting.
  11123. * 2: Do clif_changeoption()
  11124. * 3: Do not remove some permanent/time-independent effects
  11125. * @return 1: Success 0: Fail
  11126. */
  11127. int status_change_clear(struct block_list* bl, int type)
  11128. {
  11129. struct status_change* sc;
  11130. sc = status_get_sc(bl);
  11131. if (!sc)
  11132. return 0;
  11133. // Cleaning all extras vars
  11134. sc->comet_x = 0;
  11135. sc->comet_y = 0;
  11136. #ifndef RENEWAL
  11137. sc->sg_counter = 0;
  11138. #endif
  11139. if (!sc->count)
  11140. return 0;
  11141. for (const auto &it : status_db) {
  11142. sc_type status = static_cast<sc_type>(it.first);
  11143. if (!sc->data[status])
  11144. continue;
  11145. if (type == 0) { // Type 0: PC killed
  11146. if (it.second->flag[SCF_NOREMOVEONDEAD]) {
  11147. switch (status) {
  11148. case SC_ELEMENTALCHANGE: // Only when its Holy or Dark that it doesn't dispell on death
  11149. if (sc->data[status]->val2 != ELE_HOLY && sc->data[status]->val2 != ELE_DARK)
  11150. break;
  11151. default:
  11152. continue;
  11153. }
  11154. }
  11155. }
  11156. if (type == 3 && it.second->flag[SCF_NOCLEARBUFF])
  11157. continue;
  11158. status_change_end(bl, status, INVALID_TIMER);
  11159. if( type == 1 && sc->data[status] ) { // If for some reason status_change_end decides to still keep the status when quitting. [Skotlex]
  11160. (sc->count)--;
  11161. if (sc->data[status]->timer != INVALID_TIMER)
  11162. delete_timer(sc->data[status]->timer, status_change_timer);
  11163. ers_free(sc_data_ers, sc->data[status]);
  11164. sc->data[status] = NULL;
  11165. }
  11166. }
  11167. sc->opt1 = 0;
  11168. sc->opt2 = 0;
  11169. sc->opt3 = 0;
  11170. if( type == 0 || type == 2 )
  11171. clif_changeoption(bl);
  11172. return 1;
  11173. }
  11174. /**
  11175. * End a specific status after checking
  11176. * @param bl: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
  11177. * @param type: Status change (SC_*)
  11178. * @param tid: Timer
  11179. * @param file: Used for dancing save
  11180. * @param line: Used for dancing save
  11181. * @return 1: Success 0: Fail
  11182. */
  11183. int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const char* file, int line)
  11184. {
  11185. struct map_session_data *sd;
  11186. struct status_change *sc;
  11187. struct status_change_entry *sce;
  11188. struct status_data *status;
  11189. struct view_data *vd;
  11190. std::shared_ptr<s_status_change_db> scdb = status_db.find(type);
  11191. nullpo_ret(bl);
  11192. sc = status_get_sc(bl);
  11193. status = status_get_status_data(bl);
  11194. if(!sc || !(sce = sc->data[type]) || !scdb)
  11195. return 0;
  11196. sd = BL_CAST(BL_PC,bl);
  11197. if (sce->timer != tid && tid != INVALID_TIMER)
  11198. return 0;
  11199. if (tid == INVALID_TIMER) {
  11200. if (type == SC_ENDURE && sce->val4)
  11201. // Do not end infinite endure.
  11202. return 0;
  11203. if (type == SC_SPIDERWEB) {
  11204. //Delete the unit group first to expire found in the status change
  11205. std::shared_ptr<s_skill_unit_group> group, group2;
  11206. t_tick tick = gettick();
  11207. int pos = 1;
  11208. if (sce->val2)
  11209. if (!(group = skill_id2group(sce->val2)))
  11210. sce->val2 = 0;
  11211. if (sce->val3) {
  11212. if (!(group2 = skill_id2group(sce->val3)))
  11213. sce->val3 = 0;
  11214. else if (!group || ((group->limit - DIFF_TICK(tick, group->tick)) > (group2->limit - DIFF_TICK(tick, group2->tick)))) {
  11215. group = group2;
  11216. pos = 2;
  11217. }
  11218. }
  11219. if (sce->val4) {
  11220. if (!(group2 = skill_id2group(sce->val4)))
  11221. sce->val4 = 0;
  11222. else if (!group || ((group->limit - DIFF_TICK(tick, group->tick)) > (group2->limit - DIFF_TICK(tick, group2->tick)))) {
  11223. group = group2;
  11224. pos = 3;
  11225. }
  11226. }
  11227. if (pos == 1)
  11228. sce->val2 = 0;
  11229. else if (pos == 2)
  11230. sce->val3 = 0;
  11231. else if (pos == 3)
  11232. sce->val4 = 0;
  11233. if (group)
  11234. skill_delunitgroup(group);
  11235. if (!status_isdead(bl) && (sce->val2 || sce->val3 || sce->val4))
  11236. return 0; //Don't end the status change yet as there are still unit groups associated with it
  11237. }
  11238. if (sce->timer != INVALID_TIMER) // Could be a SC with infinite duration
  11239. delete_timer(sce->timer,status_change_timer);
  11240. }
  11241. (sc->count)--;
  11242. if (scdb->state.any())
  11243. status_calc_state(bl,sc,scdb->state,false);
  11244. sc->data[type] = NULL;
  11245. if (scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC])
  11246. status_display_remove(bl,type);
  11247. vd = status_get_viewdata(bl);
  11248. std::bitset<SCB_MAX> calc_flag = scdb->calc_flag;
  11249. switch(type) {
  11250. case SC_KEEPING:
  11251. case SC_BARRIER: {
  11252. unit_data *ud = unit_bl2ud(bl);
  11253. if (ud)
  11254. ud->attackabletime = ud->canact_tick = ud->canmove_tick = gettick();
  11255. }
  11256. break;
  11257. case SC_GRANITIC_ARMOR:
  11258. {
  11259. int damage = status->max_hp*sce->val3/100;
  11260. if(status->hp < damage) // to not kill him
  11261. damage = status->hp-1;
  11262. status_damage(NULL,bl,damage,0,0,1,0);
  11263. }
  11264. break;
  11265. case SC_RUN:
  11266. {
  11267. struct unit_data *ud = unit_bl2ud(bl);
  11268. bool begin_spurt = true;
  11269. // Note: this int64 value is stored in two separate int32 variables (FIXME)
  11270. t_tick starttick = (t_tick)sce->val3&0x00000000ffffffffLL;
  11271. starttick |= ((t_tick)sce->val4<<32)&0xffffffff00000000LL;
  11272. if (ud) {
  11273. if(!ud->state.running)
  11274. begin_spurt = false;
  11275. ud->state.running = 0;
  11276. if (ud->walktimer != INVALID_TIMER)
  11277. unit_stop_walking(bl,1);
  11278. }
  11279. if (begin_spurt && sce->val1 >= 7 &&
  11280. DIFF_TICK(gettick(), starttick) <= 1000 &&
  11281. (!sd || (sd->weapontype1 == W_FIST && sd->weapontype2 == W_FIST))
  11282. )
  11283. sc_start(bl,bl,SC_SPURT,100,sce->val1,skill_get_time2(scdb->skill_id, sce->val1));
  11284. }
  11285. break;
  11286. case SC_AUTOBERSERK:
  11287. if (sc->data[SC_PROVOKE] && sc->data[SC_PROVOKE]->val4 == 1)
  11288. status_change_end(bl, SC_PROVOKE, INVALID_TIMER);
  11289. break;
  11290. case SC_ENDURE:
  11291. case SC_DEFENDER:
  11292. case SC_REFLECTSHIELD:
  11293. case SC_AUTOGUARD:
  11294. {
  11295. struct map_session_data *tsd;
  11296. if( bl->type == BL_PC ) { // Clear Status from others
  11297. int i;
  11298. for( i = 0; i < MAX_DEVOTION; i++ ) {
  11299. if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) && tsd->sc.data[type] )
  11300. status_change_end(&tsd->bl, type, INVALID_TIMER);
  11301. }
  11302. }
  11303. else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag ) { // Clear Status from Master
  11304. tsd = ((TBL_MER*)bl)->master;
  11305. if( tsd && tsd->sc.data[type] )
  11306. status_change_end(&tsd->bl, type, INVALID_TIMER);
  11307. }
  11308. }
  11309. break;
  11310. case SC_DEVOTION:
  11311. {
  11312. struct block_list *d_bl = map_id2bl(sce->val1);
  11313. if( d_bl ) {
  11314. if( d_bl->type == BL_PC )
  11315. ((TBL_PC*)d_bl)->devotion[sce->val2] = 0;
  11316. else if( d_bl->type == BL_MER )
  11317. ((TBL_MER*)d_bl)->devotion_flag = 0;
  11318. clif_devotion(d_bl, NULL);
  11319. }
  11320. status_change_end(bl, SC_AUTOGUARD, INVALID_TIMER);
  11321. status_change_end(bl, SC_DEFENDER, INVALID_TIMER);
  11322. status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER);
  11323. status_change_end(bl, SC_ENDURE, INVALID_TIMER);
  11324. }
  11325. break;
  11326. case SC_FLASHKICK: {
  11327. map_session_data *tsd;
  11328. if (!(tsd = map_id2sd(sce->val1)))
  11329. break;
  11330. tsd->stellar_mark[sce->val2] = 0;
  11331. }
  11332. break;
  11333. case SC_SOULUNITY: {
  11334. map_session_data *tsd;
  11335. if (!(tsd = map_id2sd(sce->val2)))
  11336. break;
  11337. tsd->united_soul[sce->val3] = 0;
  11338. }
  11339. break;
  11340. case SC_BLADESTOP:
  11341. if(sce->val4) {
  11342. int tid2 = sce->val4; //stop the status for the other guy of bladestop as well
  11343. struct block_list *tbl = map_id2bl(tid2);
  11344. struct status_change *tsc = status_get_sc(tbl);
  11345. sce->val4 = 0;
  11346. if(tbl && tsc && tsc->data[SC_BLADESTOP]) {
  11347. tsc->data[SC_BLADESTOP]->val4 = 0;
  11348. status_change_end(tbl, SC_BLADESTOP, INVALID_TIMER);
  11349. }
  11350. clif_bladestop(bl, tid2, 0);
  11351. }
  11352. break;
  11353. case SC_DANCING:
  11354. {
  11355. struct map_session_data *dsd;
  11356. struct status_change_entry *dsc;
  11357. if(sce->val4 && sce->val4 != BCT_SELF && (dsd=map_id2sd(sce->val4))) { // End status on partner as well
  11358. dsc = dsd->sc.data[SC_DANCING];
  11359. if(dsc) {
  11360. // This will prevent recursive loops.
  11361. dsc->val2 = dsc->val4 = 0;
  11362. status_change_end(&dsd->bl, SC_DANCING, INVALID_TIMER);
  11363. }
  11364. }
  11365. if(sce->val2) { // Erase associated land skill
  11366. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val2);
  11367. sce->val2 = 0;
  11368. if (group)
  11369. skill_delunitgroup(group);
  11370. }
  11371. if((sce->val1&0xFFFF) == CG_MOONLIT)
  11372. clif_status_change(bl,EFST_MOON,0,0,0,0,0);
  11373. #ifdef RENEWAL
  11374. status_change_end(bl, SC_ENSEMBLEFATIGUE, INVALID_TIMER);
  11375. #else
  11376. status_change_end(bl, SC_LONGING, INVALID_TIMER);
  11377. #endif
  11378. }
  11379. break;
  11380. case SC_NOCHAT:
  11381. if (sd && sd->status.manner < 0 && tid != INVALID_TIMER)
  11382. sd->status.manner = 0;
  11383. if (sd && tid == INVALID_TIMER) {
  11384. clif_changestatus(sd,SP_MANNER,sd->status.manner);
  11385. clif_updatestatus(sd,SP_MANNER);
  11386. }
  11387. break;
  11388. case SC_SPLASHER:
  11389. case SC_ROSEBLOSSOM:
  11390. {
  11391. struct block_list *src=map_id2bl(sce->val3);
  11392. if(src && tid != INVALID_TIMER)
  11393. skill_castend_damage_id(src, bl, sce->val2, sce->val1, gettick(), SD_LEVEL );
  11394. }
  11395. break;
  11396. case SC_CLOSECONFINE2:{
  11397. struct block_list *src = sce->val2?map_id2bl(sce->val2):NULL;
  11398. struct status_change *sc2 = src?status_get_sc(src):NULL;
  11399. if (src && sc2 && sc2->data[SC_CLOSECONFINE]) {
  11400. // If status was already ended, do nothing.
  11401. // Decrease count
  11402. if (--(sc2->data[SC_CLOSECONFINE]->val1) <= 0) // No more holds, free him up.
  11403. status_change_end(src, SC_CLOSECONFINE, INVALID_TIMER);
  11404. }
  11405. }
  11406. case SC_CLOSECONFINE:
  11407. if (sce->val2 > 0) {
  11408. // Caster has been unlocked... nearby chars need to be unlocked.
  11409. int range = 1
  11410. + skill_get_range2(bl, scdb->skill_id, sce->val1, true)
  11411. + skill_get_range2(bl, TF_BACKSLIDING, 1, true); // Since most people use this to escape the hold....
  11412. map_foreachinallarea(status_change_timer_sub,
  11413. bl->m, bl->x-range, bl->y-range, bl->x+range,bl->y+range,BL_CHAR,bl,sce,type,gettick());
  11414. }
  11415. break;
  11416. case SC_COMBO:
  11417. skill_combo_toggle_inf(bl,sce->val1,0);
  11418. break;
  11419. case SC_MARIONETTE:
  11420. case SC_MARIONETTE2: // Marionette target
  11421. if (sce->val1) { // Check for partner and end their marionette status as well
  11422. enum sc_type type2 = (type == SC_MARIONETTE) ? SC_MARIONETTE2 : SC_MARIONETTE;
  11423. struct block_list *pbl = map_id2bl(sce->val1);
  11424. struct status_change* sc2 = pbl?status_get_sc(pbl):NULL;
  11425. if (sc2 && sc2->data[type2]) {
  11426. sc2->data[type2]->val1 = 0;
  11427. status_change_end(pbl, type2, INVALID_TIMER);
  11428. }
  11429. }
  11430. break;
  11431. case SC_CONCENTRATION:
  11432. if (sc->data[SC_ENDURE] && !sc->data[SC_ENDURE]->val4)
  11433. status_change_end(bl, SC_ENDURE, INVALID_TIMER);
  11434. break;
  11435. case SC_BERSERK:
  11436. if(status->hp > 200 && sc && sc->data[SC__BLOODYLUST]) {
  11437. status_percent_heal(bl, 100, 0);
  11438. status_change_end(bl, SC__BLOODYLUST, INVALID_TIMER);
  11439. } else if (status->hp > 100 && sce->val2) // If val2 is removed, no HP penalty (dispelled?) [Skotlex]
  11440. status_set_hp(bl, 100, 0);
  11441. if(sc->data[SC_ENDURE] && sc->data[SC_ENDURE]->val4) {
  11442. sc->data[SC_ENDURE]->val4 = 0;
  11443. status_change_end(bl, SC_ENDURE, INVALID_TIMER);
  11444. }
  11445. sc_start4(bl, bl, SC_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill_get_time(LK_BERSERK, sce->val1));
  11446. break;
  11447. case SC_GOSPEL:
  11448. if (sce->val3) { // Clear the group.
  11449. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val3);
  11450. sce->val3 = 0;
  11451. if (group)
  11452. skill_delunitgroup(group);
  11453. }
  11454. break;
  11455. #ifndef RENEWAL
  11456. case SC_HERMODE:
  11457. if(sce->val3 == BCT_SELF)
  11458. skill_clear_unitgroup(bl);
  11459. break;
  11460. case SC_BASILICA: // Clear the skill area. [Skotlex]
  11461. if (sce->val3 && sce->val4 == bl->id) {
  11462. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val3);
  11463. sce->val3 = 0;
  11464. if (group)
  11465. skill_delunitgroup(group);
  11466. }
  11467. break;
  11468. #endif
  11469. case SC_TRICKDEAD:
  11470. if (vd) vd->dead_sit = 0;
  11471. break;
  11472. case SC_WARM:
  11473. case SC__MANHOLE:
  11474. case SC_BANDING:
  11475. case SC_LEADERSHIP:
  11476. case SC_GLORYWOUNDS:
  11477. case SC_SOULCOLD:
  11478. case SC_HAWKEYES:
  11479. if (sce->val4) { // Clear the group.
  11480. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val4);
  11481. sce->val4 = 0;
  11482. if( group ) // Might have been cleared before status ended, e.g. land protector
  11483. skill_delunitgroup(group);
  11484. }
  11485. break;
  11486. case SC_JAILED:
  11487. if(tid == INVALID_TIMER)
  11488. break;
  11489. // Natural expiration.
  11490. if(sd && sd->mapindex == sce->val2)
  11491. pc_setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT);
  11492. break; // Guess hes not in jail :P
  11493. case SC_CHANGE:
  11494. if (tid == INVALID_TIMER)
  11495. break;
  11496. // "lose almost all their HP and SP" on natural expiration.
  11497. status_set_hp(bl, 10, 0);
  11498. status_set_sp(bl, 10, 0);
  11499. break;
  11500. case SC_AUTOTRADE:
  11501. if (tid == INVALID_TIMER)
  11502. break;
  11503. // Vending is not automatically closed for autovenders
  11504. vending_closevending(sd);
  11505. map_quit(sd);
  11506. // Because map_quit calls status_change_end with tid -1
  11507. // from here it's not neccesary to continue
  11508. return 1;
  11509. break;
  11510. case SC_STOP:
  11511. if( sce->val2 ) {
  11512. struct block_list* tbl = map_id2bl(sce->val2);
  11513. sce->val2 = 0;
  11514. if( tbl && (sc = status_get_sc(tbl)) && sc->data[SC_STOP] && sc->data[SC_STOP]->val2 == bl->id )
  11515. status_change_end(tbl, SC_STOP, INVALID_TIMER);
  11516. }
  11517. break;
  11518. case SC_TENSIONRELAX:
  11519. if (sc && (sc->data[SC_WEIGHT50] || sc->data[SC_WEIGHT90]))
  11520. status_get_regen_data(bl)->state.overweight = 1; // Add the overweight flag back
  11521. break;
  11522. case SC_MONSTER_TRANSFORM:
  11523. case SC_ACTIVE_MONSTER_TRANSFORM:
  11524. if (sce->val2)
  11525. status_change_end(bl, (sc_type)sce->val2, INVALID_TIMER);
  11526. break;
  11527. /* 3rd Stuff */
  11528. case SC_MILLENNIUMSHIELD:
  11529. clif_millenniumshield(bl, 0);
  11530. break;
  11531. case SC_HALLUCINATIONWALK:
  11532. sc_start(bl,bl,SC_HALLUCINATIONWALK_POSTDELAY,100,sce->val1,skill_get_time2(GC_HALLUCINATIONWALK,sce->val1));
  11533. break;
  11534. case SC_WHITEIMPRISON:
  11535. {
  11536. struct block_list* src = map_id2bl(sce->val2);
  11537. if( tid == -1 || !src)
  11538. break; // Terminated by Damage
  11539. 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);
  11540. }
  11541. break;
  11542. case SC_WUGDASH:
  11543. {
  11544. struct unit_data *ud = unit_bl2ud(bl);
  11545. if (ud) {
  11546. ud->state.running = 0;
  11547. if (ud->walktimer != INVALID_TIMER)
  11548. unit_stop_walking(bl,1);
  11549. }
  11550. }
  11551. break;
  11552. case SC__SHADOWFORM:
  11553. {
  11554. struct map_session_data *s_sd = map_id2sd(sce->val2);
  11555. if (s_sd) s_sd->shadowform_id = 0;
  11556. }
  11557. break;
  11558. case SC_SATURDAYNIGHTFEVER: // Sit down force of Saturday Night Fever has the duration of only 3 seconds.
  11559. sc_start(bl, bl,SC_SITDOWN_FORCE,100,sce->val1,skill_get_time2(WM_SATURDAY_NIGHT_FEVER,sce->val1));
  11560. break;
  11561. case SC_NEUTRALBARRIER_MASTER:
  11562. case SC_STEALTHFIELD_MASTER:
  11563. if( sce->val2 ) {
  11564. std::shared_ptr<s_skill_unit_group> group = skill_id2group(sce->val2);
  11565. sce->val2 = 0;
  11566. if( group ) // Might have been cleared before status ended, e.g. land protector
  11567. skill_delunitgroup(group);
  11568. }
  11569. break;
  11570. case SC_CURSEDCIRCLE_ATKER:
  11571. if( sce->val2 ) // Used the default area size cause there is a chance the caster could knock back and can't clear the target.
  11572. map_foreachinallrange(status_change_timer_sub, bl, AREA_SIZE + 3, BL_CHAR, bl, sce, SC_CURSEDCIRCLE_TARGET, gettick());
  11573. break;
  11574. case SC_RAISINGDRAGON:
  11575. if( sd && !pc_isdead(sd) ) {
  11576. int i = min(sd->spiritball,5);
  11577. pc_delspiritball(sd, sd->spiritball, 0);
  11578. status_change_end(bl, SC_EXPLOSIONSPIRITS, INVALID_TIMER);
  11579. while( i > 0 ) {
  11580. pc_addspiritball(sd, skill_get_time(MO_CALLSPIRITS, pc_checkskill(sd,MO_CALLSPIRITS)), 5);
  11581. --i;
  11582. }
  11583. }
  11584. break;
  11585. case SC_CURSEDCIRCLE_TARGET:
  11586. {
  11587. struct block_list *src = map_id2bl(sce->val2);
  11588. struct status_change *sc2 = status_get_sc(src);
  11589. if( sc2 && sc2->data[SC_CURSEDCIRCLE_ATKER] && --(sc2->data[SC_CURSEDCIRCLE_ATKER]->val2) == 0 ) {
  11590. clif_bladestop(bl, sce->val2, 0);
  11591. status_change_end(src, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER);
  11592. }
  11593. }
  11594. break;
  11595. case SC_TEARGAS:
  11596. status_change_end(bl,SC_TEARGAS_SOB,INVALID_TIMER);
  11597. break;
  11598. case SC_SITDOWN_FORCE:
  11599. case SC_BANANA_BOMB_SITDOWN:
  11600. if( sd && pc_issit(sd) && pc_setstand(sd, false) )
  11601. skill_sit(sd, false);
  11602. break;
  11603. case SC_KYOUGAKU:
  11604. clif_status_load(bl, EFST_KYOUGAKU, 0); // Avoid client crash
  11605. clif_status_load(bl, EFST_ACTIVE_MONSTER_TRANSFORM, 0);
  11606. break;
  11607. case SC_INTRAVISION:
  11608. calc_flag = status_db.getSCB_ALL(); // Required for overlapping
  11609. break;
  11610. case SC_SUNSTANCE:
  11611. status_change_end(bl, SC_LIGHTOFSUN, INVALID_TIMER);
  11612. break;
  11613. case SC_LUNARSTANCE:
  11614. status_change_end(bl, SC_NEWMOON, INVALID_TIMER);
  11615. status_change_end(bl, SC_LIGHTOFMOON, INVALID_TIMER);
  11616. break;
  11617. case SC_STARSTANCE:
  11618. status_change_end(bl, SC_FALLINGSTAR, INVALID_TIMER);
  11619. status_change_end(bl, SC_LIGHTOFSTAR, INVALID_TIMER);
  11620. break;
  11621. case SC_UNIVERSESTANCE:
  11622. status_change_end(bl, SC_LIGHTOFSUN, INVALID_TIMER);
  11623. status_change_end(bl, SC_NEWMOON, INVALID_TIMER);
  11624. status_change_end(bl, SC_LIGHTOFMOON, INVALID_TIMER);
  11625. status_change_end(bl, SC_FALLINGSTAR, INVALID_TIMER);
  11626. status_change_end(bl, SC_LIGHTOFSTAR, INVALID_TIMER);
  11627. status_change_end(bl, SC_DIMENSION, INVALID_TIMER);
  11628. break;
  11629. case SC_GRAVITYCONTROL:
  11630. status_fix_damage(bl, bl, sce->val2, clif_damage(bl, bl, gettick(), 0, 0, sce->val2, 0, DMG_NORMAL, 0, false), 0);
  11631. clif_specialeffect(bl, 223, AREA);
  11632. clif_specialeffect(bl, 330, AREA);
  11633. break;
  11634. case SC_OVERED_BOOST:
  11635. switch (bl->type) {
  11636. case BL_HOM: {
  11637. struct homun_data *hd = BL_CAST(BL_HOM,bl);
  11638. if( hd )
  11639. hd->homunculus.hunger = max(1,hd->homunculus.hunger - 50);
  11640. }
  11641. break;
  11642. case BL_PC:
  11643. status_zap(bl,0,status_get_max_sp(bl) / 2);
  11644. break;
  11645. }
  11646. break;
  11647. case SC_FULL_THROTTLE: {
  11648. int sec = skill_get_time2(scdb->skill_id, sce->val1);
  11649. clif_status_change(bl, EFST_DEC_AGI, 1, sec, 0, 0, 0);
  11650. sc_start(bl, bl, SC_REBOUND, 100, sce->val1, sec);
  11651. }
  11652. break;
  11653. case SC_REBOUND:
  11654. clif_status_load(bl, EFST_DEC_AGI, 0);
  11655. break;
  11656. case SC_ITEMSCRIPT: // Removes Buff Icons
  11657. if (sd)
  11658. clif_status_load(bl, (enum efst_type)sce->val2, 0);
  11659. break;
  11660. case SC_C_MARKER:
  11661. {
  11662. // Remove mark data from caster
  11663. struct map_session_data *caster = map_id2sd(sce->val2);
  11664. uint8 i = 0;
  11665. if (!caster)
  11666. break;
  11667. ARR_FIND(0,MAX_SKILL_CRIMSON_MARKER,i,caster->c_marker[i] == bl->id);
  11668. if (i < MAX_SKILL_CRIMSON_MARKER) {
  11669. caster->c_marker[i] = 0;
  11670. clif_crimson_marker(caster, bl, true);
  11671. }
  11672. }
  11673. break;
  11674. case SC_H_MINE:
  11675. {
  11676. // Drop the material from target if expired
  11677. struct item it;
  11678. struct map_session_data *caster = NULL;
  11679. if (sce->val3 || status_isdead(bl) || !(caster = map_id2sd(sce->val2)))
  11680. break;
  11681. std::shared_ptr<s_skill_db> skill = skill_db.find(RL_H_MINE);
  11682. if (!itemdb_exists(skill->require.itemid[0]))
  11683. break;
  11684. memset(&it, 0, sizeof(it));
  11685. it.nameid = skill->require.itemid[0];
  11686. it.amount = max(skill->require.amount[0],1);
  11687. it.identify = 1;
  11688. map_addflooritem(&it, it.amount, bl->m,bl->x, bl->y, caster->status.char_id, 0, 0, 4, 0);
  11689. }
  11690. break;
  11691. case SC_VACUUM_EXTREME:
  11692. ///< !CHECKME: Seems on official, there's delay before same target can be vacuumed in same area again [Cydh]
  11693. sc_start2(bl, bl, SC_VACUUM_EXTREME_POSTDELAY, 100, sce->val1, sce->val2, skill_get_time2(SO_VACUUM_EXTREME,sce->val1));
  11694. break;
  11695. case SC_SWORDCLAN:
  11696. case SC_ARCWANDCLAN:
  11697. case SC_GOLDENMACECLAN:
  11698. case SC_CROSSBOWCLAN:
  11699. case SC_JUMPINGCLAN:
  11700. status_change_end(bl,SC_CLAN_INFO,INVALID_TIMER);
  11701. break;
  11702. case SC_DIMENSION1:
  11703. case SC_DIMENSION2:
  11704. if (sd)
  11705. pc_delspiritball(sd, 1, 0);
  11706. break;
  11707. case SC_SOULENERGY:
  11708. if (sd)
  11709. pc_delsoulball(sd, sd->soulball, false);
  11710. break;
  11711. case SC_MADOGEAR:
  11712. status_db.removeByStatusFlag(bl, { SCF_MADOENDCANCEL });
  11713. if (sd)
  11714. pc_bonus_script_clear(sd, BSF_REM_ON_MADOGEAR);
  11715. break;
  11716. case SC_HOMUN_TIME:
  11717. if (sd && hom_is_active(sd->hd))
  11718. hom_vaporize(sd, HOM_ST_REST);
  11719. break;
  11720. case SC_SERVANT_SIGN: {
  11721. map_session_data *tsd = map_id2sd(sce->val1);
  11722. if( tsd != nullptr )
  11723. tsd->servant_sign[sce->val2] = 0;
  11724. }
  11725. break;
  11726. case SC_SOUNDBLEND: {
  11727. block_list *src = map_id2bl(sce->val2);
  11728. if (src && tid != INVALID_TIMER)
  11729. skill_castend_damage_id(src, bl, TR_SOUNDBLEND, sce->val1, gettick(), SD_LEVEL|SD_ANIMATION);
  11730. }
  11731. break;
  11732. case SC_SERVANTWEAPON:
  11733. if( sd ){
  11734. pc_delservantball( *sd, sd->servantball );
  11735. }
  11736. break;
  11737. case SC_CHARGINGPIERCE:
  11738. status_change_end(bl, SC_CHARGINGPIERCE_COUNT, INVALID_TIMER);
  11739. break;
  11740. case SC_ABYSSFORCEWEAPON:
  11741. if( sd ){
  11742. pc_delabyssball( *sd, sd->abyssball );
  11743. }
  11744. break;
  11745. }
  11746. // Reset the options as needed
  11747. std::bitset<SCF_MAX> opt_flag = scdb->flag;
  11748. bool disable_opt_flag = false;
  11749. switch (type) {
  11750. case SC_DANCING:
  11751. if ((sce->val1&0xFFFF) == CG_MOONLIT)
  11752. sc->opt3 &= ~OPT3_MOONLIT;
  11753. break;
  11754. case SC_INCATKRATE: // Simulated Explosion spirits effect.
  11755. if (bl->type != BL_MOB) {
  11756. disable_opt_flag = true;
  11757. break;
  11758. }
  11759. break;
  11760. }
  11761. if (scdb->opt1)
  11762. sc->opt1 = OPT1_NONE;
  11763. if (scdb->opt2)
  11764. sc->opt2 &= ~scdb->opt2;
  11765. if (scdb->opt3)
  11766. sc->opt3 &= ~scdb->opt3;
  11767. if (scdb->look)
  11768. sc->option &= ~scdb->look;
  11769. if (calc_flag[SCB_DYE]) { // Restore DYE color
  11770. if (vd && !vd->cloth_color && sce->val4)
  11771. clif_changelook(bl,LOOK_CLOTHES_COLOR,sce->val4);
  11772. calc_flag.reset(SCB_DYE);
  11773. }
  11774. /*if (calc_flag[SCB_BODY])// Might be needed in the future. [Rytech]
  11775. { //Restore body style
  11776. if (vd && !vd->body_style && sce->val4)
  11777. clif_changelook(bl,LOOK_BODY2,sce->val4);
  11778. calc_flag.reset(SCB_BODY);
  11779. }*/
  11780. // On Aegis, when turning off a status change, first goes the sc packet, then the option packet.
  11781. int status_icon = scdb->icon;
  11782. #if PACKETVER < 20151104
  11783. if (status_icon == EFST_WEAPONPROPERTY)
  11784. status_icon = EFST_ATTACK_PROPERTY_NOTHING + sce->val1; // Assign status icon for older clients
  11785. #endif
  11786. clif_status_change(bl,status_icon,0,0,0,0,0);
  11787. if( opt_flag[SCF_NONPLAYER] ) // bugreport:681
  11788. clif_changeoption2(bl);
  11789. 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])) {
  11790. clif_changeoption(bl);
  11791. if (sd && opt_flag[SCF_SENDLOOK]) {
  11792. clif_changelook(bl,LOOK_BASE,sd->vd.class_);
  11793. clif_get_weapon_view(sd,&sd->vd.weapon,&sd->vd.shield);
  11794. clif_changelook(bl,LOOK_WEAPON,sd->vd.weapon);
  11795. clif_changelook(bl,LOOK_SHIELD,sd->vd.shield);
  11796. clif_changelook(bl,LOOK_CLOTHES_COLOR,cap_value(sd->status.clothes_color,0,battle_config.max_cloth_color));
  11797. clif_changelook(bl,LOOK_BODY2,cap_value(sd->status.body,0,battle_config.max_body_style));
  11798. }
  11799. }
  11800. if (calc_flag.any()) {
  11801. #ifndef RENEWAL
  11802. if (type == SC_MAGICPOWER) {
  11803. //If Mystical Amplification ends, MATK is immediately recalculated
  11804. status_calc_bl_(bl, calc_flag, SCO_FORCE);
  11805. } else
  11806. #endif
  11807. status_calc_bl_(bl, calc_flag);
  11808. }
  11809. if(opt_flag[SCF_UNITMOVE]) // Out of hiding, invoke on place.
  11810. skill_unit_move(bl,gettick(),1);
  11811. if(opt_flag[SCF_ONTOUCH] && sd && !sd->state.warping && map_getcell(bl->m,bl->x,bl->y,CELL_CHKNPC))
  11812. npc_touch_area_allnpc(sd,bl->m,bl->x,bl->y); // Trigger on-touch event.
  11813. // Needed to be here to make sure OPT1_STONEWAIT has been cleared from the target
  11814. if (type == SC_STONEWAIT)
  11815. status_change_start(bl, bl, SC_STONE, 100, sce->val1, sce->val2, 0, 0, sce->val3, SCSTART_NOAVOID);
  11816. ers_free(sc_data_ers, sce);
  11817. return 1;
  11818. }
  11819. /**
  11820. * Resets timers for statuses
  11821. * Used with reoccurring status effects, such as dropping SP every 5 seconds
  11822. * @param tid: Timer ID
  11823. * @param tick: How long before next call
  11824. * @param id: ID of character
  11825. * @param data: Information passed through the timer call
  11826. * @return 1: Success 0: Fail
  11827. */
  11828. TIMER_FUNC(status_change_timer){
  11829. enum sc_type type = (sc_type)data;
  11830. struct block_list *bl;
  11831. struct map_session_data *sd;
  11832. int interval = status_get_sc_interval(type);
  11833. bool dounlock = false;
  11834. bl = map_id2bl(id);
  11835. if(!bl) {
  11836. ShowDebug("status_change_timer: Null pointer id: %d data: %" PRIdPTR "\n", id, data);
  11837. return 0;
  11838. }
  11839. struct status_change * const sc = status_get_sc(bl);
  11840. struct status_data * const status = status_get_status_data(bl);
  11841. if(!sc) {
  11842. ShowDebug("status_change_timer: Null pointer id: %d data: %" PRIdPTR " bl-type: %d\n", id, data, bl->type);
  11843. return 0;
  11844. }
  11845. struct status_change_entry * const sce = sc->data[type];
  11846. if(!sce) {
  11847. ShowDebug("status_change_timer: Null pointer id: %d data: %" PRIdPTR " bl-type: %d\n", id, data, bl->type);
  11848. return 0;
  11849. }
  11850. if( sce->timer != tid ) {
  11851. ShowError("status_change_timer: Mismatch for type %d: %d != %d (bl id %d)\n",type,tid,sce->timer, bl->id);
  11852. return 0;
  11853. }
  11854. sd = BL_CAST(BL_PC, bl);
  11855. std::function<void (t_tick)> sc_timer_next = [&sce, &bl, &data](t_tick t) {
  11856. sce->timer = add_timer(t, status_change_timer, bl->id, data);
  11857. };
  11858. switch(type) {
  11859. case SC_MAXIMIZEPOWER:
  11860. case SC_CLOAKING:
  11861. if(!status_charge(bl, 0, 1))
  11862. break; // Not enough SP to continue.
  11863. sc_timer_next(sce->val2+tick);
  11864. return 0;
  11865. case SC_CHASEWALK:
  11866. if(!status_charge(bl, 0, sce->val4))
  11867. break; // Not enough SP to continue.
  11868. if (!sc->data[SC_CHASEWALK2]) {
  11869. sc_start(bl,bl, SC_CHASEWALK2,100,1<<(sce->val1-1),
  11870. (t_tick)(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_ROGUE?10:1) // SL bonus -> x10 duration
  11871. *skill_get_time2(status_db.getSkill(type),sce->val1));
  11872. }
  11873. sc_timer_next(sce->val2+tick);
  11874. return 0;
  11875. break;
  11876. case SC_HIDING:
  11877. if(--(sce->val2)>0) {
  11878. if(sce->val2 % sce->val4 == 0 && !status_charge(bl, 0, 1))
  11879. break; // Fail if it's time to substract SP and there isn't.
  11880. sc_timer_next(1000+tick);
  11881. return 0;
  11882. }
  11883. break;
  11884. case SC_SIGHT:
  11885. case SC_RUWACH:
  11886. case SC_SIGHTBLASTER:
  11887. if(type == SC_SIGHTBLASTER) {
  11888. //Restore trap immunity
  11889. if(sce->val4%2)
  11890. sce->val4--;
  11891. map_foreachinallrange( status_change_timer_sub, bl, sce->val3, BL_CHAR|BL_SKILL, bl, sce, type, tick);
  11892. } else {
  11893. map_foreachinallrange( status_change_timer_sub, bl, sce->val3, BL_CHAR, bl, sce, type, tick);
  11894. skill_reveal_trap_inarea(bl, sce->val3, bl->x, bl->y);
  11895. }
  11896. if( --(sce->val2)>0 ) {
  11897. sce->val4 += 20; // Use for Shadow Form 2 seconds checking.
  11898. sc_timer_next(20+tick);
  11899. return 0;
  11900. }
  11901. break;
  11902. case SC_PROVOKE:
  11903. if(sce->val4) { // Auto-provoke (it is ended in status_heal)
  11904. sc_timer_next(1000*60+tick);
  11905. return 0;
  11906. }
  11907. break;
  11908. case SC_STONE:
  11909. if (sce->val4 >= 0 && status->hp > status->max_hp / 4)
  11910. status_percent_damage(nullptr, bl, -1, 0, false);
  11911. break;
  11912. case SC_POISON:
  11913. case SC_DPOISON:
  11914. if (sce->val4 >= 0 && !sc->data[SC_SLOWPOISON]) {
  11915. unsigned int damage = 0;
  11916. if (sd)
  11917. damage = (type == SC_DPOISON) ? 2 + status->max_hp / 50 : 2 + status->max_hp * 3 / 200;
  11918. else
  11919. damage = (type == SC_DPOISON) ? 2 + status->max_hp / 100 : 2 + status->max_hp / 200;
  11920. if (status->hp > umax(status->max_hp / 4, damage)) // Stop damaging after 25% HP left.
  11921. status_zap(bl, damage, 0);
  11922. }
  11923. break;
  11924. case SC_BLEEDING:
  11925. if (sce->val4 >= 0) {
  11926. int64 damage = rnd() % 600 + 200;
  11927. if (!sd && damage >= status->hp)
  11928. damage = status->hp - 1; // No deadly damage for monsters
  11929. map_freeblock_lock();
  11930. dounlock = true;
  11931. status_zap(bl, damage, 0);
  11932. }
  11933. break;
  11934. case SC_BURNING:
  11935. if (sce->val4 >= 0) {
  11936. int64 damage = 1000 + (3 * status->max_hp) / 100; // Deals fixed (1000 + 3%*MaxHP)
  11937. map_freeblock_lock();
  11938. dounlock = true;
  11939. status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, 0, 1, damage, 1, DMG_NORMAL, 0, false),0);
  11940. }
  11941. break;
  11942. case SC_TOXIN:
  11943. if (sce->val4 >= 0) { // Damage is every 10 seconds including 3%sp drain.
  11944. if (sce->val3 == 1) { // Target
  11945. map_freeblock_lock();
  11946. dounlock = true;
  11947. 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);
  11948. } else { // Caster
  11949. interval = 1000; // Assign here since status_get_sc_internval() contains the target interval.
  11950. if (status->sp < status->max_sp)
  11951. status_heal(bl, 0, (int)status->max_sp * 1 / 100, 1);
  11952. }
  11953. }
  11954. break;
  11955. case SC_MAGICMUSHROOM:
  11956. if (sce->val4 >= 0) {
  11957. bool flag = 0;
  11958. int64 damage = status->max_hp * 3 / 100;
  11959. if (status->hp <= damage)
  11960. damage = status->hp - 1; // Cannot Kill
  11961. if (damage > 0) { // 3% Damage each 4 seconds
  11962. map_freeblock_lock();
  11963. status_zap(bl, damage, 0);
  11964. flag = !sc->data[type]; // Killed? Should not
  11965. map_freeblock_unlock();
  11966. }
  11967. if (!flag) { // Random Skill Cast
  11968. if (magic_mushroom_db.size() > 0 && sd && !pc_issit(sd)) { // Can't cast if sit
  11969. auto mushroom_spell = magic_mushroom_db.begin();
  11970. std::advance(mushroom_spell, rnd() % magic_mushroom_db.size());
  11971. uint16 mushroom_skill_id = mushroom_spell->second->skill_id;
  11972. if (!skill_get_index(mushroom_skill_id))
  11973. break;
  11974. unit_stop_attack(bl);
  11975. unit_skillcastcancel(bl, 1);
  11976. switch (skill_get_casttype(mushroom_skill_id)) { // Magic Mushroom skills are buffs or area damage
  11977. case CAST_GROUND:
  11978. skill_castend_pos2(bl, bl->x, bl->y, mushroom_skill_id, 1, tick, 0);
  11979. break;
  11980. case CAST_NODAMAGE:
  11981. skill_castend_nodamage_id(bl, bl, mushroom_skill_id, 1, tick, 0);
  11982. break;
  11983. case CAST_DAMAGE:
  11984. skill_castend_damage_id(bl, bl, mushroom_skill_id, 1, tick, 0);
  11985. break;
  11986. }
  11987. }
  11988. clif_emotion(bl, ET_SMILE);
  11989. }
  11990. }
  11991. break;
  11992. case SC_PYREXIA:
  11993. if (sce->val4 >= 0) {
  11994. map_freeblock_lock();
  11995. dounlock = true;
  11996. status_fix_damage(bl, bl, 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 100, 1, DMG_NORMAL, 0, false),0);
  11997. }
  11998. break;
  11999. case SC_LEECHESEND:
  12000. if (sce->val4 >= 0) {
  12001. int64 damage = status->vit * (sce->val1 - 3) + (int)status->max_hp / 100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100)
  12002. map_freeblock_lock();
  12003. dounlock = true;
  12004. status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, damage, 1, DMG_NORMAL, 0, false),0);
  12005. unit_skillcastcancel(bl, 2);
  12006. }
  12007. break;
  12008. case SC_DEATHHURT:
  12009. if (sce->val4 >= 0) {
  12010. if (status->hp < status->max_hp)
  12011. status_heal(bl, (int)status->max_hp * 1 / 100, 0, 1);
  12012. }
  12013. break;
  12014. case SC_TENSIONRELAX:
  12015. if(status->max_hp > status->hp && --(sce->val3) >= 0) {
  12016. sc_timer_next(10000 + tick);
  12017. return 0;
  12018. }
  12019. break;
  12020. case SC_KNOWLEDGE:
  12021. if (!sd) break;
  12022. if(bl->m == sd->feel_map[0].m ||
  12023. bl->m == sd->feel_map[1].m ||
  12024. bl->m == sd->feel_map[2].m)
  12025. { // Timeout will be handled by pc_setpos
  12026. sce->timer = INVALID_TIMER;
  12027. return 0;
  12028. }
  12029. break;
  12030. case SC_S_LIFEPOTION:
  12031. case SC_L_LIFEPOTION:
  12032. if( --(sce->val4) >= 0 ) {
  12033. // val1 < 0 = per max% | val1 > 0 = exact amount
  12034. int hp = 0;
  12035. if( status->hp < status->max_hp )
  12036. hp = (sce->val1 < 0) ? (int)(status->max_hp * -1 * sce->val1 / 100.) : sce->val1;
  12037. status_heal(bl, hp, 0, 2);
  12038. sc_timer_next((sce->val2 * 1000) + tick);
  12039. return 0;
  12040. }
  12041. break;
  12042. case SC_BOSSMAPINFO:
  12043. if( sd && --(sce->val4) >= 0 ) {
  12044. struct mob_data *boss_md = map_id2boss(sce->val1);
  12045. if (boss_md) {
  12046. if (sd->bl.m != boss_md->bl.m) // Not on same map anymore
  12047. return 0;
  12048. else if (boss_md->bl.prev != NULL) { // Boss is alive - Update X, Y on minimap
  12049. sce->val2 = 0;
  12050. clif_bossmapinfo(sd, boss_md, BOSS_INFO_ALIVE);
  12051. } else if (boss_md->spawn_timer != INVALID_TIMER && !sce->val2) { // Boss is dead
  12052. sce->val2 = 1;
  12053. clif_bossmapinfo(sd, boss_md, BOSS_INFO_DEAD);
  12054. }
  12055. }
  12056. sc_timer_next(1000 + tick);
  12057. return 0;
  12058. }
  12059. break;
  12060. case SC_DANCING: // SP consumption by time of dancing skills
  12061. {
  12062. int s = 0;
  12063. int sp = 1;
  12064. if (--sce->val3 <= 0)
  12065. break;
  12066. switch(sce->val1&0xFFFF) {
  12067. #ifndef RENEWAL
  12068. case BD_RICHMANKIM:
  12069. case BD_DRUMBATTLEFIELD:
  12070. case BD_RINGNIBELUNGEN:
  12071. case BD_SIEGFRIED:
  12072. case BA_DISSONANCE:
  12073. case BA_ASSASSINCROSS:
  12074. case DC_UGLYDANCE:
  12075. s=3;
  12076. break;
  12077. case BD_LULLABY:
  12078. case BD_ETERNALCHAOS:
  12079. case BD_ROKISWEIL:
  12080. case DC_FORTUNEKISS:
  12081. s=4;
  12082. break;
  12083. case CG_HERMODE:
  12084. case BD_INTOABYSS:
  12085. case BA_WHISTLE:
  12086. case DC_HUMMING:
  12087. case BA_POEMBRAGI:
  12088. case DC_SERVICEFORYOU:
  12089. s=5;
  12090. break;
  12091. case BA_APPLEIDUN:
  12092. s=6;
  12093. break;
  12094. #endif
  12095. case CG_MOONLIT:
  12096. // Moonlit's cost is 4sp*skill_lv [Skotlex]
  12097. sp= 4*(sce->val1>>16);
  12098. // Upkeep is also every 10 secs.
  12099. #ifndef RENEWAL
  12100. case DC_DONTFORGETME:
  12101. #endif
  12102. s=10;
  12103. break;
  12104. }
  12105. if( s != 0 && sce->val3 % s == 0 ) {
  12106. #ifndef RENEWAL
  12107. if (sc->data[SC_LONGING])
  12108. sp*= 3;
  12109. #endif
  12110. if (!status_charge(bl, 0, sp))
  12111. break;
  12112. }
  12113. sc_timer_next(1000+tick);
  12114. return 0;
  12115. }
  12116. break;
  12117. case SC_BERSERK:
  12118. // 5% every 10 seconds [DracoRPG]
  12119. if( --( sce->val3 ) > 0 && status_charge(bl, sce->val2, 0) && status->hp > 100 ) {
  12120. sc_timer_next(sce->val4+tick);
  12121. return 0;
  12122. }
  12123. break;
  12124. case SC_NOCHAT:
  12125. if(sd) {
  12126. sd->status.manner++;
  12127. clif_changestatus(sd,SP_MANNER,sd->status.manner);
  12128. clif_updatestatus(sd,SP_MANNER);
  12129. if (sd->status.manner < 0) { // Every 60 seconds your manner goes up by 1 until it gets back to 0.
  12130. sc_timer_next(60000+tick);
  12131. return 0;
  12132. }
  12133. }
  12134. break;
  12135. case SC_SPLASHER:
  12136. // Custom Venom Splasher countdown timer
  12137. // if (sce->val4 % 1000 == 0) {
  12138. // char timer[10];
  12139. // snprintf (timer, 10, "%d", sce->val4/1000);
  12140. // clif_message(bl, timer);
  12141. // }
  12142. if((sce->val4 -= 500) > 0) {
  12143. sc_timer_next(500 + tick);
  12144. return 0;
  12145. }
  12146. break;
  12147. case SC_MARIONETTE:
  12148. case SC_MARIONETTE2:
  12149. {
  12150. struct block_list *pbl = map_id2bl(sce->val1);
  12151. if( pbl && check_distance_bl(bl, pbl, 7) ) {
  12152. sc_timer_next(1000 + tick);
  12153. return 0;
  12154. }
  12155. }
  12156. break;
  12157. case SC_GOSPEL:
  12158. if(sce->val4 == BCT_SELF && --(sce->val2) > 0) {
  12159. int hp, sp;
  12160. hp = (sce->val1 > 5) ? 45 : 30;
  12161. sp = (sce->val1 > 5) ? 35 : 20;
  12162. if(!status_charge(bl, hp, sp))
  12163. break;
  12164. sc_timer_next(10000+tick);
  12165. return 0;
  12166. }
  12167. break;
  12168. case SC_JAILED:
  12169. if(sce->val1 == INT_MAX || --(sce->val1) > 0) {
  12170. sc_timer_next(60000+tick);
  12171. return 0;
  12172. }
  12173. break;
  12174. case SC_BLIND:
  12175. if(sc->data[SC_FOGWALL]) { // Blind lasts forever while you are standing on the fog.
  12176. sc_timer_next(5000+tick);
  12177. return 0;
  12178. }
  12179. break;
  12180. case SC_ABUNDANCE:
  12181. if(--(sce->val4) > 0) {
  12182. status_heal(bl,0,60,0);
  12183. sc_timer_next(10000+tick);
  12184. }
  12185. break;
  12186. case SC_OBLIVIONCURSE:
  12187. if( --(sce->val4) >= 0 ) {
  12188. clif_emotion(bl,ET_QUESTION);
  12189. sc_timer_next(3000 + tick);
  12190. return 0;
  12191. }
  12192. break;
  12193. case SC_WEAPONBLOCKING:
  12194. if( --(sce->val4) >= 0 ) {
  12195. if( !status_charge(bl,0,3) )
  12196. break;
  12197. sc_timer_next(5000+tick);
  12198. return 0;
  12199. }
  12200. break;
  12201. case SC_CLOAKINGEXCEED:
  12202. if(!status_charge(bl,0,10-sce->val1))
  12203. break;
  12204. sc_timer_next(1000 + tick);
  12205. return 0;
  12206. case SC_RENOVATIO:
  12207. if( --(sce->val4) >= 0 ) {
  12208. int heal = status->max_hp * (sce->val1 + 4) / 100;
  12209. if( sc && sc->data[SC_AKAITSUKI] && heal )
  12210. heal = ~heal + 1;
  12211. status_heal(bl, heal, 0, 3);
  12212. sc_timer_next(5000 + tick);
  12213. return 0;
  12214. }
  12215. break;
  12216. case SC_SPHERE_1:
  12217. case SC_SPHERE_2:
  12218. case SC_SPHERE_3:
  12219. case SC_SPHERE_4:
  12220. case SC_SPHERE_5:
  12221. if( --(sce->val4) >= 0 ) {
  12222. if( !status_charge(bl, 0, 1) )
  12223. break;
  12224. sc_timer_next(1000 + tick);
  12225. return 0;
  12226. }
  12227. break;
  12228. case SC_FREEZE_SP:
  12229. if( !status_charge(bl, 0, sce->val2) ) {
  12230. int i;
  12231. for(i = SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) // Also remove stored spell as well.
  12232. status_change_end(bl, (sc_type)i, INVALID_TIMER);
  12233. break;
  12234. }
  12235. sc_timer_next(10000 + tick);
  12236. return 0;
  12237. case SC_ELECTRICSHOCKER:
  12238. if( --(sce->val4) >= 0 ) {
  12239. status_charge(bl, 0, 5 * sce->val1 * status->max_sp / 100);
  12240. sc_timer_next(1000 + tick);
  12241. return 0;
  12242. }
  12243. break;
  12244. case SC_CAMOUFLAGE:
  12245. if (!status_charge(bl, 0, 7 - sce->val1))
  12246. break;
  12247. if (--sce->val4 >= 0)
  12248. sce->val3++;
  12249. sc_timer_next(1000 + tick);
  12250. return 0;
  12251. case SC__REPRODUCE:
  12252. if(!status_charge(bl, 0, 1))
  12253. break;
  12254. sc_timer_next(1000+tick);
  12255. return 0;
  12256. case SC__SHADOWFORM:
  12257. if( --(sce->val4) >= 0 ) {
  12258. if( !status_charge(bl, 0, 11 - sce->val1) )
  12259. break;
  12260. sc_timer_next(1000 + tick);
  12261. return 0;
  12262. }
  12263. break;
  12264. case SC__INVISIBILITY:
  12265. if( !status_charge(bl, 0, (12 - 2 * sce->val1) * status->max_sp / 100) ) // 6% - skill_lv.
  12266. break;
  12267. sc_timer_next(1000 + tick);
  12268. return 0;
  12269. case SC_STRIKING:
  12270. if( --(sce->val4) >= 0 ) {
  12271. if( !status_charge(bl,0, sce->val3 ) )
  12272. break;
  12273. sc_timer_next(1000 + tick);
  12274. return 0;
  12275. }
  12276. break;
  12277. case SC_WARMER: {
  12278. int hp = 0;
  12279. struct status_change *ssc = status_get_sc(map_id2bl(sce->val2));
  12280. if (ssc && ssc->data[SC_HEATER_OPTION])
  12281. hp = status->max_hp * 3 * sce->val1 / 100;
  12282. else
  12283. hp = status->max_hp * sce->val1 / 100;
  12284. if (sc && sc->data[SC_AKAITSUKI] && hp)
  12285. hp = ~hp + 1;
  12286. if (status->hp != status->max_hp)
  12287. status_heal(bl, hp, 0, 0);
  12288. sc_timer_next(3000 + tick);
  12289. return 0;
  12290. }
  12291. case SC_HELLS_PLANT:
  12292. if( sce->val4 >= 0 ){
  12293. skill_castend_damage_id( bl, bl, GN_HELLS_PLANT_ATK, sce->val1, tick, 0 );
  12294. }
  12295. break;
  12296. case SC_VOICEOFSIREN:
  12297. if( --(sce->val4) >= 0 ) {
  12298. clif_emotion(bl,ET_THROB);
  12299. sc_timer_next(2000 + tick);
  12300. return 0;
  12301. }
  12302. break;
  12303. case SC_DEEPSLEEP:
  12304. if( --(sce->val4) >= 0 ) { // Recovers 3% HP/SP every 2 seconds.
  12305. status_heal(bl, status->max_hp * 3 / 100, status->max_sp * 3 / 100, 2);
  12306. sc_timer_next(2000 + tick);
  12307. return 0;
  12308. }
  12309. break;
  12310. case SC_SATURDAYNIGHTFEVER:
  12311. // 1% HP/SP drain every val4 seconds [Jobbie]
  12312. if( --(sce->val3) >= 0 ) {
  12313. if( !status_charge(bl, status->hp / 100, status->sp / 100) )
  12314. break;
  12315. sc_timer_next(sce->val4+tick);
  12316. return 0;
  12317. }
  12318. break;
  12319. case SC_CRYSTALIZE:
  12320. if( --(sce->val4) >= 0 ) { // Drains 2% of HP and 1% of SP every seconds.
  12321. if (!status_charge(bl, status->max_hp * 2 / 100, status->max_sp / 100))
  12322. break;
  12323. sc_timer_next(1000 + tick);
  12324. return 0;
  12325. }
  12326. break;
  12327. case SC_FORCEOFVANGUARD:
  12328. if( !status_charge(bl,0,24 - 4 * sce->val1) )
  12329. break;
  12330. sc_timer_next(10000 + tick);
  12331. return 0;
  12332. case SC_BANDING:
  12333. if( status_charge(bl, 0, 7 - sce->val1) ) {
  12334. sce->val2 = (sd ? skill_banding_count(sd) : 1);
  12335. sc_timer_next(5000 + tick);
  12336. return 0;
  12337. }
  12338. break;
  12339. case SC_REFLECTDAMAGE:
  12340. if( --(sce->val4) > 0 ) {
  12341. if( !status_charge(bl,0,10) )
  12342. break;
  12343. sc_timer_next(1000 + tick);
  12344. return 0;
  12345. }
  12346. break;
  12347. case SC_OVERHEAT_LIMITPOINT:
  12348. if (--(sce->val1) >= 0) { // Cooling
  12349. static std::vector<int16> limit = { 150, 200, 280, 360, 450 };
  12350. uint16 skill_lv = (sd ? cap_value(pc_checkskill(sd, NC_MAINFRAME), 0, (uint16)(limit.size()-1)) : 0);
  12351. if (sc && sc->data[SC_OVERHEAT])
  12352. status_change_end(bl,SC_OVERHEAT,INVALID_TIMER);
  12353. if (sce->val1 > limit[skill_lv])
  12354. sc_start(bl, bl, SC_OVERHEAT, 100, sce->val1, 1000);
  12355. sc_timer_next(1000 + tick);
  12356. return 0;
  12357. }
  12358. break;
  12359. case SC_OVERHEAT: {
  12360. uint32 damage = status->max_hp / 100; // Suggestion 1% each second
  12361. if (damage >= status->hp)
  12362. damage = status->hp - 1; // Do not kill, just keep you with 1 hp minimum
  12363. map_freeblock_lock();
  12364. status_fix_damage(NULL, bl, damage, clif_damage(bl, bl, tick, 0, 0, damage, 0, DMG_NORMAL, 0, false),0);
  12365. if (sc->data[type]) {
  12366. sc_timer_next(1000 + tick);
  12367. }
  12368. map_freeblock_unlock();
  12369. return 0;
  12370. }
  12371. break;
  12372. case SC_MAGNETICFIELD:
  12373. if (--(sce->val4) >= 0) {
  12374. struct block_list *src = map_id2bl(sce->val2);
  12375. if (!src || (src && (status_isdead(src) || src->m != bl->m)))
  12376. break;
  12377. map_freeblock_lock();
  12378. if (!status_charge(bl, 0, 50))
  12379. status_zap(bl, 0, status->sp);
  12380. if (sc->data[type])
  12381. sc_timer_next(1000 + tick);
  12382. map_freeblock_unlock();
  12383. return 0;
  12384. }
  12385. break;
  12386. case SC_INSPIRATION:
  12387. if(--(sce->val4) >= 0) {
  12388. if (!status_charge(bl, status->max_hp * (35 - 5 * sce->val1) / 1000, status->max_sp * (45 - 5 * sce->val1) / 1000))
  12389. break;
  12390. sc_timer_next(5000+tick);
  12391. return 0;
  12392. }
  12393. break;
  12394. case SC_SHIELDSPELL_HP:
  12395. if( sce->val4 >= 0 && status->hp < status->max_hp ){
  12396. status_heal( bl, status->max_hp * sce->val2 / 100, 0, 1 );
  12397. }
  12398. break;
  12399. case SC_SHIELDSPELL_SP:
  12400. if( sce->val4 >= 0 && status->sp < status->max_sp ){
  12401. status_heal( bl, 0, status->max_sp * sce->val2 / 100, 1 );
  12402. }
  12403. break;
  12404. case SC_TROPIC:
  12405. case SC_CHILLY_AIR:
  12406. case SC_WILD_STORM:
  12407. case SC_UPHEAVAL:
  12408. case SC_HEATER:
  12409. case SC_COOLER:
  12410. case SC_BLAST:
  12411. case SC_CURSED_SOIL:
  12412. case SC_PYROTECHNIC:
  12413. case SC_AQUAPLAY:
  12414. case SC_GUST:
  12415. case SC_PETROLOGY:
  12416. case SC_CIRCLE_OF_FIRE:
  12417. case SC_FIRE_CLOAK:
  12418. case SC_WATER_DROP:
  12419. case SC_WATER_SCREEN:
  12420. case SC_WIND_CURTAIN:
  12421. case SC_WIND_STEP:
  12422. case SC_STONE_SHIELD:
  12423. case SC_SOLID_SKIN:
  12424. case SC_FLAMETECHNIC:
  12425. case SC_FLAMEARMOR:
  12426. case SC_COLD_FORCE:
  12427. case SC_CRYSTAL_ARMOR:
  12428. case SC_GRACE_BREEZE:
  12429. case SC_EYES_OF_STORM:
  12430. case SC_EARTH_CARE:
  12431. case SC_STRONG_PROTECTION:
  12432. case SC_DEEP_POISONING:
  12433. case SC_POISON_SHIELD:
  12434. if( !status_charge(bl,0,sce->val2) ) {
  12435. struct block_list *s_bl = battle_get_master(bl);
  12436. if (bl->type == BL_ELEM)
  12437. elemental_change_mode(BL_CAST(BL_ELEM, bl), EL_MODE_PASSIVE);
  12438. if( s_bl )
  12439. status_change_end(s_bl,static_cast<sc_type>(type+1),INVALID_TIMER);
  12440. status_change_end(bl,type,INVALID_TIMER);
  12441. break;
  12442. }
  12443. sc_timer_next(sce->val3 + tick);
  12444. return 0;
  12445. case SC_WATER_SCREEN_OPTION:
  12446. status_heal(bl,1000,0,2);
  12447. sc_timer_next(10000 + tick);
  12448. return 0;
  12449. case SC_TEARGAS:
  12450. if( --(sce->val4) >= 0 ) {
  12451. struct block_list *src = map_id2bl(sce->val3);
  12452. int damage = sce->val2;
  12453. map_freeblock_lock();
  12454. clif_damage(bl, bl, tick, 0, 0, damage, 1, DMG_MULTI_HIT_ENDURE, 0, false);
  12455. status_damage(src, bl, damage,0, 0, 1, 0);
  12456. if( sc->data[type] ) {
  12457. sc_timer_next(2000 + tick);
  12458. }
  12459. map_freeblock_unlock();
  12460. return 0;
  12461. }
  12462. break;
  12463. case SC_TEARGAS_SOB:
  12464. if( --(sce->val4) >= 0 ) {
  12465. clif_emotion(bl, ET_CRY);
  12466. sc_timer_next(3000 + tick);
  12467. return 0;
  12468. }
  12469. break;
  12470. case SC_STOMACHACHE:
  12471. if( --(sce->val4) >= 0 ) {
  12472. status_charge(bl,0,sce->val2); // Reduce 8 every 10 seconds.
  12473. if( sd && !pc_issit(sd) ) { // Force to sit every 10 seconds.
  12474. pc_setsit(sd);
  12475. skill_sit(sd, true);
  12476. clif_sitting(bl);
  12477. }
  12478. sc_timer_next(10000 + tick);
  12479. return 0;
  12480. }
  12481. break;
  12482. case SC_LEADERSHIP:
  12483. case SC_GLORYWOUNDS:
  12484. case SC_SOULCOLD:
  12485. case SC_HAWKEYES:
  12486. // They only end by status_change_end
  12487. sc_timer_next(600000 + tick);
  12488. return 0;
  12489. case SC_MEIKYOUSISUI:
  12490. if( --(sce->val4) >= 0 ) {
  12491. status_heal(bl, status->max_hp * sce->val2 / 100, status->max_sp * sce->val3 / 100, 0);
  12492. sc_timer_next(1000 + tick);
  12493. return 0;
  12494. }
  12495. break;
  12496. case SC_KAGEMUSYA:
  12497. if( --(sce->val4) >= 0 ) {
  12498. if(!status_charge(bl, 0, 1)) break;
  12499. sc_timer_next(1000+tick);
  12500. return 0;
  12501. }
  12502. break;
  12503. case SC_ANGRIFFS_MODUS:
  12504. if(--(sce->val4) >= 0) { // Drain hp/sp
  12505. if( !status_charge(bl,100,20) ) break;
  12506. sc_timer_next(1000+tick);
  12507. return 0;
  12508. }
  12509. break;
  12510. case SC_CBC:
  12511. if(--(sce->val4) >= 0) { // Drain hp/sp
  12512. int hp=0;
  12513. int sp = (status->max_sp * sce->val3) / 100;
  12514. if(bl->type == BL_MOB) hp = sp*10;
  12515. if( !status_charge(bl,hp,sp) )break;
  12516. sc_timer_next(1000+tick);
  12517. return 0;
  12518. }
  12519. break;
  12520. case SC_FULL_THROTTLE:
  12521. if( --(sce->val4) >= 0 ) {
  12522. status_percent_damage(bl, bl, 0, sce->val2, false);
  12523. sc_timer_next(1000 + tick);
  12524. return 0;
  12525. }
  12526. break;
  12527. case SC_REBOUND:
  12528. if( --(sce->val4) >= 0 ) {
  12529. clif_emotion(bl, ET_SWEAT);
  12530. sc_timer_next(2000 + tick);
  12531. return 0;
  12532. }
  12533. break;
  12534. case SC_KINGS_GRACE:
  12535. if( --(sce->val4) >= 0 ) {
  12536. status_percent_heal(bl, sce->val2, 0);
  12537. sc_timer_next(1000 + tick);
  12538. return 0;
  12539. }
  12540. break;
  12541. case SC_FRIGG_SONG:
  12542. if( --(sce->val4) >= 0 ) {
  12543. status_heal(bl, sce->val3, 0, 0);
  12544. sc_timer_next(1000 + tick);
  12545. return 0;
  12546. }
  12547. break;
  12548. case SC_C_MARKER:
  12549. if( --(sce->val4) >= 0 ) {
  12550. TBL_PC *caster = map_id2sd(sce->val2);
  12551. if (!caster || caster->bl.m != bl->m) //End the SC if caster isn't in same map
  12552. break;
  12553. sc_timer_next(1000 + tick);
  12554. clif_crimson_marker(caster, bl, false);
  12555. return 0;
  12556. }
  12557. break;
  12558. case SC_STEALTHFIELD_MASTER:
  12559. if (--(sce->val4) >= 0) {
  12560. if (!status_charge(bl, 0, status->max_sp * 3 / 100))
  12561. break;
  12562. sc_timer_next(sce->val3 + tick);
  12563. return 0;
  12564. }
  12565. break;
  12566. case SC_VACUUM_EXTREME:
  12567. if (sce->val4 > 0) {
  12568. // Only slide targets to center if they are standing still
  12569. if (unit_bl2ud(bl)->walktimer == INVALID_TIMER) {
  12570. uint16 x = sce->val3 >> 16, y = sce->val3 & 0xFFFF;
  12571. 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)) {
  12572. clif_slide(bl, x, y);
  12573. clif_fixpos(bl);
  12574. }
  12575. }
  12576. sc_timer_next(tick + sce->val4);
  12577. sce->val4 = 0;
  12578. }
  12579. break;
  12580. case SC_FIRE_INSIGNIA:
  12581. if (--(sce->val4) >= 0) {
  12582. if (status->def_ele == ELE_FIRE)
  12583. status_heal(bl, status->max_hp / 100, 0, 1);
  12584. else if (status->def_ele == ELE_EARTH)
  12585. status_zap(bl, status->max_hp / 100, 0);
  12586. sc_timer_next(5000 + tick);
  12587. return 0;
  12588. }
  12589. break;
  12590. case SC_WATER_INSIGNIA:
  12591. if (--(sce->val4) >= 0) {
  12592. if (status->def_ele == ELE_WATER)
  12593. status_heal(bl, status->max_hp / 100, 0, 1);
  12594. else if (status->def_ele == ELE_FIRE)
  12595. status_zap(bl, status->max_hp / 100, 0);
  12596. sc_timer_next(5000 + tick);
  12597. return 0;
  12598. }
  12599. break;
  12600. case SC_WIND_INSIGNIA:
  12601. if (--(sce->val4) >= 0) {
  12602. if (status->def_ele == ELE_WIND)
  12603. status_heal(bl, status->max_hp / 100, 0, 1);
  12604. else if (status->def_ele == ELE_WATER)
  12605. status_zap(bl, status->max_hp / 100, 0);
  12606. sc_timer_next(5000 + tick);
  12607. return 0;
  12608. }
  12609. break;
  12610. case SC_EARTH_INSIGNIA:
  12611. if (--(sce->val4) >= 0) {
  12612. if (status->def_ele == ELE_EARTH)
  12613. status_heal(bl, status->max_hp / 100, 0, 1);
  12614. else if (status->def_ele == ELE_WIND)
  12615. status_zap(bl, status->max_hp / 100, 0);
  12616. sc_timer_next(5000 + tick);
  12617. return 0;
  12618. }
  12619. break;
  12620. case SC_BITESCAR:
  12621. if (--(sce->val4) >= 0) {
  12622. status_percent_damage(bl, bl, -(sce->val2), 0, 0);
  12623. sc_timer_next(1000 + tick);
  12624. return 0;
  12625. }
  12626. break;
  12627. case SC_FRESHSHRIMP:
  12628. if (--(sce->val4) >= 0) {
  12629. status_heal(bl, sce->val2, 0, 3);
  12630. sc_timer_next((10000 - ((sce->val1 - 1) * 1000)) + tick);
  12631. return 0;
  12632. }
  12633. break;
  12634. case SC_DORAM_BUF_01:
  12635. if( sd && --(sce->val4) >= 0 ) {
  12636. if( status->hp < status->max_hp )
  12637. status_heal(bl, 10, 0, 2);
  12638. sc_timer_next(10000 + tick);
  12639. return 0;
  12640. }
  12641. break;
  12642. case SC_DORAM_BUF_02:
  12643. if( sd && --(sce->val4) >= 0 ) {
  12644. if( status->sp < status->max_sp )
  12645. status_heal(bl, 0, 5, 2);
  12646. sc_timer_next(10000 + tick);
  12647. return 0;
  12648. }
  12649. break;
  12650. case SC_NEWMOON:
  12651. if (--(sce->val4) >= 0) {
  12652. if (!status_charge(bl, 0, 1))
  12653. break;
  12654. sc_timer_next(1000 + tick);
  12655. return 0;
  12656. }
  12657. break;
  12658. case SC_CREATINGSTAR:
  12659. if (--(sce->val4) >= 0) { // Needed to check who the caster is and what AoE is giving the status.
  12660. struct block_list *star_caster = map_id2bl(sce->val2);
  12661. struct skill_unit *star_aoe = (struct skill_unit *)map_id2bl(sce->val3);
  12662. if (star_caster == nullptr || status_isdead(star_caster) || star_caster->m != bl->m || star_aoe == nullptr)
  12663. break;
  12664. sc_timer_next(500 + tick);
  12665. // Attack after timer to prevent errors
  12666. skill_attack(BF_WEAPON, star_caster, &star_aoe->bl, bl, SJ_BOOKOFCREATINGSTAR, sce->val1, tick, 0);
  12667. return 0;
  12668. }
  12669. break;
  12670. case SC_SOULUNITY:
  12671. if (--(sce->val4) >= 0) { // Needed to check the caster's location for the range check.
  12672. struct block_list *unity_src = map_id2bl(sce->val2);
  12673. if (!unity_src || status_isdead(unity_src) || unity_src->m != bl->m || !check_distance_bl(bl, unity_src, 11))
  12674. break;
  12675. status_heal(bl, 150 * sce->val1, 0, 2);
  12676. sc_timer_next(3000 + tick);
  12677. return 0;
  12678. }
  12679. break;
  12680. case SC_SOULCOLLECT:
  12681. pc_addsoulball(sd, sce->val2);
  12682. if (sd->soulball < sce->val2) {
  12683. sc_timer_next(sce->val3 + tick);
  12684. return 0;
  12685. }
  12686. break;
  12687. case SC_HELPANGEL:
  12688. if (--(sce->val4) >= 0) {
  12689. status_heal(bl, 1000, 350, 2);
  12690. sc_timer_next(1000 + tick);
  12691. return 0;
  12692. }
  12693. break;
  12694. case SC_BURNT:
  12695. if( --(sce->val4) >= 0 ) {
  12696. int damage = 2000;
  12697. if( damage >= status->hp )
  12698. damage = status->hp - 1;
  12699. map_freeblock_lock();
  12700. status_zap(bl,damage,0);
  12701. if( sc->data[type] ) {
  12702. sc_timer_next(1000 + tick);
  12703. }
  12704. map_freeblock_unlock();
  12705. return 0;
  12706. }
  12707. break;
  12708. case SC_MEDIALE:
  12709. if (--(sce->val4) >= 0) {
  12710. clif_specialeffect(bl, 1808, AREA);
  12711. skill_castend_nodamage_id(bl, bl, CD_MEDIALE_VOTUM, sce->val1, tick, 1);
  12712. sc_timer_next(2000 + tick);
  12713. return 0;
  12714. }
  12715. break;
  12716. case SC_DANCING_KNIFE:
  12717. if (--(sce->val4) >= 0) {
  12718. skill_castend_nodamage_id(bl, bl, SHC_DANCING_KNIFE, sce->val1, tick, 1);
  12719. sc_timer_next(300 + tick);
  12720. return 0;
  12721. }
  12722. break;
  12723. case SC_A_MACHINE:
  12724. if (--(sce->val4) >= 0) {
  12725. skill_castend_nodamage_id(bl, bl, MT_A_MACHINE, sce->val1, tick, 1);
  12726. sc_timer_next(1000 + tick);
  12727. return 0;
  12728. }
  12729. break;
  12730. case SC_SERVANTWEAPON:
  12731. if (sce->val4 >= 0) {
  12732. if( sd && sd->servantball < MAX_SERVANTBALL ){
  12733. pc_addservantball( *sd, MAX_SERVANTBALL );
  12734. }
  12735. interval = max(500, skill_get_time2(DK_SERVANTWEAPON, sce->val1));
  12736. map_freeblock_lock();
  12737. dounlock = true;
  12738. }
  12739. break;
  12740. case SC_ABYSSFORCEWEAPON:
  12741. if (sce->val4 >= 0) {
  12742. if( sd && sd->abyssball < MAX_ABYSSBALL ){
  12743. pc_addabyssball( *sd );
  12744. }
  12745. interval = max(500, skill_get_time2(ABC_FROM_THE_ABYSS, sce->val1));
  12746. map_freeblock_lock();
  12747. dounlock = true;
  12748. }
  12749. break;
  12750. }
  12751. // If status has an interval and there is at least 100ms remaining time, wait for next interval
  12752. if(interval > 0 && sc->data[type] && sce->val4 >= 100) {
  12753. sc_timer_next(min(sce->val4,interval)+tick);
  12754. sce->val4 -= interval;
  12755. if (dounlock)
  12756. map_freeblock_unlock();
  12757. return 0;
  12758. }
  12759. if (dounlock)
  12760. map_freeblock_unlock();
  12761. // Default for all non-handled control paths is to end the status
  12762. return status_change_end( bl,type,tid );
  12763. }
  12764. /**
  12765. * For each iteration of repetitive status
  12766. * @param bl: Object [PC|MOB|HOM|MER|ELEM]
  12767. * @param ap: va_list arguments (src, sce, type, tick)
  12768. */
  12769. int status_change_timer_sub(struct block_list* bl, va_list ap)
  12770. {
  12771. struct status_change* tsc;
  12772. struct block_list* src = va_arg(ap,struct block_list*);
  12773. struct status_change_entry* sce = va_arg(ap,struct status_change_entry*);
  12774. enum sc_type type = (sc_type)va_arg(ap,int); // gcc: enum args get promoted to int
  12775. t_tick tick = va_arg(ap,t_tick);
  12776. if (status_isdead(bl))
  12777. return 0;
  12778. tsc = status_get_sc(bl);
  12779. switch( type ) {
  12780. case SC_SIGHT: // Reveal hidden ennemy on 3*3 range
  12781. case SC_CONCENTRATE:
  12782. status_change_end(bl, SC_HIDING, INVALID_TIMER);
  12783. status_change_end(bl, SC_CLOAKING, INVALID_TIMER);
  12784. status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
  12785. status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER);
  12786. status_change_end(bl, SC_NEWMOON, INVALID_TIMER);
  12787. if (tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 > 0 && sce->val4%2000 == 0) && // For every 2 seconds do the checking
  12788. rnd()%100 < 100 - tsc->data[SC__SHADOWFORM]->val1 * 10) // [100 - (Skill Level x 10)] %
  12789. status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
  12790. break;
  12791. case SC_RUWACH: // Reveal hidden target and deal little dammages if enemy
  12792. if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] ||
  12793. tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_NEWMOON] || tsc->data[SC_CLOAKINGEXCEED])) {
  12794. status_change_end(bl, SC_HIDING, INVALID_TIMER);
  12795. status_change_end(bl, SC_CLOAKING, INVALID_TIMER);
  12796. status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER);
  12797. status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
  12798. status_change_end(bl, SC_NEWMOON, INVALID_TIMER);
  12799. if(battle_check_target( src, bl, BCT_ENEMY ) > 0)
  12800. skill_attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0);
  12801. }
  12802. if (tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 > 0 && sce->val4%2000 == 0) && // For every 2 seconds do the checking
  12803. rnd()%100 < 100 - tsc->data[SC__SHADOWFORM]->val1 * 10 ) { // [100 - (Skill Level x 10)] %
  12804. status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
  12805. if (battle_check_target(src, bl, BCT_ENEMY) > 0)
  12806. skill_attack(BF_MAGIC, src, src, bl, status_db.getSkill(type), 1, tick, 0);
  12807. }
  12808. break;
  12809. case SC_SIGHTBLASTER:
  12810. if (battle_check_target( src, bl, BCT_ENEMY ) > 0 &&
  12811. status_check_skilluse(src, bl, WZ_SIGHTBLASTER, 2))
  12812. {
  12813. if (sce) {
  12814. struct skill_unit *su = NULL;
  12815. if(bl->type == BL_SKILL)
  12816. su = (struct skill_unit *)bl;
  12817. if (skill_attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,sce->val1,tick,0x1000000)
  12818. && (!su || !su->group || !skill_get_inf2(su->group->skill_id, INF2_ISTRAP))) { // The hit is not counted if it's against a trap
  12819. sce->val2 = 0; // This signals it to end.
  12820. } else if((bl->type&BL_SKILL) && sce->val4%2 == 0) {
  12821. //Remove trap immunity temporarily so it triggers if you still stand on it
  12822. sce->val4++;
  12823. }
  12824. }
  12825. }
  12826. break;
  12827. case SC_CLOSECONFINE:
  12828. // Lock char has released the hold on everyone...
  12829. if (tsc && tsc->data[SC_CLOSECONFINE2] && tsc->data[SC_CLOSECONFINE2]->val2 == src->id) {
  12830. tsc->data[SC_CLOSECONFINE2]->val2 = 0;
  12831. status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER);
  12832. }
  12833. break;
  12834. case SC_CURSEDCIRCLE_TARGET:
  12835. if( tsc && tsc->data[SC_CURSEDCIRCLE_TARGET] && tsc->data[SC_CURSEDCIRCLE_TARGET]->val2 == src->id ) {
  12836. clif_bladestop(bl, tsc->data[SC_CURSEDCIRCLE_TARGET]->val2, 0);
  12837. status_change_end(bl, type, INVALID_TIMER);
  12838. }
  12839. break;
  12840. }
  12841. return 0;
  12842. }
  12843. /**
  12844. * Clears buffs/debuffs on an object
  12845. * @param bl: Object to clear [PC|MOB|HOM|MER|ELEM]
  12846. * @param type: Type to remove
  12847. * SCCB_BUFFS: Clear Buffs
  12848. * SCCB_DEBUFFS: Clear Debuffs
  12849. * SCCB_REFRESH: Clear specific debuffs through RK_REFRESH
  12850. * SCCB_CHEM_PROTECT: Clear AM_CP_ARMOR/HELM/SHIELD/WEAPON
  12851. * SCCB_LUXANIMA: Bonus Script removed through RK_LUXANIMA
  12852. */
  12853. void status_change_clear_buffs(struct block_list* bl, uint8 type)
  12854. {
  12855. struct status_change *sc= status_get_sc(bl);
  12856. if (!sc || !sc->count)
  12857. return;
  12858. //Clears buffs with specified flag and type
  12859. for (const auto &it : status_db) {
  12860. sc_type status = static_cast<sc_type>(it.first);
  12861. std::bitset<SCF_MAX> flag = it.second->flag;
  12862. if (!sc->data[status] || flag[SCF_NOCLEARBUFF]) //Skip status with SCF_NOCLEARBUFF, no matter what
  12863. continue;
  12864. // &SCCB_LUXANIMA : Cleared by RK_LUXANIMA
  12865. if (!(type&SCCB_LUXANIMA) && flag[SCF_REMOVEONLUXANIMA])
  12866. continue;
  12867. // &SCCB_CHEM_PROTECT : Clears AM_CP_ARMOR/HELP/SHIELD/WEAPON
  12868. if (!(type&SCCB_CHEM_PROTECT) && flag[SCF_REMOVECHEMICALPROTECT])
  12869. continue;
  12870. // &SCCB_REFRESH : Cleared by RK_REFRESH
  12871. if (!(type&SCCB_REFRESH) && flag[SCF_REMOVEONREFRESH])
  12872. continue;
  12873. // &SCCB_DEBUFFS : Clears debuffs
  12874. if (!(type&SCCB_DEBUFFS) && flag[SCF_DEBUFF])
  12875. continue;
  12876. // &SCCB_BUFFS : Clears buffs
  12877. if (!(type&SCCB_BUFFS) && !(flag[SCF_DEBUFF]))
  12878. continue;
  12879. if (status == SC_SATURDAYNIGHTFEVER || status == SC_BERSERK) // Mark to not lose HP
  12880. sc->data[status]->val2 = 0;
  12881. status_change_end(bl, status, INVALID_TIMER);
  12882. }
  12883. //Removes bonus_script
  12884. if (bl->type == BL_PC) {
  12885. uint32 i = 0;
  12886. if (type&SCCB_BUFFS) i |= BSF_REM_BUFF;
  12887. if (type&SCCB_DEBUFFS) i |= BSF_REM_DEBUFF;
  12888. if (type&SCCB_REFRESH) i |= BSF_REM_ON_REFRESH;
  12889. if (type&SCCB_LUXANIMA) i |= BSF_REM_ON_LUXANIMA;
  12890. pc_bonus_script_clear(BL_CAST(BL_PC,bl),i);
  12891. }
  12892. // Cleaning all extras vars
  12893. sc->comet_x = 0;
  12894. sc->comet_y = 0;
  12895. #ifndef RENEWAL
  12896. sc->sg_counter = 0;
  12897. #endif
  12898. return;
  12899. }
  12900. /**
  12901. * Infect a user with status effects (SC_DEADLYINFECT)
  12902. * @param src: Object initiating change on bl [PC|MOB|HOM|MER|ELEM]
  12903. * @param bl: Object to change
  12904. * @return 1: Success 0: Fail
  12905. */
  12906. int status_change_spread(block_list *src, block_list *bl)
  12907. {
  12908. if (src == nullptr || bl == nullptr)
  12909. return 0;
  12910. // Status Immunity resistance
  12911. if (status_bl_has_mode(src, MD_STATUSIMMUNE) || status_bl_has_mode(bl, MD_STATUSIMMUNE))
  12912. return 0;
  12913. status_change *sc = status_get_sc(src);
  12914. if (sc == nullptr || sc->count == 0)
  12915. return 0;
  12916. bool hasSpread = false;
  12917. t_tick tick = gettick(), sc_tick;
  12918. for (const auto &it : status_db) {
  12919. sc_type type = static_cast<sc_type>(it.first);
  12920. const TimerData *timer;
  12921. if (sc->data[type] && it.second->flag[SCF_SPREADEFFECT]) {
  12922. if (sc->data[type]->timer != INVALID_TIMER) {
  12923. timer = get_timer(sc->data[type]->timer);
  12924. if (timer == nullptr || timer->func != status_change_timer || DIFF_TICK(timer->tick, tick) < 0)
  12925. continue;
  12926. int32 val4 = sc->data[type]->val4;
  12927. sc_tick = DIFF_TICK(timer->tick, tick) + (val4 > 0 ? val4 : 0);
  12928. } else
  12929. sc_tick = INFINITE_TICK;
  12930. status_change_start(src, bl, type, 10000, sc->data[type]->val1, sc->data[type]->val2, sc->data[type]->val3, sc->data[type]->val4, sc_tick, SCSTART_NOAVOID | SCSTART_NOTICKDEF | SCSTART_NORATEDEF);
  12931. if (!hasSpread)
  12932. hasSpread = true;
  12933. }
  12934. }
  12935. return hasSpread;
  12936. }
  12937. /**
  12938. * Applying natural heal bonuses (sit, skill, homun, etc...)
  12939. * TODO: the va_list doesn't seem to be used, safe to remove?
  12940. * @param bl: Object applying bonuses to [PC|HOM|MER|ELEM]
  12941. * @param args: va_list arguments
  12942. * @return which regeneration bonuses have been applied (flag)
  12943. */
  12944. static t_tick natural_heal_prev_tick,natural_heal_diff_tick;
  12945. static int status_natural_heal(struct block_list* bl, va_list args)
  12946. {
  12947. struct regen_data *regen;
  12948. struct status_data *status;
  12949. struct status_change *sc;
  12950. struct unit_data *ud;
  12951. struct view_data *vd = NULL;
  12952. struct regen_data_sub *sregen;
  12953. struct map_session_data *sd;
  12954. int rate, multi = 1, flag;
  12955. regen = status_get_regen_data(bl);
  12956. if (!regen)
  12957. return 0;
  12958. status = status_get_status_data(bl);
  12959. sc = status_get_sc(bl);
  12960. if (sc && !sc->count)
  12961. sc = NULL;
  12962. sd = BL_CAST(BL_PC,bl);
  12963. flag = regen->flag;
  12964. if (flag&RGN_HP && (regen->state.block&1))
  12965. flag &= ~(RGN_HP|RGN_SHP);
  12966. if (flag&RGN_SP && (regen->state.block&2))
  12967. flag &= ~(RGN_SP|RGN_SSP);
  12968. // Only skill-based regen is disabled at max HP/SP
  12969. if (flag&RGN_SHP && (status->hp >= status->max_hp))
  12970. flag &= ~RGN_SHP;
  12971. if (flag&RGN_SSP && (status->sp >= status->max_sp))
  12972. flag &= ~RGN_SSP;
  12973. if (flag && (
  12974. status_isdead(bl) ||
  12975. (sc && (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || sc->data[SC__INVISIBILITY]))
  12976. ))
  12977. flag = RGN_NONE;
  12978. if (sd) {
  12979. if (sd->hp_loss.value || sd->sp_loss.value)
  12980. pc_bleeding(sd, natural_heal_diff_tick);
  12981. if (sd->hp_regen.value || sd->sp_regen.value || sd->percent_hp_regen.value || sd->percent_sp_regen.value)
  12982. pc_regen(sd, natural_heal_diff_tick);
  12983. }
  12984. if(flag&(RGN_SHP|RGN_SSP) && regen->ssregen &&
  12985. (vd = status_get_viewdata(bl)) && vd->dead_sit == 2)
  12986. { // Apply sitting regen bonus.
  12987. sregen = regen->ssregen;
  12988. if(flag&(RGN_SHP)) { // Sitting HP regen
  12989. rate = (int)(natural_heal_diff_tick * (sregen->rate.hp / 100.));
  12990. if (regen->state.overweight)
  12991. rate >>= 1; // Half as fast when overweight.
  12992. sregen->tick.hp += rate;
  12993. while(sregen->tick.hp >= (unsigned int)battle_config.natural_heal_skill_interval) {
  12994. sregen->tick.hp -= battle_config.natural_heal_skill_interval;
  12995. if(status_heal(bl, sregen->hp, 0, 3) < sregen->hp) { // Full
  12996. flag &= ~RGN_SHP;
  12997. break;
  12998. }
  12999. }
  13000. }
  13001. if(flag&(RGN_SSP)) { // Sitting SP regen
  13002. rate = (int)(natural_heal_diff_tick * (sregen->rate.sp / 100.));
  13003. if (regen->state.overweight)
  13004. rate >>= 1; // Half as fast when overweight.
  13005. sregen->tick.sp += rate;
  13006. while(sregen->tick.sp >= (unsigned int)battle_config.natural_heal_skill_interval) {
  13007. sregen->tick.sp -= battle_config.natural_heal_skill_interval;
  13008. if(status_heal(bl, 0, sregen->sp, 3) < sregen->sp) { // Full
  13009. flag &= ~RGN_SSP;
  13010. break;
  13011. }
  13012. }
  13013. }
  13014. }
  13015. if (flag && regen->state.overweight)
  13016. flag = RGN_NONE;
  13017. ud = unit_bl2ud(bl);
  13018. if (flag&(RGN_HP|RGN_SHP|RGN_SSP) && ud && ud->walktimer != INVALID_TIMER) {
  13019. flag &= ~(RGN_SHP|RGN_SSP);
  13020. if(!regen->state.walk)
  13021. flag &= ~RGN_HP;
  13022. }
  13023. if (flag&(RGN_HP|RGN_SP)) {
  13024. if(!vd)
  13025. vd = status_get_viewdata(bl);
  13026. if(vd && vd->dead_sit == 2)
  13027. multi += 1; //This causes the interval to be halved
  13028. if(regen->state.gc)
  13029. multi += 1; //This causes the interval to be halved
  13030. }
  13031. // Natural Hp regen
  13032. if (flag&RGN_HP) {
  13033. // Interval to next recovery tick
  13034. rate = (int)(battle_config.natural_healhp_interval / (regen->rate.hp/100. * multi));
  13035. if (ud && ud->walktimer != INVALID_TIMER)
  13036. rate *= 2;
  13037. // Homun HP regen fix (they should regen as if they were sitting (twice as fast)
  13038. if(bl->type == BL_HOM)
  13039. rate /= 2;
  13040. // Our timer system isn't 100% accurate so make sure we use the closest interval
  13041. rate -= NATURAL_HEAL_INTERVAL / 2;
  13042. if(regen->tick.hp + rate <= natural_heal_prev_tick) {
  13043. regen->tick.hp = natural_heal_prev_tick;
  13044. if (status->hp >= status->max_hp)
  13045. flag &= ~(RGN_HP | RGN_SHP);
  13046. else if (status_heal(bl, regen->hp, 0, 1) < regen->hp)
  13047. flag &= ~RGN_SHP; // Full
  13048. }
  13049. }
  13050. else {
  13051. regen->tick.hp = natural_heal_prev_tick;
  13052. }
  13053. // Natural SP regen
  13054. if(flag&RGN_SP) {
  13055. // Interval to next recovery tick
  13056. rate = (int)(battle_config.natural_healsp_interval / (regen->rate.sp/100. * multi));
  13057. // Homun SP regen fix (they should regen as if they were sitting (twice as fast)
  13058. if(bl->type==BL_HOM)
  13059. rate /= 2;
  13060. #ifdef RENEWAL
  13061. if (sd && (sd->class_&MAPID_UPPERMASK) == MAPID_MONK &&
  13062. sc && sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SPIRIT] || sc->data[SC_SPIRIT]->val2 != SL_MONK))
  13063. rate *= 2; // Tick is doubled in Fury state
  13064. #endif
  13065. // Our timer system isn't 100% accurate so make sure we use the closest interval
  13066. rate -= NATURAL_HEAL_INTERVAL / 2;
  13067. if(regen->tick.sp + rate <= natural_heal_prev_tick) {
  13068. regen->tick.sp = natural_heal_prev_tick;
  13069. if (status->sp >= status->max_sp)
  13070. flag &= ~(RGN_SP | RGN_SSP);
  13071. else if (status_heal(bl, 0, regen->sp, 1) < regen->sp)
  13072. flag &= ~RGN_SSP; // Full
  13073. }
  13074. }
  13075. else {
  13076. regen->tick.sp = natural_heal_prev_tick;
  13077. }
  13078. if (!regen->sregen)
  13079. return flag;
  13080. // Skill regen
  13081. sregen = regen->sregen;
  13082. if(flag&RGN_SHP) { // Skill HP regen
  13083. sregen->tick.hp += (int)(natural_heal_diff_tick * (sregen->rate.hp / 100.));
  13084. while(sregen->tick.hp >= (unsigned int)battle_config.natural_heal_skill_interval) {
  13085. sregen->tick.hp -= battle_config.natural_heal_skill_interval;
  13086. if(status_heal(bl, sregen->hp, 0, 3) < sregen->hp)
  13087. break; // Full
  13088. }
  13089. }
  13090. if(flag&RGN_SSP) { // Skill SP regen
  13091. sregen->tick.sp += (int)(natural_heal_diff_tick * (sregen->rate.sp /100.));
  13092. while(sregen->tick.sp >= (unsigned int)battle_config.natural_heal_skill_interval) {
  13093. int val = sregen->sp;
  13094. if (sd && sd->state.doridori) {
  13095. val *= 2;
  13096. sd->state.doridori = 0;
  13097. if ((rate = pc_checkskill(sd,TK_SPTIME)))
  13098. sc_start(bl,bl,skill_get_sc(TK_SPTIME),
  13099. 100,rate,skill_get_time(TK_SPTIME, rate));
  13100. if (
  13101. (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR &&
  13102. rnd()%10000 < battle_config.sg_angel_skill_ratio
  13103. ) { // Angel of the Sun/Moon/Star
  13104. clif_feel_hate_reset(sd);
  13105. pc_resethate(sd);
  13106. pc_resetfeel(sd);
  13107. }
  13108. }
  13109. sregen->tick.sp -= battle_config.natural_heal_skill_interval;
  13110. if(status_heal(bl, 0, val, 3) < val)
  13111. break; // Full
  13112. }
  13113. }
  13114. return flag;
  13115. }
  13116. /**
  13117. * Natural heal main timer
  13118. * @param tid: Timer ID
  13119. * @param tick: Current tick (time)
  13120. * @param id: Object ID to heal
  13121. * @param data: data pushed through timer function
  13122. * @return 0
  13123. */
  13124. static TIMER_FUNC(status_natural_heal_timer){
  13125. natural_heal_diff_tick = DIFF_TICK(tick,natural_heal_prev_tick);
  13126. natural_heal_prev_tick = tick;
  13127. map_foreachregen(status_natural_heal);
  13128. return 0;
  13129. }
  13130. /**
  13131. * Clears the lastEffect value from a target
  13132. * @param tid: Timer ID
  13133. * @param tick: Current tick (time)
  13134. * @param id: Object ID
  13135. * @param data: data pushed through timer function
  13136. * @return 0
  13137. */
  13138. TIMER_FUNC(status_clear_lastEffect_timer) {
  13139. block_list *bl = map_id2bl(id);
  13140. if (bl != nullptr) {
  13141. status_change *sc = status_get_sc(bl);
  13142. if (sc != nullptr) {
  13143. sc->lastEffect = SC_NONE;
  13144. sc->lastEffectTimer = INVALID_TIMER;
  13145. }
  13146. }
  13147. return 0;
  13148. }
  13149. /**
  13150. * Check if status is disabled on a map
  13151. * @param type: Status Change data
  13152. * @param mapIsVS: If the map is a map_flag_vs type
  13153. * @param mapisPVP: If the map is a PvP type
  13154. * @param mapIsGVG: If the map is a map_flag_gvg type
  13155. * @param mapIsBG: If the map is a Battleground type
  13156. * @param mapZone: Map Zone type
  13157. * @param mapIsTE: If the map us WOE TE
  13158. * @return True - SC disabled on map; False - SC not disabled on map/Invalid SC
  13159. */
  13160. static bool status_change_isDisabledOnMap_(sc_type type, bool mapIsVS, bool mapIsPVP, bool mapIsGVG, bool mapIsBG, unsigned int mapZone, bool mapIsTE)
  13161. {
  13162. if (!status_db.validateStatus(type))
  13163. return false;
  13164. if ((!mapIsVS && SCDisabled[type]&1) ||
  13165. (mapIsPVP && SCDisabled[type]&2) ||
  13166. (mapIsGVG && SCDisabled[type]&4) ||
  13167. (mapIsBG && SCDisabled[type]&8) ||
  13168. (mapIsTE && SCDisabled[type]&16) ||
  13169. (SCDisabled[type]&(mapZone)))
  13170. {
  13171. return true;
  13172. }
  13173. return false;
  13174. }
  13175. /**
  13176. * Clear a status if it is disabled on a map
  13177. * @param bl: Block list data
  13178. * @param sc: Status Change data
  13179. */
  13180. void status_change_clear_onChangeMap(struct block_list *bl, struct status_change *sc)
  13181. {
  13182. nullpo_retv(bl);
  13183. if (sc && sc->count) {
  13184. struct map_data *mapdata = map_getmapdata(bl->m);
  13185. bool mapIsVS = mapdata_flag_vs2(mapdata);
  13186. bool mapIsPVP = mapdata->flag[MF_PVP] != 0;
  13187. bool mapIsGVG = mapdata_flag_gvg2_no_te(mapdata);
  13188. bool mapIsBG = mapdata->flag[MF_BATTLEGROUND] != 0;
  13189. bool mapIsTE = mapdata_flag_gvg2_te(mapdata);
  13190. for (const auto &it : status_db) {
  13191. sc_type type = static_cast<sc_type>(it.first);
  13192. if (!sc->data[type] || !SCDisabled[type])
  13193. continue;
  13194. if (status_change_isDisabledOnMap_(type, mapIsVS, mapIsPVP, mapIsGVG, mapIsBG, mapdata->zone, mapIsTE))
  13195. status_change_end(bl, type, INVALID_TIMER);
  13196. }
  13197. }
  13198. }
  13199. /**
  13200. * Read status_disabled.txt file
  13201. * @param str: Fields passed from sv_readdb
  13202. * @param columns: Columns passed from sv_readdb function call
  13203. * @param current: Current row being read into SCDisabled array
  13204. * @return True - Successfully stored, False - Invalid SC
  13205. */
  13206. static bool status_readdb_status_disabled(char **str, int columns, int current)
  13207. {
  13208. int64 type = SC_NONE;
  13209. if (ISDIGIT(str[0][0]))
  13210. type = atoi(str[0]);
  13211. else {
  13212. if (!script_get_constant(str[0],&type))
  13213. type = SC_NONE;
  13214. }
  13215. if (type <= SC_NONE || type >= SC_MAX) {
  13216. ShowError("status_readdb_status_disabled: Invalid SC with type %s.\n", str[0]);
  13217. return false;
  13218. }
  13219. SCDisabled[type] = (unsigned int)atol(str[1]);
  13220. return true;
  13221. }
  13222. const std::string AttributeDatabase::getDefaultLocation() {
  13223. return std::string(db_path) + "/attr_fix.yml";
  13224. }
  13225. /**
  13226. * Reads and parses an entry from the attr_fix.
  13227. * @param node: YAML node containing the entry.
  13228. * @return count of successfully parsed rows
  13229. */
  13230. uint64 AttributeDatabase::parseBodyNode(const ryml::NodeRef& node) {
  13231. uint16 level;
  13232. if (!this->asUInt16(node, "Level", level))
  13233. return 0;
  13234. if (!CHK_ELEMENT_LEVEL(level)) {
  13235. this->invalidWarning(node["Level"], "Invalid element level %hu.\n", level);
  13236. return 0;
  13237. }
  13238. for (const auto &itatk : um_eleid2elename) {
  13239. if (!this->nodeExists(node, itatk.first))
  13240. continue;
  13241. const auto& eleNode = node[c4::to_csubstr(itatk.first)];
  13242. for (const auto &itdef : um_eleid2elename) {
  13243. if (!this->nodeExists(eleNode, itdef.first))
  13244. continue;
  13245. int16 val;
  13246. if (!this->asInt16(eleNode, itdef.first, val))
  13247. return 0;
  13248. if (val < -100) {
  13249. 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);
  13250. val = -100;
  13251. }
  13252. else if (val > 200) {
  13253. 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);
  13254. val = 200;
  13255. }
  13256. this->attr_fix_table[level-1][itatk.second][itdef.second] = val;
  13257. }
  13258. }
  13259. return 1;
  13260. }
  13261. AttributeDatabase elemental_attribute_db;
  13262. /**
  13263. * Get attribute ratio
  13264. * @param atk_ele Attack element enum e_element
  13265. * @param def_ele Defense element enum e_element
  13266. * @param level Element level 1 ~ MAX_ELE_LEVEL
  13267. */
  13268. int16 AttributeDatabase::getAttribute(uint16 level, uint16 atk_ele, uint16 def_ele) {
  13269. if (!CHK_ELEMENT(atk_ele) || !CHK_ELEMENT(def_ele) || !CHK_ELEMENT_LEVEL(level+1))
  13270. return 100;
  13271. return this->attr_fix_table[level][atk_ele][def_ele];
  13272. }
  13273. const std::string StatusDatabase::getDefaultLocation() {
  13274. return std::string(db_path) + "/status.yml";
  13275. }
  13276. /**
  13277. * Reads and parses an entry from status_db.
  13278. * @param node: YAML node containing the entry.
  13279. * @return count of successfully parsed rows
  13280. */
  13281. uint64 StatusDatabase::parseBodyNode(const ryml::NodeRef& node) {
  13282. std::string status_name;
  13283. if (!this->asString(node, "Status", status_name))
  13284. return 0;
  13285. std::string status_constant = "SC_" + status_name;
  13286. int64 constant;
  13287. if (!script_get_constant(status_constant.c_str(), &constant)) {
  13288. this->invalidWarning(node["Status"], "Invalid Status %s.\n", status_name.c_str());
  13289. return 0;
  13290. }
  13291. if (!this->validateStatus(static_cast<sc_type>(constant))) {
  13292. this->invalidWarning(node["Status"], "Status %s is out of bounds.\n", status_name.c_str());
  13293. return 0;
  13294. }
  13295. int status_id = static_cast<int32>(constant);
  13296. std::shared_ptr<s_status_change_db> status = this->find(status_id);
  13297. bool exists = status != nullptr;
  13298. if (!exists) {
  13299. status = std::make_shared<s_status_change_db>();
  13300. status->type = static_cast<sc_type>(status_id);
  13301. }
  13302. if (this->nodeExists(node, "Icon")) {
  13303. std::string icon_name;
  13304. if (!this->asString(node, "Icon", icon_name))
  13305. return 0;
  13306. int64 constant;
  13307. if (!script_get_constant(icon_name.c_str(), &constant)) {
  13308. this->invalidWarning(node["Icon"], "Icon %s is invalid, defaulting to EFST_BLANK.\n", icon_name.c_str());
  13309. constant = EFST_BLANK;
  13310. }
  13311. if (constant < EFST_BLANK || constant >= EFST_MAX) {
  13312. this->invalidWarning(node["Icon"], "Icon %s is out of bounds, defaulting to EFST_BLANK.\n", icon_name.c_str());
  13313. constant = EFST_BLANK;
  13314. }
  13315. status->icon = static_cast<efst_type>(constant);
  13316. } else {
  13317. if (!exists)
  13318. status->icon = EFST_BLANK;
  13319. }
  13320. if (this->nodeExists(node, "DurationLookup")) {
  13321. std::string skill_name;
  13322. if (!this->asString(node, "DurationLookup", skill_name))
  13323. return 0;
  13324. uint16 skill_id = skill_name2id(skill_name.c_str());
  13325. if (skill_id == 0)
  13326. this->invalidWarning(node["DurationLookup"], "DurationLookup skill %s is invalid, defaulting to none.\n", skill_name.c_str());
  13327. status->skill_id = skill_id;
  13328. } else {
  13329. if (!exists)
  13330. status->skill_id = 0;
  13331. }
  13332. if (this->nodeExists(node, "States")) {
  13333. const ryml::NodeRef& stateNode = node["States"];
  13334. for (const auto &it : stateNode) {
  13335. std::string state;
  13336. c4::from_chars(it.key(), &state);
  13337. std::string state_constant = "SCS_" + state;
  13338. int64 constant;
  13339. if (!script_get_constant(state_constant.c_str(), &constant)) {
  13340. this->invalidWarning(stateNode, "State %s is invalid.\n", state.c_str());
  13341. return 0;
  13342. }
  13343. if (constant < SCS_NONE || constant >= SCS_MAX) {
  13344. this->invalidWarning(stateNode, "State %s is out of bounds.\n", state.c_str());
  13345. return 0;
  13346. }
  13347. bool active;
  13348. if (!this->asBool(stateNode, state, active))
  13349. return 0;
  13350. if (active)
  13351. status->state.set(static_cast<e_scs_flag>(constant));
  13352. else
  13353. status->state.reset(static_cast<e_scs_flag>(constant));
  13354. }
  13355. } else {
  13356. if (!exists)
  13357. status->state.reset();
  13358. }
  13359. if (this->nodeExists(node, "CalcFlags")) {
  13360. const ryml::NodeRef& flagNode = node["CalcFlags"];
  13361. if (this->nodeExists(flagNode, "All")) {
  13362. bool active;
  13363. if (!this->asBool(flagNode, "All", active))
  13364. return 0;
  13365. if (active)
  13366. status->calc_flag = this->getSCB_ALL();
  13367. else
  13368. status->calc_flag.reset();
  13369. }
  13370. for (const auto &it : flagNode) {
  13371. std::string flag;
  13372. c4::from_chars(it.key(), &flag);
  13373. std::string flag_constant = "SCB_" + flag;
  13374. int64 constant;
  13375. // Skipped because processed above the loop
  13376. if (flag.compare("All") == 0)
  13377. continue;
  13378. if (!script_get_constant(flag_constant.c_str(), &constant)) {
  13379. this->invalidWarning(flagNode, "CalcFlag %s is invalid.\n", flag.c_str());
  13380. return 0;
  13381. }
  13382. if (constant < SCB_NONE || constant >= SCB_MAX) {
  13383. this->invalidWarning(flagNode, "CalcFlag %s is out of bounds.\n", flag.c_str());
  13384. return 0;
  13385. }
  13386. bool active;
  13387. if (!this->asBool(flagNode, flag, active))
  13388. return 0;
  13389. if (active)
  13390. status->calc_flag.set(static_cast<e_scb_flag>(constant));
  13391. else
  13392. status->calc_flag.reset(static_cast<e_scb_flag>(constant));
  13393. }
  13394. } else {
  13395. if (!exists)
  13396. status->calc_flag.reset();
  13397. }
  13398. if (this->nodeExists(node, "Opt1")) {
  13399. std::string opt;
  13400. if (!this->asString(node, "Opt1", opt))
  13401. return 0;
  13402. std::string opt_constant = "OPT1_" + opt;
  13403. int64 constant;
  13404. if (!script_get_constant(opt_constant.c_str(), &constant)) {
  13405. this->invalidWarning(node["Opt1"], "Opt1 %s is invalid.\n", opt.c_str());
  13406. return 0;
  13407. }
  13408. if (constant < OPT1_NONE || constant >= OPT1_MAX) {
  13409. this->invalidWarning(node["Opt1"], "Opt2 %s is out of bounds.\n", opt.c_str());
  13410. return 0;
  13411. }
  13412. status->opt1 = static_cast<e_sc_opt1>(constant);
  13413. } else {
  13414. if (!exists)
  13415. status->opt1 = OPT1_NONE;
  13416. }
  13417. if (this->nodeExists(node, "Opt2")) {
  13418. const ryml::NodeRef& optNode = node["Opt2"];
  13419. for (const auto &it : optNode) {
  13420. std::string opt;
  13421. c4::from_chars(it.key(), &opt);
  13422. std::string opt_constant = "OPT2_" + opt;
  13423. int64 constant;
  13424. if (!script_get_constant(opt_constant.c_str(), &constant)) {
  13425. this->invalidWarning(optNode, "Opt2 %s is invalid.\n", opt.c_str());
  13426. return 0;
  13427. }
  13428. if (constant < OPT2_NONE || constant >= OPT2_MAX) {
  13429. this->invalidWarning(optNode, "Opt2 %s is out of bounds.\n", opt.c_str());
  13430. return 0;
  13431. }
  13432. bool active;
  13433. if (!this->asBool(optNode, opt, active))
  13434. return 0;
  13435. if (active)
  13436. status->opt2 |= static_cast<e_sc_opt2>(constant);
  13437. else
  13438. status->opt2 &= ~static_cast<e_sc_opt2>(constant);
  13439. }
  13440. } else {
  13441. if (!exists)
  13442. status->opt2 = OPT2_NONE;
  13443. }
  13444. if (this->nodeExists(node, "Opt3")) {
  13445. const ryml::NodeRef& optNode = node["Opt3"];
  13446. for (const auto &it : optNode) {
  13447. std::string opt;
  13448. c4::from_chars(it.key(), &opt);
  13449. std::string opt_constant = "OPT3_" + opt;
  13450. int64 constant;
  13451. if (!script_get_constant(opt_constant.c_str(), &constant)) {
  13452. this->invalidWarning(optNode, "Opt3 %s is invalid.\n", opt.c_str());
  13453. return 0;
  13454. }
  13455. if (constant < OPT3_NORMAL || constant >= OPT3_MAX) {
  13456. this->invalidWarning(optNode, "Opt3 %s is out of bounds.\n", opt.c_str());
  13457. return 0;
  13458. }
  13459. bool active;
  13460. if (!this->asBool(optNode, opt, active))
  13461. return 0;
  13462. if (active)
  13463. status->opt3 |= static_cast<e_sc_opt3>(constant);
  13464. else
  13465. status->opt3 &= ~static_cast<e_sc_opt3>(constant);
  13466. }
  13467. } else {
  13468. if (!exists)
  13469. status->opt3 = OPT3_NORMAL;
  13470. }
  13471. if (this->nodeExists(node, "Options")) {
  13472. const ryml::NodeRef& optionNode = node["Options"];
  13473. for (const auto &it : optionNode) {
  13474. std::string option;
  13475. c4::from_chars(it.key(), &option);
  13476. std::string option_constant = "OPTION_" + option;
  13477. int64 constant;
  13478. if (!script_get_constant(option_constant.c_str(), &constant)) {
  13479. this->invalidWarning(optionNode, "Option %s is invalid.\n", option.c_str());
  13480. return 0;
  13481. }
  13482. if (constant < OPTION_NOTHING || constant >= OPTION_MAX) {
  13483. this->invalidWarning(optionNode, "Option %s is out of bounds.\n", option.c_str());
  13484. return 0;
  13485. }
  13486. bool active;
  13487. if (!this->asBool(optionNode, option, active))
  13488. return 0;
  13489. if (active)
  13490. status->look |= static_cast<e_option>(constant);
  13491. else
  13492. status->look &= ~static_cast<e_option>(constant);
  13493. }
  13494. } else {
  13495. if (!exists)
  13496. status->look = OPTION_NOTHING;
  13497. }
  13498. if (this->nodeExists(node, "Flags")) {
  13499. const ryml::NodeRef& flagNode = node["Flags"];
  13500. for (const auto &it : flagNode) {
  13501. std::string flag;
  13502. c4::from_chars(it.key(), &flag);
  13503. std::string flag_constant = "SCF_" + flag;
  13504. int64 constant;
  13505. if (!script_get_constant(flag_constant.c_str(), &constant)) {
  13506. this->invalidWarning(flagNode, "Flag %s is invalid.\n", flag.c_str());
  13507. return 0;
  13508. }
  13509. if (constant < SCF_NONE || constant >= SCF_MAX) {
  13510. this->invalidWarning(flagNode, "Flag %s is out of bounds.\n", flag.c_str());
  13511. return 0;
  13512. }
  13513. bool active;
  13514. if (!this->asBool(flagNode, flag, active))
  13515. return 0;
  13516. if (active)
  13517. status->flag.set(static_cast<e_status_change_flag>(constant));
  13518. else
  13519. status->flag.reset(static_cast<e_status_change_flag>(constant));
  13520. }
  13521. } else {
  13522. if (!exists)
  13523. status->flag.reset();
  13524. }
  13525. if (this->nodeExists(node, "MinRate")) {
  13526. uint16 rate;
  13527. if (!this->asUInt16(node, "MinRate", rate))
  13528. return 0;
  13529. status->min_rate = rate;
  13530. } else {
  13531. if (!exists)
  13532. status->min_rate = 0;
  13533. }
  13534. if (this->nodeExists(node, "MinDuration")) {
  13535. int64 duration;
  13536. if (!this->asInt64(node, "MinDuration", duration))
  13537. return 0;
  13538. status->min_duration = static_cast<t_tick>(duration);
  13539. } else {
  13540. if (!exists)
  13541. status->min_duration = 1;
  13542. }
  13543. if (this->nodeExists(node, "Fail")) {
  13544. const ryml::NodeRef& failNode = node["Fail"];
  13545. for (const auto &it : failNode) {
  13546. std::string fail;
  13547. c4::from_chars(it.key(), &fail);
  13548. std::string fail_constant = "SC_" + fail;
  13549. int64 constant;
  13550. if (!script_get_constant(fail_constant.c_str(), &constant)) {
  13551. this->invalidWarning(failNode, "Fail status %s is invalid.\n", fail.c_str());
  13552. return 0;
  13553. }
  13554. if (!this->validateStatus(static_cast<sc_type>(constant))) {
  13555. this->invalidWarning(failNode, "Fail status %s is out of bounds.\n", fail.c_str());
  13556. return 0;
  13557. }
  13558. bool active;
  13559. if (!this->asBool(failNode, fail, active))
  13560. return 0;
  13561. if (active)
  13562. status->fail.push_back(static_cast<sc_type>(constant));
  13563. else
  13564. util::vector_erase_if_exists(status->fail, static_cast<sc_type>(constant));
  13565. }
  13566. }
  13567. if (this->nodeExists(node, "End")) {
  13568. const ryml::NodeRef& endNode = node["End"];
  13569. for (const auto &it : endNode) {
  13570. std::string end;
  13571. c4::from_chars(it.key(), &end);
  13572. std::string end_constant = "SC_" + end;
  13573. int64 constant;
  13574. if (!script_get_constant(end_constant.c_str(), &constant)) {
  13575. this->invalidWarning(endNode, "End status %s is invalid.\n", end.c_str());
  13576. return 0;
  13577. }
  13578. if (!this->validateStatus(static_cast<sc_type>(constant))) {
  13579. this->invalidWarning(endNode, "End status %s is out of bounds.\n", end.c_str());
  13580. return 0;
  13581. }
  13582. bool active;
  13583. if (!this->asBool(endNode, end, active))
  13584. return 0;
  13585. if (active)
  13586. status->end.push_back(static_cast<sc_type>(constant));
  13587. else
  13588. util::vector_erase_if_exists(status->end, static_cast<sc_type>(constant));
  13589. }
  13590. }
  13591. if (this->nodeExists(node, "EndReturn")) {
  13592. const ryml::NodeRef &endNode = node["EndReturn"];
  13593. for (const auto &it : endNode) {
  13594. std::string end;
  13595. c4::from_chars(it.key(), &end);
  13596. std::string end_constant = "SC_" + end;
  13597. int64 constant;
  13598. if (!script_get_constant(end_constant.c_str(), &constant)) {
  13599. this->invalidWarning(endNode, "EndReturn status %s is invalid.\n", end.c_str());
  13600. return 0;
  13601. }
  13602. if (!this->validateStatus(static_cast<sc_type>(constant))) {
  13603. this->invalidWarning(endNode, "EndReturn status %s is out of bounds.\n", end.c_str());
  13604. return 0;
  13605. }
  13606. bool active;
  13607. if (!this->asBool(endNode, end, active))
  13608. return 0;
  13609. if (active)
  13610. status->endreturn.push_back(static_cast<sc_type>(constant));
  13611. else
  13612. util::vector_erase_if_exists(status->endreturn, static_cast<sc_type>(constant));
  13613. }
  13614. }
  13615. if (!exists) {
  13616. this->put(status_id, status);
  13617. }
  13618. return 1;
  13619. }
  13620. void StatusDatabase::loadingFinished(){
  13621. std::fill( std::begin( this->StatusRelevantBLTypes ), std::end( this->StatusRelevantBLTypes ), BL_PC );
  13622. for( auto& entry : *this ){
  13623. auto& status = entry.second;
  13624. if (status->type == SC_HALLUCINATION && !battle_config.display_hallucination) // Disable Hallucination.
  13625. status->icon = EFST_BLANK;
  13626. if( status->icon == EFST_BLANK ){
  13627. continue;
  13628. }else if( status->flag[SCF_BLEFFECT] ){
  13629. this->StatusRelevantBLTypes[status->icon] |= BL_SCEFFECT;
  13630. }else{
  13631. this->StatusRelevantBLTypes[status->icon] = BL_PC;
  13632. }
  13633. }
  13634. }
  13635. StatusDatabase status_db;
  13636. /**
  13637. * Sets defaults in tables and starts read db functions
  13638. * sv_readdb reads the file, outputting the information line-by-line to
  13639. * previous functions above, separating information by delimiter
  13640. * DBs being read:
  13641. * attr_fix.yml: Attribute adjustment table for attacks
  13642. * size_fix.yml: Size adjustment table for weapons
  13643. * refine.yml: Refining data table
  13644. * @return 0
  13645. */
  13646. void status_readdb( bool reload ){
  13647. int i;
  13648. const char* dbsubpath[] = {
  13649. "",
  13650. "/" DBIMPORT,
  13651. //add other path here
  13652. };
  13653. // read databases
  13654. // path,filename,separator,mincol,maxcol,maxrow,func_parsor
  13655. for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
  13656. size_t n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
  13657. size_t n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
  13658. char* dbsubpath1 = (char*)aMalloc(n1+1);
  13659. char* dbsubpath2 = (char*)aMalloc(n2+1);
  13660. if(i==0) {
  13661. safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]);
  13662. safesnprintf(dbsubpath2,n2,"%s/%s%s",db_path,DBPATH,dbsubpath[i]);
  13663. }
  13664. else {
  13665. safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]);
  13666. safesnprintf(dbsubpath2,n1,"%s%s",db_path,dbsubpath[i]);
  13667. }
  13668. sv_readdb(dbsubpath1, "status_disabled.txt", ',', 2, 2, -1, &status_readdb_status_disabled, i > 0);
  13669. aFree(dbsubpath1);
  13670. aFree(dbsubpath2);
  13671. }
  13672. if( reload ){
  13673. size_fix_db.reload();
  13674. refine_db.reload();
  13675. status_db.reload();
  13676. }else{
  13677. size_fix_db.load();
  13678. refine_db.load();
  13679. status_db.load();
  13680. }
  13681. elemental_attribute_db.load();
  13682. }
  13683. /**
  13684. * Status db init and destroy.
  13685. */
  13686. void do_init_status(void) {
  13687. memset(SCDisabled, 0, sizeof(SCDisabled));
  13688. add_timer_func_list(status_change_timer,"status_change_timer");
  13689. add_timer_func_list(status_natural_heal_timer,"status_natural_heal_timer");
  13690. add_timer_func_list(status_clear_lastEffect_timer, "status_clear_lastEffect_timer");
  13691. initDummyData();
  13692. status_readdb();
  13693. natural_heal_prev_tick = gettick();
  13694. sc_data_ers = ers_new(sizeof(struct status_change_entry),"status.cpp::sc_data_ers",ERS_OPT_NONE);
  13695. add_timer_interval(natural_heal_prev_tick + NATURAL_HEAL_INTERVAL, status_natural_heal_timer, 0, 0, NATURAL_HEAL_INTERVAL);
  13696. }
  13697. /** Destroy status data */
  13698. void do_final_status(void) {
  13699. ers_destroy(sc_data_ers);
  13700. size_fix_db.clear();
  13701. refine_db.clear();
  13702. status_db.clear();
  13703. elemental_attribute_db.clear();
  13704. }