skill.c 289 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531
  1. // $Id: skill.c,v 1.8 2004/02/27 5:34:51 PM Celestia $
  2. /* スキル?係 */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include "timer.h"
  8. #include "nullpo.h"
  9. #include "malloc.h"
  10. #include "skill.h"
  11. #include "map.h"
  12. #include "clif.h"
  13. #include "pc.h"
  14. #include "status.h"
  15. #include "pet.h"
  16. #include "mob.h"
  17. #include "battle.h"
  18. #include "party.h"
  19. #include "itemdb.h"
  20. #include "script.h"
  21. #include "intif.h"
  22. #include "log.h"
  23. #include "chrif.h"
  24. #include "guild.h"
  25. #include "showmsg.h"
  26. #include "grfio.h"
  27. #ifdef MEMWATCH
  28. #include "memwatch.h"
  29. #endif
  30. #define SKILLUNITTIMER_INVERVAL 100
  31. #define STATE_BLIND 0x10
  32. #define swap(x,y) { int t; t = x; x = y; y = t; }
  33. const struct skill_name_db skill_names[] = {
  34. { AC_CHARGEARROW, "CHARGEARROW", "Charge_Arrow" } ,
  35. { AC_CONCENTRATION, "CONCENTRATION", "Improve_Concentration" } ,
  36. { AC_DOUBLE, "DOUBLE", "Double_Strafe" } ,
  37. { AC_MAKINGARROW, "MAKINGARROW", "Arrow_Creation" } ,
  38. { AC_OWL, "OWL", "Owl's_Eye" } ,
  39. { AC_SHOWER, "SHOWER", "Arrow_Shower" } ,
  40. { AC_VULTURE, "VULTURE", "Vulture's_Eye" } ,
  41. { ALL_RESURRECTION, "RESURRECTION", "Resurrection" } ,
  42. { AL_ANGELUS, "ANGELUS", "Angelus" } ,
  43. { AL_BLESSING, "BLESSING", "Blessing" } ,
  44. { AL_CRUCIS, "CRUCIS", "Signum_Crusis" } ,
  45. { AL_CURE, "CURE", "Cure" } ,
  46. { AL_DECAGI, "DECAGI", "Decrease_AGI" } ,
  47. { AL_DEMONBANE, "DEMONBANE", "Demon_Bane" } ,
  48. { AL_DP, "DP", "Divine_Protection" } ,
  49. { AL_HEAL, "HEAL", "Heal" } ,
  50. { AL_HOLYLIGHT, "HOLYLIGHT", "Holy_Light" } ,
  51. { AL_HOLYWATER, "HOLYWATER", "Aqua_Benedicta" } ,
  52. { AL_INCAGI, "INCAGI", "Increase_AGI" } ,
  53. { AL_PNEUMA, "PNEUMA", "Pneuma" } ,
  54. { AL_RUWACH, "RUWACH", "Ruwach" } ,
  55. { AL_TELEPORT, "TELEPORT", "Teleport" } ,
  56. { AL_WARP, "WARP", "Warp_Portal" } ,
  57. { AM_ACIDTERROR, "ACIDTERROR", "Acid_Terror" } ,
  58. { AM_AXEMASTERY, "AXEMASTERY", "Axe_Mastery" } ,
  59. { AM_BERSERKPITCHER, "BERSERKPITCHER", "Berserk Pitcher" } ,
  60. { AM_BIOETHICS, "BIOETHICS", "Bioethics" } ,
  61. { AM_BIOTECHNOLOGY, "BIOTECHNOLOGY", "Biotechnology" } ,
  62. { AM_CALLHOMUN, "CALLHOMUN", "Call_Homunculus" } ,
  63. { AM_CANNIBALIZE, "CANNIBALIZE", "Bio_Cannibalize" } ,
  64. { AM_CP_ARMOR, "ARMOR", "Chemical_Protection_Armor" } ,
  65. { AM_CP_HELM, "HELM", "Chemical_Protection_Helm" } ,
  66. { AM_CP_SHIELD, "SHIELD", "Chemical_Protection_Shield" } ,
  67. { AM_CP_WEAPON, "WEAPON", "Chemical_Protection_Weapon" } ,
  68. { AM_CREATECREATURE, "CREATECREATURE", "Life_Creation" } ,
  69. { AM_CULTIVATION, "CULTIVATION", "Cultivation" } ,
  70. { AM_DEMONSTRATION, "DEMONSTRATION", "Demonstration" } ,
  71. { AM_DRILLMASTER, "DRILLMASTER", "Drillmaster" } ,
  72. { AM_FLAMECONTROL, "FLAMECONTROL", "Flame_Control" } ,
  73. { AM_HEALHOMUN, "HEALHOMUN", "Heal_Homunculus" } ,
  74. { AM_LEARNINGPOTION, "LEARNINGPOTION", "AM_LEARNINGPOTION" } ,
  75. { AM_PHARMACY, "PHARMACY", "Pharmacy" } ,
  76. { AM_POTIONPITCHER, "POTIONPITCHER", "Potion_Pitcher" } ,
  77. { AM_REST, "REST", "Sabbath" } ,
  78. { AM_RESURRECTHOMUN, "RESURRECTHOMUN", "Ressurect_Homunculus" } ,
  79. { AM_SPHEREMINE, "SPHEREMINE", "Sphere_Mine" } ,
  80. { ASC_BREAKER, "BREAKER", "Breaker" } ,
  81. { ASC_CDP, "CDP", "Create_Deadly_Poison" } ,
  82. { ASC_EDP, "EDP", "Deadly_Poison_Enchantment" } ,
  83. { ASC_HALLUCINATION, "HALLUCINATION", "Hallucination_Walk" } ,
  84. { ASC_KATAR, "KATAR", "Advanced_Katar_Mastery" } ,
  85. { ASC_METEORASSAULT, "METEORASSAULT", "Meteor_Assault" } ,
  86. { AS_CLOAKING, "CLOAKING", "Cloaking" } ,
  87. { AS_ENCHANTPOISON, "ENCHANTPOISON", "Enchant_Poison" } ,
  88. { AS_GRIMTOOTH, "GRIMTOOTH", "Grimtooth" } ,
  89. { AS_KATAR, "KATAR", "Katar_Mastery" } ,
  90. { AS_LEFT, "LEFT", "Lefthand_Mastery" } ,
  91. { AS_POISONREACT, "POISONREACT", "Poison_React" } ,
  92. { AS_RIGHT, "RIGHT", "Righthand_Mastery" } ,
  93. { AS_SONICBLOW, "SONICBLOW", "Sonic_Blow" } ,
  94. { AS_SPLASHER, "SPLASHER", "Venom_Splasher" } ,
  95. { AS_VENOMDUST, "VENOMDUST", "Venom_Dust" } ,
  96. { BA_APPLEIDUN, "APPLEIDUN", "Apple_of_Idun" } ,
  97. { BA_ASSASSINCROSS, "ASSASSINCROSS", "Assassin_Cross" } ,
  98. { BA_DISSONANCE, "DISSONANCE", "Dissonance" } ,
  99. { BA_FROSTJOKE, "FROSTJOKE", "Dumb_Joke" } ,
  100. { BA_MUSICALLESSON, "MUSICALLESSON", "Musical_Lesson" } ,
  101. { BA_MUSICALSTRIKE, "MUSICALSTRIKE", "Musical_Strike" } ,
  102. { BA_POEMBRAGI, "POEMBRAGI", "Poem_of_Bragi" } ,
  103. { BA_WHISTLE, "WHISTLE", "Whistle" } ,
  104. { BD_ADAPTATION, "ADAPTATION", "Adaption" } ,
  105. { BD_DRUMBATTLEFIELD, "DRUMBATTLEFIELD", "Drumb_BattleField" } ,
  106. { BD_ENCORE, "ENCORE", "Encore" } ,
  107. { BD_ETERNALCHAOS, "ETERNALCHAOS", "Eternal_Chaos" } ,
  108. { BD_INTOABYSS, "INTOABYSS", "Into_the_Abyss" } ,
  109. { BD_LULLABY, "LULLABY", "Lullaby" } ,
  110. { BD_RAGNAROK, "RAGNAROK", "Ragnarok" } ,
  111. { BD_RICHMANKIM, "RICHMANKIM", "Rich_Mankim" } ,
  112. { BD_RINGNIBELUNGEN, "RINGNIBELUNGEN", "Ring_of_Nibelugen" } ,
  113. { BD_ROKISWEIL, "ROKISWEIL", "Loki's_Wail" } ,
  114. { BD_SIEGFRIED, "SIEGFRIED", "Invulnerable_Siegfried" } ,
  115. { BS_ADRENALINE, "ADRENALINE", "Adrenaline_Rush" } ,
  116. { BS_ADRENALINE2, "ADRENALINE2", "Adrenaline Rush 2" } ,
  117. { BS_AXE, "AXE", "Smith_Axe" } ,
  118. { BS_DAGGER, "DAGGER", "Smith_Dagger" } ,
  119. { BS_ENCHANTEDSTONE, "ENCHANTEDSTONE", "Enchantedstone_Craft" } ,
  120. { BS_FINDINGORE, "FINDINGORE", "Ore_Discovery" } ,
  121. { BS_HAMMERFALL, "HAMMERFALL", "Hammer_Fall" } ,
  122. { BS_HILTBINDING, "HILTBINDING", "Hilt_Binding" } ,
  123. { BS_IRON, "IRON", "Iron_Tempering" } ,
  124. { BS_KNUCKLE, "KNUCKLE", "Smith_Knucklebrace" } ,
  125. { BS_MACE, "MACE", "Smith_Mace" } ,
  126. { BS_MAXIMIZE, "MAXIMIZE", "Power_Maximize" } ,
  127. { BS_ORIDEOCON, "ORIDEOCON", "Orideocon_Research" } ,
  128. { BS_OVERTHRUST, "OVERTHRUST", "Power-Thrust" } ,
  129. { BS_REPAIRWEAPON, "REPAIRWEAPON", "Weapon_Repair" } ,
  130. { BS_SKINTEMPER, "SKINTEMPER", "Skin_Tempering" } ,
  131. { BS_SPEAR, "SPEAR", "Smith_Spear" } ,
  132. { BS_STEEL, "STEEL", "Steel_Tempering" } ,
  133. { BS_SWORD, "SWORD", "Smith_Sword" } ,
  134. { BS_TWOHANDSWORD, "TWOHANDSWORD", "Smith_Two-handed_Sword" } ,
  135. { BS_WEAPONPERFECT, "WEAPONPERFECT", "Weapon_Perfection" } ,
  136. { BS_WEAPONRESEARCH, "WEAPONRESEARCH", "Weaponry_Research" } ,
  137. { CG_ARROWVULCAN, "ARROWVULCAN", "Vulcan_Arrow" } ,
  138. { CG_MARIONETTE, "MARIONETTE", "Marionette_Control" } ,
  139. { CG_MOONLIT, "MOONLIT", "Moonlight_Petals" } ,
  140. { CH_CHAINCRUSH, "CHAINCRUSH", "Chain_Crush_Combo" } ,
  141. { CH_PALMSTRIKE, "PALMSTRIKE", "Palm_Push_Strike" } ,
  142. { CH_SOULCOLLECT, "SOULCOLLECT", "Collect_Soul" } ,
  143. { CH_TIGERFIST, "TIGERFIST", "Tiger_Knuckle_Fist" } ,
  144. { CR_ALCHEMY, "ALCHEMY", "Alchemy" } ,
  145. { CR_SLIMPITCHER, "SLIMPITCHER", "Slim_Pitcher" } ,
  146. { CR_FULLPROTECTION, "FULLPROTECTION", "Full_Chemical_Protection" } ,
  147. { CR_AUTOGUARD, "AUTOGUARD", "Guard" } ,
  148. { CR_DEFENDER, "DEFENDER", "Defender" } ,
  149. { CR_DEVOTION, "DEVOTION", "Sacrifice" } ,
  150. { CR_GRANDCROSS, "GRANDCROSS", "Grand_Cross" } ,
  151. { CR_HOLYCROSS, "HOLYCROSS", "Holy_Cross" } ,
  152. { CR_PROVIDENCE, "PROVIDENCE", "Providence" } ,
  153. { CR_REFLECTSHIELD, "REFLECTSHIELD", "Shield_Reflect" } ,
  154. { CR_SHIELDBOOMERANG, "SHIELDBOOMERANG", "Shield_Boomerang" } ,
  155. { CR_SHIELDCHARGE, "SHIELDCHARGE", "Shield_Charge" } ,
  156. { CR_SPEARQUICKEN, "SPEARQUICKEN", "Spear_Quicken" } ,
  157. { CR_SYNTHESISPOTION, "SYNTHESISPOTION", "Potion_Synthesis" } ,
  158. { CR_TRUST, "TRUST", "Faith" } ,
  159. { DC_DANCINGLESSON, "DANCINGLESSON", "Dancing_Lesson" } ,
  160. { DC_DONTFORGETME, "DONTFORGETME", "Don't_Forget_Me" } ,
  161. { DC_FORTUNEKISS, "FORTUNEKISS", "Fortune_Kiss" } ,
  162. { DC_HUMMING, "HUMMING", "Humming" } ,
  163. { DC_SCREAM, "SCREAM", "Scream" } ,
  164. { DC_SERVICEFORYOU, "SERVICEFORYOU", "Prostitute" } ,
  165. { DC_THROWARROW, "THROWARROW", "Throw_Arrow" } ,
  166. { DC_UGLYDANCE, "UGLYDANCE", "Ugly_Dance" } ,
  167. { GD_BATTLEORDER, "BATTLEORDER", "Battle_Orders" } ,
  168. { GD_REGENERATION, "REGENERATION", "Regeneration" } ,
  169. { GD_RESTORE, "RESTORE", "Restore" } ,
  170. { GD_EMERGENCYCALL, "EMERGENCYCALL", "Emergency_Call" } ,
  171. { HP_ASSUMPTIO, "ASSUMPTIO", "Assumptio" } ,
  172. { HP_BASILICA, "BASILICA", "Basilica" } ,
  173. { HP_MEDITATIO, "MEDITATIO", "Meditation" } ,
  174. { HT_ANKLESNARE, "ANKLESNARE", "Ankle_Snare" } ,
  175. { HT_BEASTBANE, "BEASTBANE", "Beast_Bane" } ,
  176. { HT_BLASTMINE, "BLASTMINE", "Blast_Mine" } ,
  177. { HT_BLITZBEAT, "BLITZBEAT", "Blitz_Beat" } ,
  178. { HT_CLAYMORETRAP, "CLAYMORETRAP", "Claymore_Trap" } ,
  179. { HT_DETECTING, "DETECTING", "Detect" } ,
  180. { HT_FALCON, "FALCON", "Falconry_Mastery" } ,
  181. { HT_FLASHER, "FLASHER", "Flasher" } ,
  182. { HT_FREEZINGTRAP, "FREEZINGTRAP", "Freezing_Trap" } ,
  183. { HT_LANDMINE, "LANDMINE", "Land_Mine" } ,
  184. { HT_REMOVETRAP, "REMOVETRAP", "Remove_Trap" } ,
  185. { HT_SANDMAN, "SANDMAN", "Sandman" } ,
  186. { HT_SHOCKWAVE, "SHOCKWAVE", "Shockwave_Trap" } ,
  187. { HT_SKIDTRAP, "SKIDTRAP", "Skid_Trap" } ,
  188. { HT_SPRINGTRAP, "SPRINGTRAP", "Spring_Trap" } ,
  189. { HT_STEELCROW, "STEELCROW", "Steel_Crow" } ,
  190. { HT_TALKIEBOX, "TALKIEBOX", "Talkie_Box" } ,
  191. { HW_MAGICCRASHER, "MAGICCRASHER", "Magic_Crasher" } ,
  192. { HW_MAGICPOWER, "MAGICPOWER", "Magic_Power" } ,
  193. { HW_NAPALMVULCAN, "NAPALMVULCAN", "Napalm_Vulcan" } ,
  194. { HW_SOULDRAIN, "SOULDRAIN", "Soul_Drain" } ,
  195. { ITM_TOMAHAWK, "TOMAHAWK", "Throw_Tomahawk" } ,
  196. { KN_AUTOCOUNTER, "AUTOCOUNTER", "Counter_Attack" } ,
  197. { KN_BOWLINGBASH, "BOWLINGBASH", "Bowling_Bash" } ,
  198. { KN_BRANDISHSPEAR, "BRANDISHSPEAR", "Brandish_Spear" } ,
  199. { KN_CAVALIERMASTERY, "CAVALIERMASTERY", "Cavalier_Mastery" } ,
  200. { KN_PIERCE, "PIERCE", "Pierce" } ,
  201. { KN_RIDING, "RIDING", "Peco_Peco_Ride" } ,
  202. { KN_SPEARBOOMERANG, "SPEARBOOMERANG", "Spear_Boomerang" } ,
  203. { KN_SPEARMASTERY, "SPEARMASTERY", "Spear_Mastery" } ,
  204. { KN_SPEARSTAB, "SPEARSTAB", "Spear_Stab" } ,
  205. { KN_TWOHANDQUICKEN, "TWOHANDQUICKEN", "Twohand_Quicken" } ,
  206. { LK_AURABLADE, "AURABLADE", "Aura_Blade" } ,
  207. { LK_BERSERK, "BERSERK", "Berserk" } ,
  208. { LK_CONCENTRATION, "CONCENTRATION", "Concentration" } ,
  209. { LK_FURY, "FURY", "LK_FURY" } ,
  210. { LK_HEADCRUSH, "HEADCRUSH", "Head_Crusher" } ,
  211. { LK_JOINTBEAT, "JOINTBEAT", "Joint_Beat" } ,
  212. { LK_PARRYING, "PARRYING", "Parrying" } ,
  213. { LK_SPIRALPIERCE, "SPIRALPIERCE", "Spiral_Pierce" } ,
  214. { LK_TENSIONRELAX, "TENSIONRELAX", "Tension_Relax" } ,
  215. { MC_CARTREVOLUTION, "CARTREVOLUTION", "Cart_Revolution" } ,
  216. { MC_CHANGECART, "CHANGECART", "Change_Cart" } ,
  217. { MC_DISCOUNT, "DISCOUNT", "Discount" } ,
  218. { MC_IDENTIFY, "IDENTIFY", "Item_Appraisal" } ,
  219. { MC_INCCARRY, "INCCARRY", "Enlarge_Weight_Limit" } ,
  220. { MC_LOUD, "LOUD", "Lord_Exclamation" } ,
  221. { MC_MAMMONITE, "MAMMONITE", "Mammonite" } ,
  222. { MC_OVERCHARGE, "OVERCHARGE", "Overcharge" } ,
  223. { MC_PUSHCART, "PUSHCART", "Pushcart" } ,
  224. { MC_VENDING, "VENDING", "Vending" } ,
  225. { MG_COLDBOLT, "COLDBOLT", "Cold_Bolt" } ,
  226. { MG_ENERGYCOAT, "ENERGYCOAT", "Energy_Coat" } ,
  227. { MG_FIREBALL, "FIREBALL", "Fire_Ball" } ,
  228. { MG_FIREBOLT, "FIREBOLT", "Fire_Bolt" } ,
  229. { MG_FIREWALL, "FIREWALL", "Fire_Wall" } ,
  230. { MG_FROSTDIVER, "FROSTDIVER", "Frost_Diver" } ,
  231. { MG_LIGHTNINGBOLT, "LIGHTNINGBOLT", "Lightening_Bolt" } ,
  232. { MG_NAPALMBEAT, "NAPALMBEAT", "Napalm_Beat" } ,
  233. { MG_SAFETYWALL, "SAFETYWALL", "Safety_Wall" } ,
  234. { MG_SIGHT, "SIGHT", "Sight" } ,
  235. { MG_SOULSTRIKE, "SOULSTRIKE", "Soul_Strike" } ,
  236. { MG_SRECOVERY, "SRECOVERY", "Increase_SP_Recovery" } ,
  237. { MG_STONECURSE, "STONECURSE", "Stone_Curse" } ,
  238. { MG_THUNDERSTORM, "THUNDERSTORM", "Thunderstorm" } ,
  239. { MO_ABSORBSPIRITS, "ABSORBSPIRITS", "Absorb_Spirits" } ,
  240. { MO_BLADESTOP, "BLADESTOP", "Blade_Stop" } ,
  241. { MO_BODYRELOCATION, "BODYRELOCATION", "Body_Relocation" } ,
  242. { MO_CALLSPIRITS, "CALLSPIRITS", "Call_Spirits" } ,
  243. { MO_CHAINCOMBO, "CHAINCOMBO", "Chain_Combo" } ,
  244. { MO_COMBOFINISH, "COMBOFINISH", "Combo_Finish" } ,
  245. { MO_DODGE, "DODGE", "Dodge" } ,
  246. { MO_EXPLOSIONSPIRITS, "EXPLOSIONSPIRITS", "Explosion_Spirits" } ,
  247. { MO_EXTREMITYFIST, "EXTREMITYFIST", "Extremity_Fist" } ,
  248. { MO_FINGEROFFENSIVE, "FINGEROFFENSIVE", "Finger_Offensive" } ,
  249. { MO_INVESTIGATE, "INVESTIGATE", "Investigate" } ,
  250. { MO_IRONHAND, "IRONHAND", "Iron_Hand" } ,
  251. { MO_SPIRITSRECOVERY, "SPIRITSRECOVERY", "Spirit_Recovery" } ,
  252. { MO_STEELBODY, "STEELBODY", "Steel_Body" } ,
  253. { MO_TRIPLEATTACK, "TRIPLEATTACK", "Triple_Blows" } ,
  254. { NPC_ATTRICHANGE, "ATTRICHANGE", "NPC_ATTRICHANGE" } ,
  255. { NPC_BARRIER, "BARRIER", "NPC_BARRIER" } ,
  256. { NPC_BLINDATTACK, "BLINDATTACK", "NPC_BLINDATTACK" } ,
  257. { NPC_BLOODDRAIN, "BLOODDRAIN", "NPC_BLOODDRAIN" } ,
  258. { NPC_CHANGEDARKNESS, "CHANGEDARKNESS", "NPC_CHANGEDARKNESS" } ,
  259. { NPC_CHANGEFIRE, "CHANGEFIRE", "NPC_CHANGEFIRE" } ,
  260. { NPC_CHANGEGROUND, "CHANGEGROUND", "NPC_CHANGEGROUND" } ,
  261. { NPC_CHANGEHOLY, "CHANGEHOLY", "NPC_CHANGEHOLY" } ,
  262. { NPC_CHANGEPOISON, "CHANGEPOISON", "NPC_CHANGEPOISON" } ,
  263. { NPC_CHANGETELEKINESIS, "CHANGETELEKINESIS", "NPC_CHANGETELEKINESIS" } ,
  264. { NPC_CHANGEWATER, "CHANGEWATER", "NPC_CHANGEWATER" } ,
  265. { NPC_CHANGEWIND, "CHANGEWIND", "NPC_CHANGEWIND" } ,
  266. { NPC_COMBOATTACK, "COMBOATTACK", "NPC_COMBOATTACK" } ,
  267. { NPC_CRITICALSLASH, "CRITICALSLASH", "NPC_CRITICALSLASH" } ,
  268. { NPC_CURSEATTACK, "CURSEATTACK", "NPC_CURSEATTACK" } ,
  269. { NPC_DARKBLESSING, "DARKBLESSING", "NPC_DARKBLESSING" } ,
  270. { NPC_DARKBREATH, "DARKBREATH", "NPC_DARKBREATH" } ,
  271. { NPC_DARKCROSS, "DARKCROSS", "NPC_DARKCROSS" } ,
  272. { NPC_DARKNESSATTACK, "DARKNESSATTACK", "NPC_DARKNESSATTACK" } ,
  273. { NPC_DEFENDER, "DEFENDER", "NPC_DEFENDER" } ,
  274. { NPC_EMOTION, "EMOTION", "NPC_EMOTION" } ,
  275. { NPC_ENERGYDRAIN, "ENERGYDRAIN", "NPC_ENERGYDRAIN" } ,
  276. { NPC_FIREATTACK, "FIREATTACK", "NPC_FIREATTACK" } ,
  277. { NPC_GROUNDATTACK, "GROUNDATTACK", "NPC_GROUNDATTACK" } ,
  278. { NPC_GUIDEDATTACK, "GUIDEDATTACK", "NPC_GUIDEDATTACK" } ,
  279. { NPC_HALLUCINATION, "HALLUCINATION", "NPC_HALLUCINATION" } ,
  280. { NPC_HOLYATTACK, "HOLYATTACK", "NPC_HOLYATTACK" } ,
  281. { NPC_KEEPING, "KEEPING", "NPC_KEEPING" } ,
  282. { NPC_LICK, "LICK", "NPC_LICK" } ,
  283. { NPC_MAGICALATTACK, "MAGICALATTACK", "NPC_MAGICALATTACK" } ,
  284. { NPC_MENTALBREAKER, "MENTALBREAKER", "NPC_MENTALBREAKER" } ,
  285. { NPC_METAMORPHOSIS, "METAMORPHOSIS", "NPC_METAMORPHOSIS" } ,
  286. { NPC_PETRIFYATTACK, "PETRIFYATTACK", "NPC_PETRIFYATTACK" } ,
  287. { NPC_PIERCINGATT, "PIERCINGATT", "NPC_PIERCINGATT" } ,
  288. { NPC_POISON, "POISON", "NPC_POISON" } ,
  289. { NPC_POISONATTACK, "POISONATTACK", "NPC_POISONATTACK" } ,
  290. { NPC_PROVOCATION, "PROVOCATION", "NPC_PROVOCATION" } ,
  291. { NPC_RANDOMATTACK, "RANDOMATTACK", "NPC_RANDOMATTACK" } ,
  292. { NPC_RANGEATTACK, "RANGEATTACK", "NPC_RANGEATTACK" } ,
  293. { NPC_REBIRTH, "REBIRTH", "NPC_REBIRTH" } ,
  294. { NPC_SELFDESTRUCTION, "SELFDESTRUCTION", "Kabooooom!" } ,
  295. { NPC_SELFDESTRUCTION2, "SELFDESTRUCTION2", "NPC_SELFDESTRUCTION2" } ,
  296. { NPC_SILENCEATTACK, "SILENCEATTACK", "NPC_SILENCEATTACK" } ,
  297. { NPC_SLEEPATTACK, "SLEEPATTACK", "NPC_SLEEPATTACK" } ,
  298. { NPC_SMOKING, "SMOKING", "NPC_SMOKING" } ,
  299. { NPC_SPLASHATTACK, "SPLASHATTACK", "NPC_SPLASHATTACK" } ,
  300. { NPC_STUNATTACK, "STUNATTACK", "NPC_STUNATTACK" } ,
  301. { NPC_SUICIDE, "SUICIDE", "NPC_SUICIDE" } ,
  302. { NPC_SUMMONMONSTER, "SUMMONMONSTER", "NPC_SUMMONMONSTER" } ,
  303. { NPC_SUMMONSLAVE, "SUMMONSLAVE", "NPC_SUMMONSLAVE" } ,
  304. { NPC_TELEKINESISATTACK, "TELEKINESISATTACK", "NPC_TELEKINESISATTACK" } ,
  305. { NPC_TRANSFORMATION, "TRANSFORMATION", "NPC_TRANSFORMATION" } ,
  306. { NPC_WATERATTACK, "WATERATTACK", "NPC_WATERATTACK" } ,
  307. { NPC_WINDATTACK, "WINDATTACK", "NPC_WINDATTACK" } ,
  308. { NV_BASIC, "BASIC", "Basic_Skill" } ,
  309. { NV_FIRSTAID, "FIRSTAID", "First Aid" } ,
  310. { NV_TRICKDEAD, "TRICKDEAD", "Play_Dead" } ,
  311. { PA_GOSPEL, "GOSPEL", "Gospel" } ,
  312. { PA_PRESSURE, "PRESSURE", "Pressure" } ,
  313. { PA_SACRIFICE, "SACRIFICE", "Sacrificial_Ritual" } ,
  314. { PF_FOGWALL, "FOGWALL", "Wall_of_Fog" } ,
  315. { PF_HPCONVERSION, "HPCONVERSION", "Health_Conversion" } ,
  316. { PF_MEMORIZE, "MEMORIZE", "Memorize" } ,
  317. { PF_MINDBREAKER, "MINDBREAKER", "Mind_Breaker" } ,
  318. { PF_SOULBURN, "SOULBURN", "Soul_Burn" } ,
  319. { PF_SOULCHANGE, "SOULCHANGE", "Soul_Change" } ,
  320. { PF_SPIDERWEB, "SPIDERWEB", "Spider_Web" } ,
  321. { PR_ASPERSIO, "ASPERSIO", "Aspersio" } ,
  322. { PR_BENEDICTIO, "BENEDICTIO", "B.S_Sacramenti" } ,
  323. { PR_GLORIA, "GLORIA", "Gloria" } ,
  324. { PR_IMPOSITIO, "IMPOSITIO", "Impositio_Manus" } ,
  325. { PR_KYRIE, "KYRIE", "Kyrie_Eleison" } ,
  326. { PR_LEXAETERNA, "LEXAETERNA", "Lex_Aeterna" } ,
  327. { PR_LEXDIVINA, "LEXDIVINA", "Lex_Divina" } ,
  328. { PR_MACEMASTERY, "MACEMASTERY", "Mace_Mastery" } ,
  329. { PR_MAGNIFICAT, "MAGNIFICAT", "Magnificat" } ,
  330. { PR_MAGNUS, "MAGNUS", "Magnus_Exorcismus" } ,
  331. { PR_SANCTUARY, "SANCTUARY", "Santuary" } ,
  332. { PR_SLOWPOISON, "SLOWPOISON", "Slow_Poison" } ,
  333. { PR_STRECOVERY, "STRECOVERY", "Status_Recovery" } ,
  334. { PR_SUFFRAGIUM, "SUFFRAGIUM", "Suffragium" } ,
  335. { PR_TURNUNDEAD, "TURNUNDEAD", "Turn_Undead" } ,
  336. { RG_BACKSTAP, "BACKSTAP", "Back_Stab" } ,
  337. { RG_CLEANER, "CLEANER", "Remover" } ,
  338. { RG_COMPULSION, "COMPULSION", "Compulsion_Discount" } ,
  339. { RG_FLAGGRAFFITI, "FLAGGRAFFITI", "Flag_Graffity" } ,
  340. { RG_GANGSTER, "GANGSTER", "Gangster's_Paradise" } ,
  341. { RG_GRAFFITI, "GRAFFITI", "Graffiti" } ,
  342. { RG_INTIMIDATE, "INTIMIDATE", "Intimidate" } ,
  343. { RG_PLAGIARISM, "PLAGIARISM", "Plagiarism" } ,
  344. { RG_RAID, "RAID", "Raid" } ,
  345. { RG_SNATCHER, "SNATCHER", "Snatcher" } ,
  346. { RG_STEALCOIN, "STEALCOIN", "Steal_Coin" } ,
  347. { RG_STRIPARMOR, "STRIPARMOR", "Strip_Armor" } ,
  348. { RG_STRIPHELM, "STRIPHELM", "Strip_Helm" } ,
  349. { RG_STRIPSHIELD, "STRIPSHIELD", "Strip_Shield" } ,
  350. { RG_STRIPWEAPON, "STRIPWEAPON", "Strip_Weapon" } ,
  351. { RG_TUNNELDRIVE, "TUNNELDRIVE", "Tunnel_Drive" } ,
  352. { SA_ABRACADABRA, "ABRACADABRA", "Hocus-pocus" } ,
  353. { SA_ADVANCEDBOOK, "ADVANCEDBOOK", "Advanced_Book" } ,
  354. { SA_AUTOSPELL, "AUTOSPELL", "Auto_Cast" } ,
  355. { SA_CASTCANCEL, "CASTCANCEL", "Cast_Cancel" } ,
  356. { SA_CLASSCHANGE, "CLASSCHANGE", "Class_Change" } ,
  357. { SA_COMA, "COMA", "Coma" } ,
  358. { SA_DEATH, "DEATH", "Death" } ,
  359. { SA_DELUGE, "DELUGE", "Deluge" } ,
  360. { SA_DISPELL, "DISPELL", "Dispel" } ,
  361. { SA_DRAGONOLOGY, "DRAGONOLOGY", "Dragonology" } ,
  362. { SA_FLAMELAUNCHER, "FLAMELAUNCHER", "Flame_Launcher" } ,
  363. { SA_FORTUNE, "FORTUNE", "Fortune" } ,
  364. { SA_FREECAST, "FREECAST", "Cast_Freedom" } ,
  365. { SA_FROSTWEAPON, "FROSTWEAPON", "Frost_Weapon" } ,
  366. { SA_FULLRECOVERY, "FULLRECOVERY", "Full_Recovery" } ,
  367. { SA_GRAVITY, "GRAVITY", "Gravity" } ,
  368. { SA_INSTANTDEATH, "INSTANTDEATH", "Instant_Death" } ,
  369. { SA_LANDPROTECTOR, "LANDPROTECTOR", "Land_Protector" } ,
  370. { SA_LEVELUP, "LEVELUP", "Level_Up" } ,
  371. { SA_LIGHTNINGLOADER, "LIGHTNINGLOADER", "Lightning_Loader" } ,
  372. { SA_MAGICROD, "MAGICROD", "Magic_Rod" } ,
  373. { SA_MONOCELL, "MONOCELL", "Monocell" } ,
  374. { SA_QUESTION, "QUESTION", "Question?" } ,
  375. { SA_REVERSEORCISH, "REVERSEORCISH", "Reverse_Orcish" } ,
  376. { SA_SEISMICWEAPON, "SEISMICWEAPON", "Seismic_Weapon" } ,
  377. { SA_SPELLBREAKER, "SPELLBREAKER", "Break_Spell" } ,
  378. { SA_SUMMONMONSTER, "SUMMONMONSTER", "Summon_Monster" } ,
  379. { SA_TAMINGMONSTER, "TAMINGMONSTER", "Taming_Monster" } ,
  380. { SA_VIOLENTGALE, "VIOLENTGALE", "Violent_Gale" } ,
  381. { SA_VOLCANO, "VOLCANO", "Volcano" } ,
  382. { SG_DEVIL, "DEVIL", "Devil" } ,
  383. { SG_FEEL, "FEEL", "Feel" } ,
  384. { SG_FRIEND, "FRIEND", "Friend" } ,
  385. { SG_FUSION, "FUSION", "Fusion" } ,
  386. { SG_HATE, "HATE", "Hate" } ,
  387. { SG_KNOWLEDGE, "KNOWLEDGE", "Knowledge" } ,
  388. { SG_MOON_ANGER, "ANGER", "Moon Anger" } ,
  389. { SG_MOON_BLESS, "BLESS", "Moon Bless" } ,
  390. { SG_MOON_COMFORT, "COMFORT", "Moon Comfort" } ,
  391. { SG_MOON_WARM, "WARM", "Moon Warm" } ,
  392. { SG_STAR_ANGER, "ANGER", "Star Anger" } ,
  393. { SG_STAR_BLESS, "BLESS", "Star Bless" } ,
  394. { SG_STAR_COMFORT, "COMFORT", "Star Comfort" } ,
  395. { SG_STAR_WARM, "WARM", "Star Warm" } ,
  396. { SG_SUN_ANGER, "ANGER", "Sun Anger" } ,
  397. { SG_SUN_BLESS, "BLESS", "Sun Bless" } ,
  398. { SG_SUN_COMFORT, "COMFORT", "Sun Comfort" } ,
  399. { SG_SUN_WARM, "WARM", "Sun Warm" } ,
  400. { SL_ALCHEMIST, "ALCHEMIST", "Alchemist" } ,
  401. { SL_ASSASIN, "ASSASIN", "Assasin" } ,
  402. { SL_BARDDANCER, "BARDDANCER", "Bard Dancer" } ,
  403. { SL_BLACKSMITH, "BLACKSMITH", "Black Smith" } ,
  404. { SL_CRUSADER, "CRUSADER", "Crusader" } ,
  405. { SL_HUNTER, "HUNTER", "Hunter" } ,
  406. { SL_KAAHI, "KAAHI", "Kaahi" } ,
  407. { SL_KAINA, "KAINA", "Kaina" } ,
  408. { SL_KAITE, "KAITE", "Kaite" } ,
  409. { SL_KAIZEL, "KAIZEL", "Kaizel" } ,
  410. { SL_KAUPE, "KAUPE", "Kaupe" } ,
  411. { SL_KNIGHT, "KNIGHT", "Knight" } ,
  412. { SL_MONK, "MONK", "Monk" } ,
  413. { SL_PRIEST, "PRIEST", "Priest" } ,
  414. { SL_ROGUE, "ROGUE", "Rogue" } ,
  415. { SL_SAGE, "SAGE", "Sage" } ,
  416. { SL_SKA, "SKA", "SKA" } ,
  417. { SL_SKE, "SKE", "SKE" } ,
  418. { SL_SMA, "SMA", "SMA" } ,
  419. { SL_SOULLINKER, "SOULLINKER", "Soul Linker" } ,
  420. { SL_STAR, "STAR", "Star" } ,
  421. { SL_STIN, "STIN", "Stin" } ,
  422. { SL_STUN, "STUN", "Stun" } ,
  423. { SL_SUPERNOVICE, "SUPERNOVICE", "Super Novice" } ,
  424. { SL_SWOO, "SWOO", "Swoo" } ,
  425. { SL_WIZARD, "WIZARD", "Wizard" } ,
  426. { SM_AUTOBERSERK, "AUTOBERSERK", "Auto_Berserk" } ,
  427. { SM_BASH, "BASH", "Bash" } ,
  428. { SM_ENDURE, "ENDURE", "Endure" } ,
  429. { SM_FATALBLOW, "FATALBLOW", "Attack_Weak_Point" } ,
  430. { SM_MAGNUM, "MAGNUM", "Magnum_Break" } ,
  431. { SM_MOVINGRECOVERY, "MOVINGRECOVERY", "Moving_HP_Recovery" } ,
  432. { SM_PROVOKE, "PROVOKE", "Provoke" } ,
  433. { SM_RECOVERY, "RECOVERY", "Increase_HP_Recovery" } ,
  434. { SM_SWORD, "SWORD", "Sword_Mastery" } ,
  435. { SM_TWOHAND, "TWOHAND", "Two-Handed_Sword_Mastery" } ,
  436. { SN_FALCONASSAULT, "FALCONASSAULT", "Falcon_Assault" } ,
  437. { SN_SHARPSHOOTING, "SHARPSHOOTING", "Sharpshooting" } ,
  438. { SN_SIGHT, "SIGHT", "True_Sight" } ,
  439. { SN_WINDWALK, "WINDWALK", "Wind_Walk" } ,
  440. { ST_CHASEWALK, "CHASEWALK", "Chase_Walk" } ,
  441. { ST_REJECTSWORD, "REJECTSWORD", "Reject_Sword" } ,
  442. { ST_STEALBACKPACK, "STEALBACKPACK", "Steal_Backpack" } ,
  443. { ST_PRESERVE, "PRESERVE", "Preserve" } ,
  444. { ST_FULLSTRIP, "FULLSTRIP", "Full_Strip" } ,
  445. { TF_BACKSLIDING, "BACKSLIDING", "Back_Sliding" } ,
  446. { TF_DETOXIFY, "DETOXIFY", "Detoxify" } ,
  447. { TF_DOUBLE, "DOUBLE", "Double_Attack" } ,
  448. { TF_HIDING, "HIDING", "Hiding" } ,
  449. { TF_MISS, "MISS", "Improve_Dodge" } ,
  450. { TF_PICKSTONE, "PICKSTONE", "Take_Stone" } ,
  451. { TF_POISON, "POISON", "Envenom" } ,
  452. { TF_SPRINKLESAND, "SPRINKLESAND", "Throw_Sand" } ,
  453. { TF_STEAL, "STEAL", "Steal" } ,
  454. { TF_THROWSTONE, "THROWSTONE", "Throw_Stone" } ,
  455. { TK_COUNTER, "COUNTER", "Counter" } ,
  456. { TK_DODGE, "DODGE", "Dodge" } ,
  457. { TK_DOWNKICK, "DOWNKICK", "Down Kick" } ,
  458. { TK_HIGHJUMP, "HIGHJUMP", "High Jump" } ,
  459. { TK_HPTIME, "HPTIME", "HP Time" } ,
  460. { TK_JUMPKICK, "JUMPKICK", "Jump Kick" } ,
  461. { TK_POWER, "POWER", "Power" } ,
  462. { TK_READYCOUNTER, "READYCOUNTER", "Ready Counter" } ,
  463. { TK_READYDOWN, "READYDOWN", "Ready Down" } ,
  464. { TK_READYSTORM, "READYSTORM", "Ready Storm" } ,
  465. { TK_READYTURN, "READYTURN", "Ready Turn" } ,
  466. { TK_RUN, "RUN", "TK_RUN" } ,
  467. { TK_SEVENWIND, "SEVENWIND", "Seven Wind" } ,
  468. { TK_SPTIME, "SPTIME", "SP Time" } ,
  469. { TK_STORMKICK, "STORMKICK", "Storm Kick" } ,
  470. { TK_TURNKICK, "TURNKICK", "Turn Kick" } ,
  471. { WE_BABY, "BABY", "Adopt_Baby" } ,
  472. { WE_CALLBABY, "CALLBABY", "Call_Baby" } ,
  473. { WE_CALLPARENT, "CALLPARENT", "Call_Parent" } ,
  474. { WE_CALLPARTNER, "CALLPARTNER", "I Want to See You" } ,
  475. { WE_FEMALE, "FEMALE", "I Only Look Up to You" } ,
  476. { WE_MALE, "MALE", "I Will Protect You" } ,
  477. { WS_CARTBOOST, "CARTBOOST", "Cart_Boost" } ,
  478. { WS_CREATECOIN, "CREATECOIN", "Create_Coins" } ,
  479. { WS_CREATENUGGET, "CREATENUGGET", "Create_Nuggets" } ,
  480. { WS_MELTDOWN, "MELTDOWN", "Meltdown" } ,
  481. { WS_SYSTEMCREATE, "SYSTEMCREATE", "Create_System_tower" } ,
  482. { WS_WEAPONREFINE, "WEAPONREFINE", "Weapon_Refine" } ,
  483. { WZ_EARTHSPIKE, "EARTHSPIKE", "Earth_Spike" } ,
  484. { WZ_ESTIMATION, "ESTIMATION", "Sense" } ,
  485. { WZ_FIREIVY, "FIREIVY", "Fire_Ivy" } ,
  486. { WZ_FIREPILLAR, "FIREPILLAR", "Fire_Pillar" } ,
  487. { WZ_FROSTNOVA, "FROSTNOVA", "Frost_Nova" } ,
  488. { WZ_HEAVENDRIVE, "HEAVENDRIVE", "Heaven's_Drive" } ,
  489. { WZ_ICEWALL, "ICEWALL", "Ice_Wall" } ,
  490. { WZ_JUPITEL, "JUPITEL", "Jupitel_Thunder" } ,
  491. { WZ_METEOR, "METEOR", "Meteor_Storm" } ,
  492. { WZ_QUAGMIRE, "QUAGMIRE", "Quagmire" } ,
  493. { WZ_SIGHTRASHER, "SIGHTRASHER", "Sightrasher" } ,
  494. { WZ_STORMGUST, "STORMGUST", "Storm_Gust" } ,
  495. { WZ_VERMILION, "VERMILION", "Lord_of_Vermilion" } ,
  496. { WZ_WATERBALL, "WATERBALL", "Water_Ball" } ,
  497. { 0, 0, 0 }
  498. };
  499. static const int dirx[8]={0,-1,-1,-1,0,1,1,1};
  500. static const int diry[8]={1,1,0,-1,-1,-1,0,1};
  501. static int rdamage;
  502. /* スキルデ?タベ?ス */
  503. struct skill_db skill_db[MAX_SKILL_DB];
  504. /* アイテム作成デ?タベ?ス */
  505. struct skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB];
  506. /* 矢作成スキルデ?タベ?ス */
  507. struct skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB];
  508. /* アブラカダブラ?動スキルデ?タベ?ス */
  509. struct skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB];
  510. // macros to check for out of bounds errors [celest]
  511. // i: Skill ID, l: Skill Level, var: Value to return after checking
  512. // for values that don't require level just put a one (putting 0 will trigger return 0; instead
  513. // for values that might need to use a different function just skill_chk would suffice.
  514. #define skill_chk(i, l) \
  515. if (i >= 10000 && i < 10015) {i -= 9500;} \
  516. if (i < 1 || i > MAX_SKILL_DB) {return 0;} \
  517. if (l <= 0 || l > MAX_SKILL_LEVEL) {return 0;}
  518. #define skill_get(var, i, l) \
  519. { skill_chk(i, l); return var; }
  520. // Skill DB
  521. int skill_get_hit( int id ){ skill_get (skill_db[id].hit, id, 1); }
  522. int skill_get_inf( int id ){ skill_chk (id, 1); return (id < 500) ? skill_db[id].inf : guild_skill_get_inf(id); }
  523. int skill_get_pl( int id ){ skill_get (skill_db[id].pl, id, 1); }
  524. int skill_get_nk( int id ){ skill_get (skill_db[id].nk, id, 1); }
  525. int skill_get_max( int id ){ skill_chk (id, 1); return (id < 500) ? skill_db[id].max : guild_skill_get_max(id); }
  526. int skill_get_range( int id , int lv ){ skill_chk (id, lv); return (id < 500) ? skill_db[id].range[lv-1] : guild_skill_get_range(id); }
  527. int skill_get_hp( int id ,int lv ){ skill_get (skill_db[id].hp[lv-1], id, lv); }
  528. int skill_get_sp( int id ,int lv ){ skill_get (skill_db[id].sp[lv-1], id, lv); }
  529. int skill_get_zeny( int id ,int lv ){ skill_get (skill_db[id].zeny[lv-1], id, lv); }
  530. int skill_get_num( int id ,int lv ){ skill_get (skill_db[id].num[lv-1], id, lv); }
  531. int skill_get_cast( int id ,int lv ){ skill_get (skill_db[id].cast[lv-1], id, lv); }
  532. int skill_get_delay( int id ,int lv ){ skill_get (skill_db[id].delay[lv-1], id, lv); }
  533. int skill_get_time( int id ,int lv ){ skill_get (skill_db[id].upkeep_time[lv-1], id, lv); }
  534. int skill_get_time2( int id ,int lv ){ skill_get (skill_db[id].upkeep_time2[lv-1], id, lv); }
  535. int skill_get_castdef( int id ){ skill_get (skill_db[id].cast_def_rate, id, 1); }
  536. int skill_get_weapontype( int id ){ skill_get (skill_db[id].weapon, id, 1); }
  537. int skill_get_inf2( int id ){ skill_get (skill_db[id].inf2, id, 1); }
  538. int skill_get_castcancel( int id ){ skill_get (skill_db[id].castcancel, id, 1); }
  539. int skill_get_maxcount( int id ){ skill_get (skill_db[id].maxcount, id, 1); }
  540. int skill_get_blewcount( int id ,int lv ){ skill_get (skill_db[id].blewcount[lv-1], id, lv); }
  541. int skill_get_mhp( int id ,int lv ){ skill_get (skill_db[id].mhp[lv-1], id, lv); }
  542. int skill_get_castnodex( int id ,int lv ){ skill_get (skill_db[id].castnodex[lv-1], id, lv); }
  543. int skill_get_delaynodex( int id ,int lv ){ skill_get (skill_db[id].delaynodex[lv-1], id, lv); }
  544. int skill_get_nocast ( int id ){ skill_get (skill_db[id].nocast, id, 1); }
  545. int skill_get_unit_id ( int id, int flag ){ skill_get (skill_db[id].unit_id[flag], id, 1); }
  546. int skill_get_unit_layout_type( int id ,int lv ){ skill_get (skill_db[id].unit_layout_type[lv-1], id, lv); }
  547. int skill_get_unit_interval( int id ){ skill_get (skill_db[id].unit_interval, id, 1); }
  548. int skill_get_unit_range( int id ){ skill_get (skill_db[id].unit_range, id, 1); }
  549. int skill_get_unit_target( int id ){ skill_get (skill_db[id].unit_target, id, 1); }
  550. int skill_get_unit_flag( int id ){ skill_get (skill_db[id].unit_flag, id, 1); }
  551. int skill_tree_get_max(int id, int b_class){
  552. struct pc_base_job s_class = pc_calc_base_job(b_class);
  553. int i, skillid;
  554. for(i=0;(skillid=skill_tree[s_class.upper][s_class.job][i].id)>0;i++)
  555. if (id == skillid) return skill_tree[s_class.upper][s_class.job][i].max;
  556. return skill_get_max (id);
  557. }
  558. /* プロトタイプ */
  559. //struct skill_unit_group *skill_unitsetting( struct block_list *src, int skillid,int skilllv,int x,int y,int flag);
  560. int skill_check_condition( struct map_session_data *sd,int type);
  561. int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
  562. int skill_frostjoke_scream(struct block_list *bl,va_list ap);
  563. int status_change_timer_sub(struct block_list *bl, va_list ap );
  564. int skill_attack_area(struct block_list *bl,va_list ap);
  565. int skill_abra_dataset(int skilllv);
  566. int skill_clear_element_field(struct block_list *bl);
  567. int skill_landprotector(struct block_list *bl, va_list ap );
  568. int skill_trap_splash(struct block_list *bl, va_list ap );
  569. int skill_count_target(struct block_list *bl, va_list ap );
  570. struct skill_unit_group_tickset *skill_unitgrouptickset_search(struct block_list *bl,struct skill_unit_group *sg,int tick);
  571. int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int tick);
  572. int skill_unit_effect(struct block_list *bl,va_list ap);
  573. // [MouseJstr] - skill ok to cast? and when?
  574. int skillnotok(int skillid, struct map_session_data *sd)
  575. {
  576. nullpo_retr (1, sd);
  577. //if (sd == 0)
  578. //return 0;
  579. //return 1;
  580. // I think it was meant to be "no skills allowed when not a valid sd"
  581. if (!(skillid >= 10000 && skillid < 10015))
  582. if ((skillid > MAX_SKILL) || (skillid < 0))
  583. return 1;
  584. {
  585. int i = skillid;
  586. if (i >= 10000 && i < 10015)
  587. i -= 9500;
  588. if (sd->blockskill[i] > 0)
  589. return 1;
  590. }
  591. if (pc_isGM(sd) >= 20)
  592. return 0; // gm's can do anything damn thing they want
  593. // Check skill restrictions [Celest]
  594. if(!map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.gvg && skill_get_nocast (skillid) & 1)
  595. return 1;
  596. if(map[sd->bl.m].flag.pvp && skill_get_nocast (skillid) & 2)
  597. return 1;
  598. if(map[sd->bl.m].flag.gvg && skill_get_nocast (skillid) & 4)
  599. return 1;
  600. if (agit_flag && skill_get_nocast (skillid) & 8)
  601. return 1;
  602. if (battle_config.pk_mode && !map[sd->bl.m].flag.nopvp && skill_get_nocast (skillid) & 16)
  603. return 1;
  604. switch (skillid) {
  605. case AL_WARP:
  606. case AL_TELEPORT:
  607. case MC_VENDING:
  608. case MC_IDENTIFY:
  609. return 0; // always allowed
  610. default:
  611. return(map[sd->bl.m].flag.noskill);
  612. }
  613. }
  614. static int distance(int x0,int y0,int x1,int y1)
  615. {
  616. int dx,dy;
  617. dx=abs(x0-x1);
  618. dy=abs(y0-y1);
  619. return dx>dy ? dx : dy;
  620. }
  621. /* スキルユニットの配置情報を返す */
  622. struct skill_unit_layout skill_unit_layout[MAX_SKILL_UNIT_LAYOUT];
  623. int firewall_unit_pos;
  624. int icewall_unit_pos;
  625. struct skill_unit_layout *skill_get_unit_layout(int skillid,int skilllv,struct block_list *src,int x,int y)
  626. {
  627. int pos = skill_get_unit_layout_type(skillid,skilllv);
  628. int dir;
  629. if (pos!=-1)
  630. return &skill_unit_layout[pos];
  631. if (src->x==x && src->y==y)
  632. dir = 2;
  633. else
  634. dir = map_calc_dir(src,x,y);
  635. if (skillid==MG_FIREWALL)
  636. return &skill_unit_layout[firewall_unit_pos+dir];
  637. else if (skillid==WZ_ICEWALL)
  638. return &skill_unit_layout[icewall_unit_pos+dir];
  639. printf("unknown unit layout for skill %d, %d\n",skillid,skilllv);
  640. return &skill_unit_layout[0];
  641. }
  642. // 0x89,0x8a,0x8b 表示無し
  643. // 0x9a 炎?性の詠唱みたいなエフェクト
  644. // 0x9b 水?性の詠唱みたいなエフェクト
  645. // 0x9c 風?性の詠唱みたいなエフェクト
  646. // 0x9d 白い小さなエフェクト
  647. // 0xb1 Alchemist Demonstration
  648. // 0xb2 = Pink Warp Portal
  649. // 0xb3 = Gospel For Paladin
  650. // 0xb4 = Basilica
  651. // 0xb5 = Empty
  652. // 0xb6 = Fog Wall for Professor
  653. // 0xb7 = Spider Web for Professor
  654. // 0xb8 = Empty
  655. // 0xb9 =
  656. /*==========================================
  657. * スキル追加?果
  658. *------------------------------------------
  659. */
  660. int skill_additional_effect( struct block_list* src, struct block_list *bl,int skillid,int skilllv,int attack_type,unsigned int tick)
  661. {
  662. /* MOB追加?果スキル用 */
  663. const int sc[]={
  664. SC_POISON, SC_BLIND, SC_SILENCE, SC_STAN,
  665. SC_STONE, SC_CURSE, SC_SLEEP
  666. };
  667. const int sc2[]={
  668. MG_STONECURSE,MG_FROSTDIVER,NPC_STUNATTACK,
  669. NPC_SLEEPATTACK,TF_POISON,NPC_CURSEATTACK,
  670. NPC_SILENCEATTACK,0,NPC_BLINDATTACK
  671. };
  672. struct map_session_data *sd=NULL;
  673. struct map_session_data *dstsd=NULL;
  674. struct mob_data *md=NULL;
  675. struct mob_data *dstmd=NULL;
  676. struct pet_data *pd=NULL;
  677. int skill,skill2;
  678. int rate;
  679. int sc_def_mdef,sc_def_vit,sc_def_int,sc_def_luk;
  680. int sc_def_mdef2,sc_def_vit2,sc_def_int2,sc_def_luk2;
  681. nullpo_retr(0, src);
  682. nullpo_retr(0, bl);
  683. if(skillid < 0)
  684. { // remove the debug print when this case is finished
  685. printf("skill_additional_effect: skillid=%i\ncall: %p %p %i %i %i %i",skillid,
  686. src, bl,skillid,skilllv,attack_type,tick);
  687. return 0;
  688. }
  689. if(skillid > 0 && skilllv <= 0) return 0; // don't forget auto attacks! - celest
  690. if (src->type == BL_PC){
  691. nullpo_retr(0, sd = (struct map_session_data *)src);
  692. } else if (src->type == BL_MOB){
  693. nullpo_retr(0, md = (struct mob_data *)src); //未使用?
  694. } else if (src->type == BL_PET){
  695. nullpo_retr(0, pd = (struct pet_data *)src); // [Valaris]
  696. }
  697. if(bl->type == BL_PC) {
  698. nullpo_retr(0, dstsd=(struct map_session_data *)bl);
  699. } else if(bl->type == BL_MOB) {
  700. nullpo_retr(0, dstmd=(struct mob_data *)bl); //未使用?
  701. }
  702. //?象の耐性
  703. sc_def_mdef = status_get_sc_def_mdef(bl);
  704. sc_def_vit = status_get_sc_def_vit(bl);
  705. sc_def_int = status_get_sc_def_int(bl);
  706. sc_def_luk = status_get_sc_def_luk(bl);
  707. //自分の耐性
  708. sc_def_mdef2 = status_get_sc_def_mdef(src);
  709. sc_def_vit2 = status_get_sc_def_vit(src);
  710. sc_def_int2 = status_get_sc_def_int(src);
  711. sc_def_luk2 = status_get_sc_def_luk(src);
  712. switch(skillid){
  713. case 0: /* 通常攻? */
  714. /* 自動鷹 */
  715. if( sd && pc_isfalcon(sd) && sd->status.weapon == 11 && (skill=pc_checkskill(sd,HT_BLITZBEAT))>0 &&
  716. rand()%1000 <= sd->paramc[5]*10/3+1 ) {
  717. int lv=(sd->status.job_level+9)/10;
  718. skill_castend_damage_id(src,bl,HT_BLITZBEAT,(skill<lv)?skill:lv,tick,0xf00000);
  719. }
  720. // スナッチャ?
  721. if(sd && sd->status.weapon != 11 && (skill=pc_checkskill(sd,RG_SNATCHER)) > 0)
  722. if((skill*15 + 55) + (skill2 = pc_checkskill(sd,TF_STEAL))*10 > rand()%1000) {
  723. if(pc_steal_item(sd,bl))
  724. clif_skill_nodamage(src,bl,TF_STEAL,skill2,1);
  725. else if (battle_config.display_snatcher_skill_fail)
  726. clif_skill_fail(sd,skillid,0,0);
  727. }
  728. // エンチャントデットリ?ポイズン(猛毒?果)
  729. if (sd && sd->sc_data[SC_EDP].timer != -1 && rand() % 10000 < sd->sc_data[SC_EDP].val2 * sc_def_vit) {
  730. int mhp = status_get_max_hp(bl);
  731. int hp = status_get_hp(bl);
  732. int lvl = sd->sc_data[SC_EDP].val1;
  733. int diff;
  734. // MHPの1/4以下にはならない
  735. if(hp > mhp>>2) {
  736. if(bl->type == BL_PC) {
  737. diff = mhp*10/100;
  738. if (hp - diff < mhp>>2)
  739. diff = hp - (mhp>>2);
  740. pc_heal(dstsd, -hp, 0);
  741. } else if(bl->type == BL_MOB) {
  742. struct mob_data *md = (struct mob_data *)bl;
  743. hp -= mhp*15/100;
  744. if (hp > mhp>>2)
  745. md->hp = hp;
  746. else
  747. md->hp = mhp>>2;
  748. }
  749. }
  750. status_change_start(bl,SC_DPOISON,lvl,0,0,0,skill_get_time2(ASC_EDP,lvl),0);
  751. }
  752. break;
  753. case SM_BASH: /* バッシュ(急所攻?) */
  754. if( sd && (skill=pc_checkskill(sd,SM_FATALBLOW))>0 ){
  755. if( rand()%100 < 6*(skilllv-5)*sc_def_vit/100 )
  756. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(SM_FATALBLOW,skilllv),0);
  757. }
  758. break;
  759. case TF_POISON: /* インベナム */
  760. case AS_SPLASHER: /* ベナムスプラッシャ? */
  761. if(rand()%100< (2*skilllv+10)*sc_def_vit/100 )
  762. status_change_start(bl,SC_POISON,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  763. else{
  764. if(sd && skillid==TF_POISON)
  765. clif_skill_fail(sd,skillid,0,0);
  766. }
  767. break;
  768. case AS_SONICBLOW: /* ソニックブロ? */
  769. if( rand()%100 < (2*skilllv+10)*sc_def_vit/100 )
  770. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  771. break;
  772. case HT_FREEZINGTRAP: /* フリ?ジングトラップ */
  773. rate=skilllv*3+35;
  774. if(rand()%100 < rate*sc_def_mdef/100)
  775. status_change_start(bl,SC_FREEZE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  776. break;
  777. case MG_FROSTDIVER: /* フロストダイバ? */
  778. case WZ_FROSTNOVA: /* フロストノヴァ */
  779. rate=(skilllv*3+35)*sc_def_mdef/100-(status_get_int(bl)+status_get_luk(bl))/15;
  780. rate=rate<=5?5:rate;
  781. if(rand()%100 < rate)
  782. status_change_start(bl,SC_FREEZE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  783. else if(sd && skillid==MG_FROSTDIVER)
  784. clif_skill_fail(sd,skillid,0,0);
  785. break;
  786. case WZ_STORMGUST: /* スト?ムガスト */
  787. {
  788. struct status_change *sc_data = status_get_sc_data(bl);
  789. if(sc_data) {
  790. sc_data[SC_FREEZE].val3++;
  791. if(sc_data[SC_FREEZE].val3 >= 3)
  792. status_change_start(bl,SC_FREEZE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  793. }
  794. }
  795. break;
  796. case HT_LANDMINE: /* ランドマイン */
  797. if( rand()%100 < (5*skilllv+30)*sc_def_vit/100 )
  798. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  799. break;
  800. case HT_SHOCKWAVE: /* ショックウェ?ブトラップ */
  801. if(map[bl->m].flag.pvp && dstsd){
  802. dstsd->status.sp -= dstsd->status.sp*(5+15*skilllv)/100;
  803. status_calc_pc(dstsd,0);
  804. }
  805. break;
  806. case HT_SANDMAN: /* サンドマン */
  807. if( rand()%100 < (5*skilllv+30)*sc_def_int/100 )
  808. status_change_start(bl,SC_SLEEP,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  809. break;
  810. case TF_SPRINKLESAND: /* 砂まき */
  811. if( rand()%100 < 20*sc_def_int/100 )
  812. status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  813. break;
  814. case TF_THROWSTONE: /* 石投げ */
  815. if( rand()%100 < 7*sc_def_vit/100 )
  816. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  817. break;
  818. case CR_HOLYCROSS: /* ホ?リ?クロス */
  819. if( rand()%100 < 3*skilllv*sc_def_int/100 )
  820. status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  821. break;
  822. case CR_GRANDCROSS: /* グランドクロス */
  823. case NPC_DARKGRANDCROSS: /*闇グランドクロス*/
  824. {
  825. int race = status_get_race(bl);
  826. if( (battle_check_undead(race,status_get_elem_type(bl)) || race == 6) && rand()%100 < 100000*sc_def_int/100) //?制付?だが完全耐性には無?
  827. status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  828. }
  829. break;
  830. case AM_ACIDTERROR:
  831. if( rand()%100 < (skilllv*3)*sc_def_vit/100 )
  832. status_change_start(bl,SC_BLEEDING,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  833. break;
  834. case CR_SHIELDCHARGE: /* シ?ルドチャ?ジ */
  835. if( rand()%100 < (15 + skilllv*5)*sc_def_vit/100 )
  836. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  837. break;
  838. case RG_RAID: /* サプライズアタック */
  839. if( rand()%100 < (10+3*skilllv)*sc_def_vit/100 )
  840. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  841. if( rand()%100 < (10+3*skilllv)*sc_def_int/100 )
  842. status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  843. break;
  844. case BA_FROSTJOKE:
  845. if(rand()%100 < (15+5*skilllv)*sc_def_mdef/100)
  846. status_change_start(bl,SC_FREEZE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  847. break;
  848. case DC_SCREAM:
  849. if( rand()%100 < (25+5*skilllv)*sc_def_vit/100 )
  850. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  851. break;
  852. case BD_LULLABY: /* 子守唄 */
  853. if( rand()%100 < 15*sc_def_int/100 )
  854. status_change_start(bl,SC_SLEEP,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  855. break;
  856. /* MOBの追加?果付きスキル */
  857. case NPC_PETRIFYATTACK:
  858. if(rand()%100 < sc_def_mdef)
  859. status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  860. break;
  861. case NPC_POISON:
  862. case NPC_SILENCEATTACK:
  863. case NPC_STUNATTACK:
  864. if(rand()%100 < sc_def_vit && src->type!=BL_PET)
  865. status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  866. if(src->type==BL_PET)
  867. status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skilllv*1000,0);
  868. break;
  869. case NPC_CURSEATTACK:
  870. if(rand()%100 < sc_def_luk)
  871. status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  872. break;
  873. case NPC_SLEEPATTACK:
  874. case NPC_BLINDATTACK:
  875. if(rand()%100 < sc_def_int)
  876. status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  877. break;
  878. case NPC_MENTALBREAKER:
  879. if(dstsd) {
  880. int sp = dstsd->status.max_sp*(10+skilllv)/100;
  881. if(sp < 1) sp = 1;
  882. pc_heal(dstsd,0,-sp);
  883. }
  884. break;
  885. // -- moonsoul (adding status effect chance given to wizard aoe skills meteor and vermillion)
  886. //
  887. case WZ_METEOR:
  888. if(rand()%100 < sc_def_vit)
  889. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  890. break;
  891. case WZ_VERMILION:
  892. if(rand()%100 < sc_def_int)
  893. status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  894. break;
  895. // -- moonsoul (stun ability of new champion skill tigerfist)
  896. //
  897. case CH_TIGERFIST:
  898. if( rand()%100 < (10 + skilllv*10)*sc_def_vit/100 ) {
  899. int sec = skill_get_time2 (skillid,skilllv) - status_get_agi(bl)/10;
  900. status_change_start(bl,SC_STAN,skilllv,0,0,0,sec,0);
  901. }
  902. break;
  903. case LK_SPIRALPIERCE:
  904. if( rand()%100 < (15 + skilllv*5)*sc_def_vit/100 )
  905. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  906. break;
  907. case ST_REJECTSWORD: /* フリ?ジングトラップ */
  908. if( rand()%100 < (skilllv*15) )
  909. status_change_start(bl,SC_AUTOCOUNTER,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  910. break;
  911. case PF_FOGWALL: /* ホ?リ?クロス */
  912. if(src!=bl && rand()%100 < 3*skilllv*sc_def_int/100 )
  913. status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  914. break;
  915. case LK_HEADCRUSH: /* ヘッドクラッシュ */
  916. {//?件が良く分からないので適?に
  917. int race=status_get_race(bl);
  918. if( !(battle_check_undead(race,status_get_elem_type(bl)) || race == 6) && rand()%100 < (2*skilllv+10)*sc_def_vit/100 )
  919. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  920. }
  921. break;
  922. case LK_JOINTBEAT: /* ジョイントビ?ト */
  923. //?件が良く分からないので適?に
  924. if( rand()%100 < (5*skilllv+5)*sc_def_vit/100 )
  925. status_change_start(bl,SC_JOINTBEAT,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  926. break;
  927. case PF_SPIDERWEB: /* スパイダ?ウェッブ */
  928. {
  929. if(bl->type == BL_MOB)
  930. {
  931. int sec=skill_get_time2(skillid,skilllv);
  932. if(map[src->m].flag.pvp) //PvPでは拘束時間半減?
  933. sec = sec/2;
  934. battle_stopwalking(bl,1);
  935. status_change_start(bl,SC_SPIDERWEB,skilllv,0,0,0,sec,0);
  936. }
  937. }
  938. break;
  939. case ASC_METEORASSAULT: /* メテオアサルト */
  940. if( rand()%100 < (15 + skilllv*5)*sc_def_vit/100 ) //?態異常は詳細が分からないので適?に
  941. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  942. if( rand()%100 < (10+3*skilllv)*sc_def_int/100 )
  943. status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  944. break;
  945. case MO_EXTREMITYFIST: /* 阿修羅覇凰拳 */
  946. //阿修羅を使うと5分間自然回復しないようになる
  947. status_change_start(src,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0 );
  948. break;
  949. case HW_NAPALMVULCAN: /* ナパ?ムバルカン */
  950. // skilllv*5%の確率で呪い
  951. if (rand()%10000 < 5*skilllv*sc_def_luk)
  952. status_change_start(bl,SC_CURSE,7,0,0,0,skill_get_time2(NPC_CURSEATTACK,7),0);
  953. break;
  954. }
  955. if((sd||dstsd) && skillid != MC_CARTREVOLUTION && attack_type&BF_WEAPON){ /* カ?ドによる追加?果 */
  956. int i;
  957. int sc_def_card=100;
  958. for(i=SC_STONE;i<=SC_BLIND;i++){
  959. //?象に?態異常
  960. switch (i) {
  961. case SC_STONE:
  962. case SC_FREEZE:
  963. sc_def_card=sc_def_mdef;
  964. break;
  965. case SC_STAN:
  966. case SC_POISON:
  967. case SC_SILENCE:
  968. sc_def_card=sc_def_vit;
  969. break;
  970. case SC_SLEEP:
  971. case SC_CONFUSION:
  972. case SC_BLIND:
  973. sc_def_card=sc_def_int;
  974. break;
  975. case SC_CURSE:
  976. sc_def_card=sc_def_luk;
  977. }
  978. if (sd) {
  979. if(!sd->state.arrow_atk) {
  980. if(rand()%10000 < (sd->addeff[i-SC_STONE])*sc_def_card/100 ){
  981. if(battle_config.battle_log)
  982. printf("PC %d skill_addeff: cardによる異常?動 %d %d\n",sd->bl.id,i,sd->addeff[i-SC_STONE]);
  983. status_change_start(bl,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
  984. }
  985. }
  986. else {
  987. if(rand()%10000 < (sd->addeff[i-SC_STONE]+sd->arrow_addeff[i-SC_STONE])*sc_def_card/100 ){
  988. if(battle_config.battle_log)
  989. printf("PC %d skill_addeff: cardによる異常?動 %d %d\n",sd->bl.id,i,sd->addeff[i-SC_STONE]);
  990. status_change_start(bl,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
  991. }
  992. }
  993. }
  994. //自分に?態異常
  995. switch (i) {
  996. case SC_STONE:
  997. case SC_FREEZE:
  998. sc_def_card=sc_def_mdef2;
  999. break;
  1000. case SC_STAN:
  1001. case SC_POISON:
  1002. case SC_SILENCE:
  1003. sc_def_card=sc_def_vit2;
  1004. break;
  1005. case SC_SLEEP:
  1006. case SC_CONFUSION:
  1007. case SC_BLIND:
  1008. sc_def_card=sc_def_int2;
  1009. break;
  1010. case SC_CURSE:
  1011. sc_def_card=sc_def_luk2;
  1012. }
  1013. if (sd) {
  1014. if(!sd->state.arrow_atk) {
  1015. if(rand()%10000 < (sd->addeff2[i-SC_STONE])*sc_def_card/100 ){
  1016. if(battle_config.battle_log)
  1017. printf("PC %d skill_addeff: cardによる異常?動 %d %d\n",src->id,i,sd->addeff2[i-SC_STONE]);
  1018. status_change_start(src,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
  1019. }
  1020. }
  1021. else {
  1022. if(rand()%10000 < (sd->addeff2[i-SC_STONE]+sd->arrow_addeff2[i-SC_STONE])*sc_def_card/100 ){
  1023. if(battle_config.battle_log)
  1024. printf("PC %d skill_addeff: cardによる異常?動 %d %d\n",src->id,i,sd->addeff2[i-SC_STONE]);
  1025. status_change_start(src,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
  1026. }
  1027. }
  1028. }
  1029. if (dstsd &&
  1030. rand()%10000 < dstsd->addeff3[i-SC_STONE]*sc_def_card/100){
  1031. if(battle_config.battle_log)
  1032. printf("PC %d skill_addeff: cardによる異常?動 %d %d\n",src->id,i,dstsd->addeff3[i-SC_STONE]);
  1033. status_change_start(src,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
  1034. }
  1035. }
  1036. }
  1037. return 0;
  1038. }
  1039. /*=========================================================================
  1040. スキル攻?吹き飛ばし?理
  1041. -------------------------------------------------------------------------*/
  1042. int skill_blown( struct block_list *src, struct block_list *target,int count)
  1043. {
  1044. int dx=0,dy=0,nx,ny;
  1045. int x=target->x,y=target->y;
  1046. int dir,ret,prev_state=MS_IDLE;
  1047. int moveblock;
  1048. struct map_session_data *sd=NULL;
  1049. struct mob_data *md=NULL;
  1050. struct pet_data *pd=NULL;
  1051. struct skill_unit *su=NULL;
  1052. nullpo_retr(0, src);
  1053. nullpo_retr(0, target);
  1054. if(target->type==BL_PC){
  1055. sd=(struct map_session_data *)target;
  1056. }else if(target->type==BL_MOB){
  1057. md=(struct mob_data *)target;
  1058. }else if(target->type==BL_PET){
  1059. pd=(struct pet_data *)target;
  1060. }else if(target->type==BL_SKILL){
  1061. su=(struct skill_unit *)target;
  1062. }else return 0;
  1063. if (count&0xf00000)
  1064. dir = (count>>20)&0xf;
  1065. else if (count&0x10000 || (target->x==src->x && target->y==src->y))
  1066. dir = status_get_dir(target);
  1067. else
  1068. dir = map_calc_dir(target,src->x,src->y);
  1069. if (dir>=0 && dir<8){
  1070. dx = -dirx[dir];
  1071. dy = -diry[dir];
  1072. }
  1073. ret=path_blownpos(target->m,x,y,dx,dy,count&0xffff);
  1074. nx=ret>>16;
  1075. ny=ret&0xffff;
  1076. moveblock=( x/BLOCK_SIZE != nx/BLOCK_SIZE || y/BLOCK_SIZE != ny/BLOCK_SIZE);
  1077. if(count&0x20000) {
  1078. battle_stopwalking(target,1);
  1079. if(sd){
  1080. sd->to_x=nx;
  1081. sd->to_y=ny;
  1082. sd->walktimer = 1;
  1083. clif_walkok(sd);
  1084. clif_movechar(sd);
  1085. }
  1086. else if(md) {
  1087. md->to_x=nx;
  1088. md->to_y=ny;
  1089. prev_state = md->state.state;
  1090. md->state.state = MS_WALK;
  1091. clif_fixmobpos(md);
  1092. }
  1093. else if(pd) {
  1094. pd->to_x=nx;
  1095. pd->to_y=ny;
  1096. prev_state = pd->state.state;
  1097. pd->state.state = MS_WALK;
  1098. clif_fixpetpos(pd);
  1099. }
  1100. }
  1101. else
  1102. battle_stopwalking(target,2);
  1103. dx = nx - x;
  1104. dy = ny - y;
  1105. if(sd) /* ?面外に出たので消去 */
  1106. map_foreachinmovearea(clif_pcoutsight,target->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,0,sd);
  1107. else if(md)
  1108. map_foreachinmovearea(clif_moboutsight,target->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,md);
  1109. else if(pd)
  1110. map_foreachinmovearea(clif_petoutsight,target->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,pd);
  1111. if(su){
  1112. skill_unit_move_unit_group(su->group,target->m,dx,dy);
  1113. }else{
  1114. int tick = gettick();
  1115. skill_unit_move(target,tick,0);
  1116. if(moveblock) map_delblock(target);
  1117. target->x=nx;
  1118. target->y=ny;
  1119. if(moveblock) map_addblock(target);
  1120. skill_unit_move(target,tick,1);
  1121. }
  1122. if(sd) { /* ?面?に入ってきたので表示 */
  1123. map_foreachinmovearea(clif_pcinsight,target->m,nx-AREA_SIZE,ny-AREA_SIZE,nx+AREA_SIZE,ny+AREA_SIZE,-dx,-dy,0,sd);
  1124. if(count&0x20000)
  1125. sd->walktimer = -1;
  1126. }
  1127. else if(md) {
  1128. map_foreachinmovearea(clif_mobinsight,target->m,nx-AREA_SIZE,ny-AREA_SIZE,nx+AREA_SIZE,ny+AREA_SIZE,-dx,-dy,BL_PC,md);
  1129. if(count&0x20000)
  1130. md->state.state = prev_state;
  1131. }
  1132. else if(pd) {
  1133. map_foreachinmovearea(clif_petinsight,target->m,nx-AREA_SIZE,ny-AREA_SIZE,nx+AREA_SIZE,ny+AREA_SIZE,-dx,-dy,BL_PC,pd);
  1134. if(count&0x20000)
  1135. pd->state.state = prev_state;
  1136. }
  1137. return 0;
  1138. }
  1139. /*
  1140. * =========================================================================
  1141. * スキル攻??果?理まとめ
  1142. * flagの?明。16進?
  1143. * 00XRTTff
  1144. * ff = magicで計算に渡される)
  1145. * TT = パケットのtype部分(0でデフォルト)
  1146. * X = パケットのスキルLv
  1147. * R = 予約(skill_area_subで使用する)
  1148. *-------------------------------------------------------------------------
  1149. */
  1150. int skill_attack( int attack_type, struct block_list* src, struct block_list *dsrc,
  1151. struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag )
  1152. {
  1153. struct Damage dmg;
  1154. struct status_change *sc_data;
  1155. int type,lv,damage;
  1156. if(skillid > 0 && skilllv <= 0) return 0;
  1157. rdamage = 0;
  1158. nullpo_retr(0, src);
  1159. nullpo_retr(0, dsrc);
  1160. nullpo_retr(0, bl);
  1161. sc_data = status_get_sc_data(bl);
  1162. //何もしない判定ここから
  1163. if(dsrc->m != bl->m) //?象が同じマップにいなければ何もしない
  1164. return 0;
  1165. if(src->prev == NULL || dsrc->prev == NULL || bl->prev == NULL) //prevよくわからない※
  1166. return 0;
  1167. if(src->type == BL_PC && pc_isdead((struct map_session_data *)src)) //術者?がPCですでに死んでいたら何もしない
  1168. return 0;
  1169. if(dsrc->type == BL_PC && pc_isdead((struct map_session_data *)dsrc)) //術者?がPCですでに死んでいたら何もしない
  1170. return 0;
  1171. if(bl->type == BL_PC && pc_isdead((struct map_session_data *)bl)) //?象がPCですでに死んでいたら何もしない
  1172. return 0;
  1173. if(bl->type == BL_PC && skillnotok(skillid, (struct map_session_data *)bl))
  1174. return 0; // [MouseJstr]
  1175. if(sc_data && sc_data[SC_HIDING].timer != -1) { //ハイディング?態で
  1176. if(skill_get_pl(skillid) != 2) //スキルの?性が地?性でなければ何もしない
  1177. return 0;
  1178. }
  1179. if(sc_data && sc_data[SC_TRICKDEAD].timer != -1) //死んだふり中は何もしない
  1180. return 0;
  1181. if(skillid == WZ_STORMGUST) { //使用スキルがスト?ムガストで
  1182. if(sc_data && sc_data[SC_FREEZE].timer != -1) //凍結?態なら何もしない
  1183. return 0;
  1184. }
  1185. if(skillid == WZ_FROSTNOVA && dsrc->x == bl->x && dsrc->y == bl->y) //使用スキルがフロストノヴァで、dsrcとblが同じ場所なら何もしない
  1186. return 0;
  1187. if(src->type == BL_PC && ((struct map_session_data *)src)->chatID) //術者がPCでチャット中なら何もしない
  1188. return 0;
  1189. if(dsrc->type == BL_PC && ((struct map_session_data *)dsrc)->chatID) //術者がPCでチャット中なら何もしない
  1190. return 0;
  1191. if(src->type == BL_PC && bl && mob_gvmobcheck(((struct map_session_data *)src),bl)==0)
  1192. return 0;
  1193. //何もしない判定ここまで
  1194. type=-1;
  1195. lv=(flag>>20)&0xf;
  1196. dmg=battle_calc_attack(attack_type,src,bl,skillid,skilllv,flag&0xff ); //ダメ?ジ計算
  1197. //マジックロッド?理ここから
  1198. if(attack_type&BF_MAGIC && sc_data && sc_data[SC_MAGICROD].timer != -1 && src == dsrc) { //魔法攻?でマジックロッド?態でsrc=dsrcなら
  1199. dmg.damage = dmg.damage2 = 0; //ダメ?ジ0
  1200. if(bl->type == BL_PC) { //?象がPCの場合
  1201. struct map_session_data *sd = (struct map_session_data *)bl;
  1202. if (sd) {
  1203. int sp = skill_get_sp(skillid,skilllv); //使用されたスキルのSPを吸?
  1204. sp = sp * sc_data[SC_MAGICROD].val2 / 100; //吸?率計算
  1205. if(skillid == WZ_WATERBALL && skilllv > 1) //ウォ?タ?ボ?ルLv1以上
  1206. sp = sp/((skilllv|1)*(skilllv|1)); //さらに計算?
  1207. if(sp > 0x7fff) sp = 0x7fff; //SP多すぎの場合は理論最大値
  1208. else if(sp < 1) sp = 1; //1以下の場合は1
  1209. if(sd->status.sp + sp > sd->status.max_sp) { //回復SP+現在のSPがMSPより大きい場合
  1210. sp = sd->status.max_sp - sd->status.sp; //SPをMSP-現在SPにする
  1211. sd->status.sp = sd->status.max_sp; //現在のSPにMSPを代入
  1212. }
  1213. else //回復SP+現在のSPがMSPより小さい場合は回復SPを加算
  1214. sd->status.sp += sp;
  1215. clif_heal(sd->fd,SP_SP,sp); //SP回復エフェクトの表示
  1216. sd->canact_tick = tick + skill_delayfix(bl, skill_get_delay(SA_MAGICROD,sc_data[SC_MAGICROD].val1)); //
  1217. }
  1218. }
  1219. clif_skill_nodamage(bl,bl,SA_MAGICROD,sc_data[SC_MAGICROD].val1,1); //マジックロッドエフェクトを表示
  1220. }
  1221. //マジックロッド?理ここまで
  1222. if(src->type==BL_PET) { // [Valaris]
  1223. dmg.damage=battle_attr_fix(skilllv, skill_get_pl(skillid), status_get_element(bl) );
  1224. dmg.damage2=0;
  1225. }
  1226. damage = dmg.damage + dmg.damage2;
  1227. if(lv==15)
  1228. lv=-1;
  1229. if( flag&0xff00 )
  1230. type=(flag&0xff00)>>8;
  1231. if(damage <= 0 || damage < dmg.div_) //吹き飛ばし判定?※
  1232. dmg.blewcount = 0;
  1233. if(skillid == CR_GRANDCROSS||skillid == NPC_DARKGRANDCROSS) {//グランドクロス
  1234. if(battle_config.gx_disptype) dsrc = src; // 敵ダメ?ジ白文字表示
  1235. if( src == bl) type = 4; // 反動はダメ?ジモ?ションなし
  1236. }
  1237. //使用者がPCの場合の?理ここから
  1238. if(src->type == BL_PC) {
  1239. struct map_session_data *sd = (struct map_session_data *)src;
  1240. nullpo_retr(0, sd);
  1241. //連打掌(MO_CHAINCOMBO)ここから
  1242. if(skillid == MO_CHAINCOMBO) {
  1243. int delay = 1000 - 4 * status_get_agi(src) - 2 * status_get_dex(src); //基本ディレイの計算
  1244. if(damage < status_get_hp(bl)) { //ダメ?ジが?象のHPより小さい場合
  1245. if(pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0) //猛龍拳(MO_COMBOFINISH)取得&?球保持時は+300ms
  1246. delay += 300 * battle_config.combo_delay_rate /100; //追加ディレイをconfにより調整
  1247. status_change_start(src,SC_COMBO,MO_CHAINCOMBO,skilllv,0,0,delay,0); //コンボ?態に
  1248. }
  1249. sd->attackabletime = sd->canmove_tick = tick + delay;
  1250. clif_combo_delay(src,delay); //コンボディレイパケットの送信
  1251. }
  1252. //連打掌(MO_CHAINCOMBO)ここまで
  1253. //猛龍拳(MO_COMBOFINISH)ここから
  1254. else if(skillid == MO_COMBOFINISH) {
  1255. int delay = 700 - 4 * status_get_agi(src) - 2 * status_get_dex(src);
  1256. if(damage < status_get_hp(bl)) {
  1257. //阿修羅覇凰拳(MO_EXTREMITYFIST)取得&?球4個保持&爆裂波動(MO_EXPLOSIONSPIRITS)?態時は+300ms
  1258. //伏虎拳(CH_TIGERFIST)取得時も+300ms
  1259. if((pc_checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball >= 4 && sd->sc_data[SC_EXPLOSIONSPIRITS].timer != -1) ||
  1260. (pc_checkskill(sd, CH_TIGERFIST) > 0 && sd->spiritball > 0) ||
  1261. (pc_checkskill(sd, CH_CHAINCRUSH) > 0 && sd->spiritball > 1))
  1262. delay += 300 * battle_config.combo_delay_rate /100; //追加ディレイをconfにより調整
  1263. status_change_start(src,SC_COMBO,MO_COMBOFINISH,skilllv,0,0,delay,0); //コンボ?態に
  1264. }
  1265. sd->attackabletime = sd->canmove_tick = tick + delay;
  1266. clif_combo_delay(src,delay); //コンボディレイパケットの送信
  1267. }
  1268. //猛龍拳(MO_COMBOFINISH)ここまで
  1269. //伏虎拳(CH_TIGERFIST)ここから
  1270. else if(skillid == CH_TIGERFIST) {
  1271. int delay = 1000 - 4 * status_get_agi(src) - 2 * status_get_dex(src);
  1272. if(damage < status_get_hp(bl)) {
  1273. if(pc_checkskill(sd, CH_CHAINCRUSH) > 0) //連柱崩?(CH_CHAINCRUSH)取得時は+300ms
  1274. delay += 300 * battle_config.combo_delay_rate /100; //追加ディレイをconfにより調整
  1275. status_change_start(src,SC_COMBO,CH_TIGERFIST,skilllv,0,0,delay,0); //コンボ?態に
  1276. }
  1277. sd->attackabletime = sd->canmove_tick = tick + delay;
  1278. clif_combo_delay(src,delay); //コンボディレイパケットの送信
  1279. }
  1280. //伏虎拳(CH_TIGERFIST)ここまで
  1281. //連柱崩?(CH_CHAINCRUSH)ここから
  1282. else if(skillid == CH_CHAINCRUSH) {
  1283. int delay = 1000 - 4 * status_get_agi(src) - 2 * status_get_dex(src);
  1284. if(damage < status_get_hp(bl)) {
  1285. //阿修羅覇凰拳(MO_EXTREMITYFIST)取得&?球4個保持&爆裂波動(MO_EXPLOSIONSPIRITS)?態時は+300ms
  1286. if(pc_checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball >= 4 && sd->sc_data[SC_EXPLOSIONSPIRITS].timer != -1)
  1287. delay += 300 * battle_config.combo_delay_rate /100; //追加ディレイをconfにより調整
  1288. status_change_start(src,SC_COMBO,CH_CHAINCRUSH,skilllv,0,0,delay,0); //コンボ?態に
  1289. }
  1290. sd->attackabletime = sd->canmove_tick = tick + delay;
  1291. clif_combo_delay(src,delay); //コンボディレイパケットの送信
  1292. }
  1293. //連柱崩?(CH_CHAINCRUSH)ここまで
  1294. }
  1295. //使用者がPCの場合の?理ここまで
  1296. //武器スキル?ここから
  1297. //AppleGirl Was Here
  1298. if(attack_type&BF_MAGIC && damage > 0 && src != bl && src == dsrc) { //Blah Blah
  1299. if(bl->type == BL_PC) { //Blah Blah
  1300. struct map_session_data *tsd = (struct map_session_data *)bl;
  1301. if(tsd->magic_damage_return > 0) { //More Blah
  1302. rdamage += damage * tsd->magic_damage_return / 100;
  1303. if(rdamage < 1) rdamage = 1;
  1304. }
  1305. }
  1306. }
  1307. //Stop Here
  1308. if(attack_type&BF_WEAPON && damage > 0 && src != bl && src == dsrc) { //武器スキル&ダメ?ジあり&使用者と?象者が違う&src=dsrc
  1309. if(dmg.flag&BF_SHORT) { //近距離攻?時?※
  1310. if(bl->type == BL_PC) { //?象がPCの時
  1311. struct map_session_data *tsd = (struct map_session_data *)bl;
  1312. nullpo_retr(0, tsd);
  1313. if(tsd->short_weapon_damage_return > 0) { //近距離攻?跳ね返し?※
  1314. rdamage += damage * tsd->short_weapon_damage_return / 100;
  1315. if(rdamage < 1) rdamage = 1;
  1316. }
  1317. }
  1318. if(sc_data && sc_data[SC_REFLECTSHIELD].timer != -1) { //リフレクトシ?ルド時
  1319. rdamage += damage * sc_data[SC_REFLECTSHIELD].val2 / 100; //跳ね返し計算
  1320. if(rdamage < 1) rdamage = 1;
  1321. }
  1322. }
  1323. else if(dmg.flag&BF_LONG) { //遠距離攻?時?※
  1324. if(bl->type == BL_PC) { //?象がPCの時
  1325. struct map_session_data *tsd = (struct map_session_data *)bl;
  1326. nullpo_retr(0, tsd);
  1327. if(tsd->long_weapon_damage_return > 0) { //遠距離攻?跳ね返し?※
  1328. rdamage += damage * tsd->long_weapon_damage_return / 100;
  1329. if(rdamage < 1) rdamage = 1;
  1330. }
  1331. }
  1332. }
  1333. if(rdamage > 0)
  1334. clif_damage(src,src,tick, dmg.amotion,0,rdamage,1,4,0);
  1335. }
  1336. //武器スキル?ここまで
  1337. switch(skillid){
  1338. case AS_SPLASHER:
  1339. clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, -1, 5);
  1340. break;
  1341. case NPC_SELFDESTRUCTION:
  1342. case NPC_SELFDESTRUCTION2:
  1343. break;
  1344. case SN_SHARPSHOOTING:
  1345. clif_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,0,0,0);
  1346. break;
  1347. default:
  1348. clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, (lv!=0)?lv:skilllv, (skillid==0)? 5:type );
  1349. }
  1350. /* 吹き飛ばし処理とそのパケット */
  1351. if (dmg.blewcount > 0 && bl->type!=BL_SKILL && !map[src->m].flag.gvg) {
  1352. skill_blown(dsrc,bl,dmg.blewcount);
  1353. if(bl->type == BL_MOB)
  1354. clif_fixmobpos((struct mob_data *)bl);
  1355. else if(bl->type == BL_PET)
  1356. clif_fixpetpos((struct pet_data *)bl);
  1357. else
  1358. clif_fixpos(bl);
  1359. }
  1360. map_freeblock_lock();
  1361. /* ?際にダメ?ジ?理を行う */
  1362. if (skillid || flag) {
  1363. if (attack_type&BF_WEAPON)
  1364. battle_delay_damage(tick+dmg.amotion,src,bl,damage,0);
  1365. else
  1366. battle_damage(src,bl,damage,0);
  1367. }
  1368. if(skillid == RG_INTIMIDATE && damage > 0 && !(status_get_mode(bl)&0x20) && !map[src->m].flag.gvg ) {
  1369. int s_lv = status_get_lv(src),t_lv = status_get_lv(bl);
  1370. int rate = 50 + skilllv * 5;
  1371. rate = rate + (s_lv - t_lv);
  1372. if(rand()%100 < rate)
  1373. skill_addtimerskill(src,tick + 800,bl->id,0,0,skillid,skilllv,0,flag);
  1374. }
  1375. if(damage > 0 && dmg.flag&BF_SKILL && bl->type==BL_PC && pc_checkskill((struct map_session_data *)bl,RG_PLAGIARISM) && sc_data[SC_PRESERVE].timer == -1){
  1376. struct map_session_data *tsd = (struct map_session_data *)bl;
  1377. nullpo_retr(0, tsd);
  1378. if(!tsd->status.skill[skillid].id && !tsd->status.skill[skillid].lv
  1379. && !(skillid > NPC_PIERCINGATT && skillid < NPC_SUMMONMONSTER)
  1380. && !(skillid > NPC_SELFDESTRUCTION2 && skillid < NPC_UNDEADATTACK)){
  1381. //?に?んでいるスキルがあれば該?スキルを消す
  1382. if (tsd->cloneskill_id && tsd->status.skill[tsd->cloneskill_id].flag==13){
  1383. tsd->status.skill[tsd->cloneskill_id].id=0;
  1384. tsd->status.skill[tsd->cloneskill_id].flag=0;
  1385. }
  1386. tsd->cloneskill_id=skillid;
  1387. tsd->status.skill[skillid].id=skillid;
  1388. tsd->status.skill[skillid].lv=(pc_checkskill(tsd,RG_PLAGIARISM) > skill_get_max(skillid))?
  1389. skill_get_max(skillid):pc_checkskill(tsd,RG_PLAGIARISM);
  1390. tsd->status.skill[skillid].flag=13;//cloneskill flag
  1391. clif_skillinfoblock(tsd);
  1392. }
  1393. }
  1394. /* ダメ?ジがあるなら追加?果判定 */
  1395. if(bl->prev != NULL){
  1396. struct map_session_data *sd = (struct map_session_data *)bl;
  1397. nullpo_retr(0, sd);
  1398. if( bl->type != BL_PC || (sd && !pc_isdead(sd)) ) {
  1399. if(damage > 0)
  1400. skill_additional_effect(src,bl,skillid,skilllv,attack_type,tick);
  1401. if(bl->type==BL_MOB && src!=bl) /* スキル使用?件のMOBスキル */
  1402. {
  1403. struct mob_data *md=(struct mob_data *)bl;
  1404. nullpo_retr(0, md);
  1405. if(battle_config.mob_changetarget_byskill == 1)
  1406. {
  1407. int target;
  1408. target=md->target_id;
  1409. if(src->type == BL_PC)
  1410. md->target_id=src->id;
  1411. mobskill_use(md,tick,MSC_SKILLUSED|(skillid<<16));
  1412. md->target_id=target;
  1413. }
  1414. else
  1415. mobskill_use(md,tick,MSC_SKILLUSED|(skillid<<16));
  1416. }
  1417. }
  1418. }
  1419. if(src->type == BL_PC && dmg.flag&BF_WEAPON && src != bl && src == dsrc && damage > 0) {
  1420. struct map_session_data *sd = (struct map_session_data *)src;
  1421. int hp = 0,sp = 0;
  1422. nullpo_retr(0, sd);
  1423. if(sd->hp_drain_rate && sd->hp_drain_per > 0 && dmg.damage > 0 && rand()%100 < sd->hp_drain_rate) {
  1424. hp += (dmg.damage * sd->hp_drain_per)/100;
  1425. if(sd->hp_drain_rate > 0 && hp < 1) hp = 1;
  1426. else if(sd->hp_drain_rate < 0 && hp > -1) hp = -1;
  1427. }
  1428. if(sd->hp_drain_rate_ && sd->hp_drain_per_ > 0 && dmg.damage2 > 0 && rand()%100 < sd->hp_drain_rate_) {
  1429. hp += (dmg.damage2 * sd->hp_drain_per_)/100;
  1430. if(sd->hp_drain_rate_ > 0 && hp < 1) hp = 1;
  1431. else if(sd->hp_drain_rate_ < 0 && hp > -1) hp = -1;
  1432. }
  1433. if(sd->sp_drain_rate > 0 && sd->sp_drain_per > 0 && dmg.damage > 0 && rand()%100 < sd->sp_drain_rate) {
  1434. sp += (dmg.damage * sd->sp_drain_per)/100;
  1435. if(sd->sp_drain_rate > 0 && sp < 1) sp = 1;
  1436. else if(sd->sp_drain_rate < 0 && sp > -1) sp = -1;
  1437. }
  1438. if(sd->sp_drain_rate_ > 0 && sd->sp_drain_per_ > 0 && dmg.damage2 > 0 && rand()%100 < sd->sp_drain_rate_) {
  1439. sp += (dmg.damage2 * sd->sp_drain_per_)/100;
  1440. if(sd->sp_drain_rate_ > 0 && sp < 1) sp = 1;
  1441. else if(sd->sp_drain_rate_ < 0 && sp > -1) sp = -1;
  1442. }
  1443. if(hp || sp)
  1444. pc_heal(sd,hp,sp);
  1445. if (sd->sp_drain_type && bl->type == BL_PC)
  1446. battle_heal(NULL,bl,0,-sp,0);
  1447. }
  1448. if ((skillid || flag) && rdamage>0) {
  1449. if (attack_type&BF_WEAPON)
  1450. battle_delay_damage(tick+dmg.amotion,bl,src,rdamage,0);
  1451. else
  1452. battle_damage(bl,src,rdamage,0);
  1453. }
  1454. if(attack_type&BF_WEAPON && sc_data && sc_data[SC_AUTOCOUNTER].timer != -1 && sc_data[SC_AUTOCOUNTER].val4 > 0) {
  1455. if(sc_data[SC_AUTOCOUNTER].val3 == dsrc->id)
  1456. battle_weapon_attack(bl,dsrc,tick,0x8000|sc_data[SC_AUTOCOUNTER].val1);
  1457. status_change_end(bl,SC_AUTOCOUNTER,-1);
  1458. }
  1459. map_freeblock_unlock();
  1460. return (dmg.damage+dmg.damage2); /* ?ダメを返す */
  1461. }
  1462. /*==========================================
  1463. * スキル範?攻?用(map_foreachinareaから呼ばれる)
  1464. * flagについて:16進?を確認
  1465. * MSB <- 00fTffff ->LSB
  1466. * T =タ?ゲット選?用(BCT_*)
  1467. * ffff=自由に使用可能
  1468. * 0 =予約。0に固定
  1469. *------------------------------------------
  1470. */
  1471. static int skill_area_temp[8]; /* 一時??。必要なら使う。 */
  1472. typedef int (*SkillFunc)(struct block_list *,struct block_list *,int,int,unsigned int,int);
  1473. int skill_area_sub( struct block_list *bl,va_list ap )
  1474. {
  1475. struct block_list *src;
  1476. int skill_id,skill_lv,flag;
  1477. unsigned int tick;
  1478. SkillFunc func;
  1479. nullpo_retr(0, bl);
  1480. nullpo_retr(0, ap);
  1481. if(bl->type!=BL_PC && bl->type!=BL_MOB && bl->type!=BL_SKILL)
  1482. return 0;
  1483. src=va_arg(ap,struct block_list *); //ここではsrcの値を?照していないのでNULLチェックはしない
  1484. skill_id=va_arg(ap,int);
  1485. skill_lv=va_arg(ap,int);
  1486. tick=va_arg(ap,unsigned int);
  1487. flag=va_arg(ap,int);
  1488. func=va_arg(ap,SkillFunc);
  1489. if(battle_check_target(src,bl,flag) > 0)
  1490. func(src,bl,skill_id,skill_lv,tick,flag);
  1491. return 0;
  1492. }
  1493. static int skill_check_unit_range_sub( struct block_list *bl,va_list ap )
  1494. {
  1495. struct skill_unit *unit;
  1496. int *c;
  1497. int skillid,unit_id;
  1498. nullpo_retr(0, bl);
  1499. nullpo_retr(0, ap);
  1500. nullpo_retr(0, unit = (struct skill_unit *)bl);
  1501. nullpo_retr(0, c = va_arg(ap,int *));
  1502. if(bl->prev == NULL || bl->type != BL_SKILL)
  1503. return 0;
  1504. if(!unit->alive)
  1505. return 0;
  1506. skillid = va_arg(ap,int);
  1507. unit_id = unit->group->unit_id;
  1508. if (skillid==MG_SAFETYWALL || skillid==AL_PNEUMA) {
  1509. if(unit_id != 0x7e && unit_id != 0x85)
  1510. return 0;
  1511. } else if (skillid==AL_WARP) {
  1512. if ((unit_id<0x8f || unit_id>0x99) && unit_id!=0x92)
  1513. return 0;
  1514. } else if ((skillid>=HT_SKIDTRAP && skillid<=HT_CLAYMORETRAP) || skillid==HT_TALKIEBOX) {
  1515. if ((unit_id<0x8f || unit_id>0x99) && unit_id!=0x92)
  1516. return 0;
  1517. } else if (skillid==WZ_FIREPILLAR) {
  1518. if (unit_id!=0x87)
  1519. return 0;
  1520. } else if (skillid==HP_BASILICA) {
  1521. if ((unit_id<0x8f || unit_id>0x99) && unit_id!=0x92 && unit_id!=0x83)
  1522. return 0;
  1523. } else
  1524. return 0;
  1525. (*c)++;
  1526. return 0;
  1527. }
  1528. int skill_check_unit_range(int m,int x,int y,int skillid,int skilllv)
  1529. {
  1530. int c = 0;
  1531. int range = skill_get_unit_range(skillid);
  1532. int layout_type = skill_get_unit_layout_type(skillid,skilllv);
  1533. if (layout_type==-1 || layout_type>MAX_SQUARE_LAYOUT) {
  1534. printf("skill_check_unit_range: unsupported layout type %d for skill %d\n",layout_type,skillid);
  1535. return 0;
  1536. }
  1537. // とりあえず正方形のユニットレイアウトのみ対応
  1538. range += layout_type;
  1539. map_foreachinarea(skill_check_unit_range_sub,m,
  1540. x-range,y-range,x+range,y+range,BL_SKILL,&c,skillid);
  1541. return c;
  1542. }
  1543. static int skill_check_unit_range2_sub( struct block_list *bl,va_list ap )
  1544. {
  1545. int *c;
  1546. int skillid;
  1547. nullpo_retr(0, bl);
  1548. nullpo_retr(0, ap);
  1549. nullpo_retr(0, c = va_arg(ap,int *));
  1550. if(bl->prev == NULL || (bl->type != BL_PC && bl->type != BL_MOB))
  1551. return 0;
  1552. if(bl->type == BL_PC && pc_isdead((struct map_session_data *)bl))
  1553. return 0;
  1554. skillid = va_arg(ap,int);
  1555. if (skillid==HP_BASILICA && bl->type==BL_PC)
  1556. return 0;
  1557. (*c)++;
  1558. return 0;
  1559. }
  1560. int skill_check_unit_range2(int m,int x,int y,int skillid, int skilllv)
  1561. {
  1562. int c = 0;
  1563. int range = skill_get_unit_range(skillid);
  1564. int layout_type = skill_get_unit_layout_type(skillid,skilllv);
  1565. if (layout_type==-1 || layout_type>MAX_SQUARE_LAYOUT) {
  1566. printf("skill_check_unit_range2: unsupported layout type %d for skill %d\n",layout_type,skillid);
  1567. return 0;
  1568. }
  1569. // とりあえず正方形のユニットレイアウトのみ対応
  1570. range += layout_type;
  1571. map_foreachinarea(skill_check_unit_range2_sub,m,
  1572. x-range,y-range,x+range,y+range,0,&c,skillid);
  1573. return c;
  1574. }
  1575. int skill_guildaura_sub (struct block_list *bl,va_list ap)
  1576. {
  1577. struct map_session_data *sd;
  1578. struct guild *g;
  1579. int gid, id;
  1580. int flag = 0;
  1581. nullpo_retr(0, sd=(struct map_session_data *)bl);
  1582. nullpo_retr(0, ap);
  1583. id = va_arg(ap,int);
  1584. gid = va_arg(ap,int);
  1585. if (sd->status.guild_id != gid)
  1586. return 0;
  1587. g = va_arg(ap,struct guild *);
  1588. if (guild_checkskill(g, GD_LEADERSHIP)>0) flag |= 1<<0;
  1589. if (guild_checkskill(g, GD_GLORYWOUNDS)>0) flag |= 1<<1;
  1590. if (guild_checkskill(g, GD_SOULCOLD)>0) flag |= 1<<2;
  1591. if (guild_checkskill(g, GD_HAWKEYES)>0) flag |= 1<<3;
  1592. if (guild_checkskill(g, GD_CHARISMA)>0) flag |= 1<<4;
  1593. if (flag > 0) {
  1594. if (sd->sc_count && sd->sc_data[SC_GUILDAURA].timer != -1) {
  1595. if (sd->sc_data[SC_GUILDAURA].val4 != flag) {
  1596. sd->sc_data[SC_GUILDAURA].val4 = flag;
  1597. status_calc_pc (sd, 0);
  1598. }
  1599. return 0;
  1600. }
  1601. status_change_start(&sd->bl, SC_GUILDAURA,1,id,0,flag,0,0 );
  1602. }
  1603. return 0;
  1604. }
  1605. /*=========================================================================
  1606. * 範?スキル使用?理小分けここから
  1607. */
  1608. /* ?象の?をカウントする。(skill_area_temp[0]を初期化しておくこと) */
  1609. int skill_area_sub_count(struct block_list *src,struct block_list *target,int skillid,int skilllv,unsigned int tick,int flag)
  1610. {
  1611. //if(skilllv <= 0) return 0;
  1612. if(skillid > 0 && skilllv <= 0) return 0; // celest
  1613. if(skill_area_temp[0] < 0xffff)
  1614. skill_area_temp[0]++;
  1615. return 0;
  1616. }
  1617. int skill_count_water(struct block_list *src,int range)
  1618. {
  1619. int i,x,y,cnt = 0,size = range*2+1;
  1620. struct skill_unit *unit;
  1621. for (i=0;i<size*size;i++) {
  1622. x = src->x+(i%size-range);
  1623. y = src->y+(i/size-range);
  1624. if (map_getcell(src->m,x,y,CELL_CHKWATER)) {
  1625. cnt++;
  1626. continue;
  1627. }
  1628. unit = map_find_skill_unit_oncell(src,x,y,SA_DELUGE,NULL);
  1629. if (unit) {
  1630. cnt++;
  1631. skill_delunit(unit);
  1632. }
  1633. }
  1634. return cnt;
  1635. }
  1636. /*==========================================
  1637. *
  1638. *------------------------------------------
  1639. */
  1640. static int skill_timerskill(int tid, unsigned int tick, int id,int data )
  1641. {
  1642. struct map_session_data *sd = NULL;
  1643. struct mob_data *md = NULL;
  1644. struct pet_data *pd = NULL;
  1645. struct block_list *src = map_id2bl(id),*target;
  1646. struct skill_timerskill *skl = NULL;
  1647. int range;
  1648. nullpo_retr(0, src);
  1649. if(src->prev == NULL)
  1650. return 0;
  1651. if(src->type == BL_PC) {
  1652. nullpo_retr(0, sd = (struct map_session_data *)src);
  1653. skl = &sd->skilltimerskill[data];
  1654. }
  1655. else if(src->type == BL_MOB) {
  1656. nullpo_retr(0, md = (struct mob_data *)src);
  1657. skl = &md->skilltimerskill[data];
  1658. }
  1659. else if(src->type == BL_PET) { // [Valaris]
  1660. nullpo_retr(0, pd = (struct pet_data *)src);
  1661. skl = &pd->skilltimerskill[data];
  1662. }
  1663. else
  1664. return 0;
  1665. nullpo_retr(0, skl);
  1666. skl->timer = -1;
  1667. if (sd) {
  1668. sd->timerskill_count--;
  1669. }
  1670. if(skl->target_id) {
  1671. struct block_list tbl;
  1672. target = map_id2bl(skl->target_id);
  1673. if(skl->skill_id == RG_INTIMIDATE) {
  1674. if(target == NULL) {
  1675. target = &tbl; //初期化してないのにアドレス突っ?んでいいのかな?
  1676. target->type = BL_NUL;
  1677. target->m = src->m;
  1678. target->prev = target->next = NULL;
  1679. }
  1680. }
  1681. if(target == NULL)
  1682. return 0;
  1683. if(target->prev == NULL && skl->skill_id != RG_INTIMIDATE)
  1684. return 0;
  1685. if(src->m != target->m)
  1686. return 0;
  1687. if(sd && pc_isdead(sd))
  1688. return 0;
  1689. if(target->type == BL_PC && pc_isdead((struct map_session_data *)target) && skl->skill_id != RG_INTIMIDATE)
  1690. return 0;
  1691. switch(skl->skill_id) {
  1692. case TF_BACKSLIDING:
  1693. clif_skill_nodamage(src,src,skl->skill_id,skl->skill_lv,1);
  1694. break;
  1695. case RG_INTIMIDATE:
  1696. if(sd && !map[src->m].flag.noteleport) {
  1697. int x,y,i,j;
  1698. pc_randomwarp(sd,3);
  1699. for(i=0;i<16;i++) {
  1700. j = rand()%8;
  1701. x = sd->bl.x + dirx[j];
  1702. y = sd->bl.y + diry[j];
  1703. if(map_getcell(sd->bl.m,x,y,CELL_CHKPASS))
  1704. break;
  1705. }
  1706. if(i >= 16) {
  1707. x = sd->bl.x;
  1708. y = sd->bl.y;
  1709. }
  1710. if(target->prev != NULL) {
  1711. if(target->type == BL_PC && !pc_isdead((struct map_session_data *)target))
  1712. pc_setpos((struct map_session_data *)target,map[sd->bl.m].name,x,y,3);
  1713. else if(target->type == BL_MOB)
  1714. mob_warp((struct mob_data *)target,-1,x,y,3);
  1715. }
  1716. }
  1717. else if(md && !map[src->m].flag.monster_noteleport) {
  1718. int x,y,i,j;
  1719. mob_warp(md,-1,-1,-1,3);
  1720. for(i=0;i<16;i++) {
  1721. j = rand()%8;
  1722. x = md->bl.x + dirx[j];
  1723. y = md->bl.y + diry[j];
  1724. if(map_getcell(md->bl.m,x,y,CELL_CHKPASS))
  1725. break;
  1726. }
  1727. if(i >= 16) {
  1728. x = md->bl.x;
  1729. y = md->bl.y;
  1730. }
  1731. if(target->prev != NULL) {
  1732. if(target->type == BL_PC && !pc_isdead((struct map_session_data *)target))
  1733. pc_setpos((struct map_session_data *)target,map[md->bl.m].name,x,y,3);
  1734. else if(target->type == BL_MOB)
  1735. mob_warp((struct mob_data *)target,-1,x,y,3);
  1736. }
  1737. }
  1738. break;
  1739. case BA_FROSTJOKE: /* 寒いジョ?ク */
  1740. case DC_SCREAM: /* スクリ?ム */
  1741. range=15; //視界全?
  1742. map_foreachinarea(skill_frostjoke_scream,src->m,src->x-range,src->y-range,
  1743. src->x+range,src->y+range,0,src,skl->skill_id,skl->skill_lv,tick);
  1744. break;
  1745. case WZ_WATERBALL:
  1746. if (skl->type>1) {
  1747. skl->timer = 0; // skill_addtimerskillで使用されないように
  1748. skill_addtimerskill(src,tick+150,target->id,0,0,skl->skill_id,skl->skill_lv,skl->type-1,skl->flag);
  1749. skl->timer = -1;
  1750. }
  1751. skill_attack(BF_MAGIC,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
  1752. break;
  1753. default:
  1754. skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
  1755. break;
  1756. }
  1757. }
  1758. else {
  1759. if(src->m != skl->map)
  1760. return 0;
  1761. switch(skl->skill_id) {
  1762. case WZ_METEOR:
  1763. if(skl->type >= 0) {
  1764. skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->type>>16,skl->type&0xFFFF,0);
  1765. clif_skill_poseffect(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,tick);
  1766. }
  1767. else
  1768. skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,0);
  1769. break;
  1770. }
  1771. }
  1772. return 0;
  1773. }
  1774. /*==========================================
  1775. *
  1776. *------------------------------------------
  1777. */
  1778. int skill_addtimerskill(struct block_list *src,unsigned int tick,int target,int x,int y,int skill_id,int skill_lv,int type,int flag)
  1779. {
  1780. int i;
  1781. nullpo_retr(1, src);
  1782. if(src->type == BL_PC) {
  1783. struct map_session_data *sd = (struct map_session_data *)src;
  1784. nullpo_retr(1, sd);
  1785. for(i=0;i<MAX_SKILLTIMERSKILL;i++) {
  1786. if(sd->skilltimerskill[i].timer == -1) {
  1787. sd->skilltimerskill[i].timer = add_timer(tick, skill_timerskill, src->id, i);
  1788. sd->skilltimerskill[i].src_id = src->id;
  1789. sd->skilltimerskill[i].target_id = target;
  1790. sd->skilltimerskill[i].skill_id = skill_id;
  1791. sd->skilltimerskill[i].skill_lv = skill_lv;
  1792. sd->skilltimerskill[i].map = src->m;
  1793. sd->skilltimerskill[i].x = x;
  1794. sd->skilltimerskill[i].y = y;
  1795. sd->skilltimerskill[i].type = type;
  1796. sd->skilltimerskill[i].flag = flag;
  1797. sd->timerskill_count++;
  1798. return 0;
  1799. }
  1800. }
  1801. return 1;
  1802. }
  1803. else if(src->type == BL_MOB) {
  1804. struct mob_data *md = (struct mob_data *)src;
  1805. nullpo_retr(1, md);
  1806. for(i=0;i<MAX_MOBSKILLTIMERSKILL;i++) {
  1807. if(md->skilltimerskill[i].timer == -1) {
  1808. md->skilltimerskill[i].timer = add_timer(tick, skill_timerskill, src->id, i);
  1809. md->skilltimerskill[i].src_id = src->id;
  1810. md->skilltimerskill[i].target_id = target;
  1811. md->skilltimerskill[i].skill_id = skill_id;
  1812. md->skilltimerskill[i].skill_lv = skill_lv;
  1813. md->skilltimerskill[i].map = src->m;
  1814. md->skilltimerskill[i].x = x;
  1815. md->skilltimerskill[i].y = y;
  1816. md->skilltimerskill[i].type = type;
  1817. md->skilltimerskill[i].flag = flag;
  1818. return 0;
  1819. }
  1820. }
  1821. return 1;
  1822. }
  1823. else if(src->type == BL_PET) { // [Valaris]
  1824. struct pet_data *pd = (struct pet_data *)src;
  1825. nullpo_retr(1, pd);
  1826. for(i=0;i<MAX_MOBSKILLTIMERSKILL;i++) {
  1827. if(pd->skilltimerskill[i].timer == -1) {
  1828. pd->skilltimerskill[i].timer = add_timer(tick, skill_timerskill, src->id, i);
  1829. pd->skilltimerskill[i].src_id = src->id;
  1830. pd->skilltimerskill[i].target_id = target;
  1831. pd->skilltimerskill[i].skill_id = skill_id;
  1832. pd->skilltimerskill[i].skill_lv = skill_lv;
  1833. pd->skilltimerskill[i].map = src->m;
  1834. pd->skilltimerskill[i].x = x;
  1835. pd->skilltimerskill[i].y = y;
  1836. pd->skilltimerskill[i].type = type;
  1837. pd->skilltimerskill[i].flag = flag;
  1838. return 0;
  1839. }
  1840. }
  1841. return 1;
  1842. }
  1843. return 1;
  1844. }
  1845. /*==========================================
  1846. *
  1847. *------------------------------------------
  1848. */
  1849. int skill_cleartimerskill(struct block_list *src)
  1850. {
  1851. int i;
  1852. nullpo_retr(0, src);
  1853. if(src->type == BL_PC) {
  1854. struct map_session_data *sd = (struct map_session_data *)src;
  1855. nullpo_retr(0, sd);
  1856. if (sd->timerskill_count <= 0)
  1857. return 0;
  1858. for(i=0;i<MAX_SKILLTIMERSKILL;i++) {
  1859. if(sd->skilltimerskill[i].timer != -1) {
  1860. delete_timer(sd->skilltimerskill[i].timer, skill_timerskill);
  1861. sd->skilltimerskill[i].timer = -1;
  1862. sd->timerskill_count--;
  1863. }
  1864. }
  1865. }
  1866. else if(src->type == BL_MOB) {
  1867. struct mob_data *md = (struct mob_data *)src;
  1868. nullpo_retr(0, md);
  1869. for(i=0;i<MAX_MOBSKILLTIMERSKILL;i++) {
  1870. if(md->skilltimerskill[i].timer != -1) {
  1871. delete_timer(md->skilltimerskill[i].timer, skill_timerskill);
  1872. md->skilltimerskill[i].timer = -1;
  1873. }
  1874. }
  1875. }
  1876. return 0;
  1877. }
  1878. /* 範?スキル使用?理小分けここまで
  1879. * -------------------------------------------------------------------------
  1880. */
  1881. /*==========================================
  1882. * スキル使用(詠唱完了、ID指定攻?系)
  1883. * (スパゲッティに向けて1?前進!(ダメポ))
  1884. *------------------------------------------
  1885. */
  1886. int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag )
  1887. {
  1888. struct map_session_data *sd = NULL;
  1889. struct status_change *sc_data = status_get_sc_data(src);
  1890. int i;
  1891. if(skillid < 0)
  1892. { // remove the debug print when this case is finished
  1893. printf("skill_castend_damage_id: skillid=%i\ncall: %p %p %i %i %i %i",skillid,
  1894. src, bl,skillid,skilllv,tick,flag);
  1895. return 0;
  1896. }
  1897. if(skillid > 0 && skilllv <= 0) return 0;
  1898. nullpo_retr(1, src);
  1899. nullpo_retr(1, bl);
  1900. if(src->type==BL_PC)
  1901. sd=(struct map_session_data *)src;
  1902. if(sd && pc_isdead(sd))
  1903. return 1;
  1904. if((skillid == CR_GRANDCROSS || skillid == NPC_DARKGRANDCROSS) && src != bl)
  1905. bl = src;
  1906. if(bl->prev == NULL)
  1907. return 1;
  1908. if(bl->type == BL_PC && pc_isdead((struct map_session_data *)bl))
  1909. return 1;
  1910. map_freeblock_lock();
  1911. switch(skillid)
  1912. {
  1913. /* 武器攻?系スキル */
  1914. case SM_BASH: /* バッシュ */
  1915. case MC_MAMMONITE: /* メマ?ナイト */
  1916. case AC_DOUBLE: /* ダブルストレイフィング */
  1917. case AS_SONICBLOW: /* ソニックブロ? */
  1918. case KN_PIERCE: /* ピア?ス */
  1919. case KN_SPEARBOOMERANG: /* スピアブ?メラン */
  1920. case KN_BRANDISHSPEAR: /* ブランディッシュスピア */
  1921. case TF_POISON: /* インベナム */
  1922. case TF_SPRINKLESAND: /* 砂まき */
  1923. case AC_CHARGEARROW: /* チャ?ジアロ? */
  1924. // case KN_SPEARSTAB: /* スピアスタブ */
  1925. case RG_RAID: /* サプライズアタック */
  1926. case RG_INTIMIDATE: /* インティミデイト */
  1927. case BA_MUSICALSTRIKE: /* ミュ?ジカルストライク */
  1928. case DC_THROWARROW: /* 矢?ち */
  1929. case BA_DISSONANCE: /* 不協和音 */
  1930. case CR_HOLYCROSS: /* ホ?リ?クロス */
  1931. case CR_SHIELDCHARGE:
  1932. case CR_SHIELDBOOMERANG:
  1933. /* 以下MOB?用 */
  1934. /* ??攻?、SP減少攻?、遠距離攻?、防御無視攻?、多段攻? */
  1935. case NPC_PIERCINGATT:
  1936. case NPC_MENTALBREAKER:
  1937. case NPC_RANGEATTACK:
  1938. case NPC_CRITICALSLASH:
  1939. case NPC_COMBOATTACK:
  1940. /* 必中攻?、毒攻?、暗?攻?、沈?攻?、スタン攻? */
  1941. case NPC_GUIDEDATTACK:
  1942. case NPC_POISON:
  1943. case NPC_BLINDATTACK:
  1944. case NPC_SILENCEATTACK:
  1945. case NPC_STUNATTACK:
  1946. /* 石化攻?、呪い攻?、睡眠攻?、ランダムATK攻? */
  1947. case NPC_PETRIFYATTACK:
  1948. case NPC_CURSEATTACK:
  1949. case NPC_SLEEPATTACK:
  1950. case NPC_RANDOMATTACK:
  1951. /* 水?性攻?、地?性攻?、火?性攻?、風?性攻? */
  1952. case NPC_WATERATTACK:
  1953. case NPC_GROUNDATTACK:
  1954. case NPC_FIREATTACK:
  1955. case NPC_WINDATTACK:
  1956. /* 毒?性攻?、聖?性攻?、闇?性攻?、念?性攻?、SP減少攻? */
  1957. case NPC_POISONATTACK:
  1958. case NPC_HOLYATTACK:
  1959. case NPC_DARKNESSATTACK:
  1960. case NPC_TELEKINESISATTACK:
  1961. case NPC_UNDEADATTACK:
  1962. case NPC_BREAKARMOR:
  1963. case NPC_BREAKWEAPON:
  1964. case NPC_BREAKHELM:
  1965. case NPC_BREAKSHIELD:
  1966. case LK_AURABLADE: /* オ?ラブレ?ド */
  1967. case LK_SPIRALPIERCE: /* スパイラルピア?ス */
  1968. case LK_HEADCRUSH: /* ヘッドクラッシュ */
  1969. case LK_JOINTBEAT: /* ジョイントビ?ト */
  1970. // case PA_PRESSURE: /* プレッシャ? */
  1971. // case PA_SACRIFICE: /* サクリファイス */
  1972. // case SN_SHARPSHOOTING: /* シャ?プシュ?ティング */
  1973. case CG_ARROWVULCAN: /* アロ?バルカン */
  1974. case ASC_BREAKER: /* ソウルブレ?カ? */
  1975. case HW_MAGICCRASHER: /* マジッククラッシャ? */
  1976. case ASC_METEORASSAULT: /* メテオアサルト */
  1977. case ITM_TOMAHAWK:
  1978. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  1979. break;
  1980. case SN_SHARPSHOOTING: /* シャ?プシュ?ティング */
  1981. map_foreachinpath (skill_attack_area,src->m, // function, map
  1982. src->x,src->y, // source xy
  1983. bl->x,bl->y, // target xy
  1984. 2,0, // range, type
  1985. BF_WEAPON,src,src,skillid,skilllv,tick,flag,BCT_ENEMY); // varargs
  1986. break;
  1987. case PA_PRESSURE: /* プレッシャ? */
  1988. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  1989. if (rand()%100 < 50)
  1990. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(PA_PRESSURE,skilllv),0);
  1991. else
  1992. status_change_start(bl,SC_BLEEDING,skilllv,0,0,0,skill_get_time2(PA_PRESSURE,skilllv),0);
  1993. if (bl->type == BL_PC) {
  1994. int sp;
  1995. struct map_session_data *tsd = (struct map_session_data *)bl;
  1996. nullpo_retb (tsd);
  1997. sp = tsd->status.max_sp * 10 * skilllv / 100;
  1998. if (sp > tsd->status.sp) sp = tsd->status.sp;
  1999. tsd->status.sp -= sp;
  2000. pc_heal(tsd,0,-sp);
  2001. }
  2002. break;
  2003. case NPC_DARKBREATH:
  2004. clif_emotion(src,7);
  2005. skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);
  2006. break;
  2007. case MO_INVESTIGATE: /* ?勁 */
  2008. {
  2009. struct status_change *sc_data = status_get_sc_data(src);
  2010. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  2011. if(sc_data && sc_data[SC_BLADESTOP].timer != -1)
  2012. status_change_end(src,SC_BLADESTOP,-1);
  2013. }
  2014. break;
  2015. case SN_FALCONASSAULT: /* ファルコンアサルト */
  2016. skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);
  2017. break;
  2018. case RG_BACKSTAP: /* バックスタブ */
  2019. {
  2020. int dir = map_calc_dir(src,bl->x,bl->y),t_dir = status_get_dir(bl);
  2021. int dist = distance(src->x,src->y,bl->x,bl->y);
  2022. if((dist > 0 && !map_check_dir(dir,t_dir)) || bl->type == BL_SKILL) {
  2023. struct status_change *sc_data = status_get_sc_data(src);
  2024. if(sc_data && sc_data[SC_HIDING].timer != -1)
  2025. status_change_end(src, SC_HIDING, -1); // ハイディング解除
  2026. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  2027. dir = dir < 4 ? dir+4 : dir-4; // change direction [Celest]
  2028. if (bl->type == BL_PC)
  2029. ((struct map_session_data *)bl)->dir=dir;
  2030. else if (bl->type == BL_MOB)
  2031. ((struct mob_data *)bl)->dir=dir;
  2032. clif_changed_dir(bl);
  2033. //skill_blown(src,bl,skill_get_blewcount(skillid,skilllv));
  2034. }
  2035. else if(src->type == BL_PC)
  2036. clif_skill_fail(sd,sd->skillid,0,0);
  2037. }
  2038. break;
  2039. case AM_ACIDTERROR: /* アシッドテラ? */
  2040. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  2041. if(bl->type == BL_PC && rand()%100 < skill_get_time(skillid,skilllv) && battle_config.equipment_breaking) {
  2042. pc_breakarmor((struct map_session_data *)bl);
  2043. clif_emotion(bl, 23);
  2044. }
  2045. break;
  2046. case MO_FINGEROFFENSIVE: /* 指? */
  2047. {
  2048. struct status_change *sc_data = status_get_sc_data(src);
  2049. if(!battle_config.finger_offensive_type)
  2050. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  2051. else {
  2052. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  2053. if(sd) {
  2054. for(i=1;i<sd->spiritball_old;i++)
  2055. skill_addtimerskill(src,tick+i*200,bl->id,0,0,skillid,skilllv,BF_WEAPON,flag);
  2056. sd->canmove_tick = tick + (sd->spiritball_old-1)*200;
  2057. }
  2058. }
  2059. if(sc_data && sc_data[SC_BLADESTOP].timer != -1)
  2060. status_change_end(src,SC_BLADESTOP,-1);
  2061. }
  2062. break;
  2063. case MO_CHAINCOMBO: /* 連打掌 */
  2064. {
  2065. struct status_change *sc_data = status_get_sc_data(src);
  2066. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  2067. if(sc_data && sc_data[SC_BLADESTOP].timer != -1)
  2068. status_change_end(src,SC_BLADESTOP,-1);
  2069. }
  2070. break;
  2071. case MO_COMBOFINISH: /* 猛龍拳 */
  2072. case CH_TIGERFIST: /* 伏虎拳 */
  2073. case CH_CHAINCRUSH: /* 連柱崩? */
  2074. case CH_PALMSTRIKE: /* 猛虎硬派山 */
  2075. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  2076. break;
  2077. case MO_EXTREMITYFIST: /* 阿修羅覇鳳拳 */
  2078. {
  2079. struct status_change *sc_data = status_get_sc_data(src);
  2080. if(sd) {
  2081. struct walkpath_data wpd;
  2082. int dx,dy;
  2083. dx = bl->x - sd->bl.x;
  2084. dy = bl->y - sd->bl.y;
  2085. if(dx > 0) dx++;
  2086. else if(dx < 0) dx--;
  2087. if(dy > 0) dy++;
  2088. else if(dy < 0) dy--;
  2089. if(dx == 0 && dy == 0) dx++;
  2090. if(path_search(&wpd,src->m,sd->bl.x,sd->bl.y,sd->bl.x+dx,sd->bl.y+dy,1) == -1) {
  2091. dx = bl->x - sd->bl.x;
  2092. dy = bl->y - sd->bl.y;
  2093. if(path_search(&wpd,src->m,sd->bl.x,sd->bl.y,sd->bl.x+dx,sd->bl.y+dy,1) == -1) {
  2094. clif_skill_fail(sd,sd->skillid,0,0);
  2095. break;
  2096. }
  2097. }
  2098. sd->to_x = sd->bl.x + dx;
  2099. sd->to_y = sd->bl.y + dy;
  2100. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  2101. clif_walkok(sd);
  2102. clif_movechar(sd);
  2103. if(dx < 0) dx = -dx;
  2104. if(dy < 0) dy = -dy;
  2105. sd->attackabletime = sd->canmove_tick = tick + 100 + sd->speed * ((dx > dy)? dx:dy);
  2106. if(sd->canact_tick < sd->canmove_tick)
  2107. sd->canact_tick = sd->canmove_tick;
  2108. pc_movepos(sd,sd->to_x,sd->to_y);
  2109. status_change_end(&sd->bl,SC_COMBO,-1);
  2110. }
  2111. else
  2112. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
  2113. status_change_end(src, SC_EXPLOSIONSPIRITS, -1);
  2114. if(sc_data && sc_data[SC_BLADESTOP].timer != -1)
  2115. status_change_end(src,SC_BLADESTOP,-1);
  2116. }
  2117. break;
  2118. /* 武器系範?攻?スキル */
  2119. case AC_SHOWER: /* アロ?シャワ? */
  2120. case AS_GRIMTOOTH: /* グリムトゥ?ス */
  2121. case MC_CARTREVOLUTION: /* カ?トレヴォリュ?ション */
  2122. case NPC_SPLASHATTACK: /* スプラッシュアタック */
  2123. case AS_SPLASHER: /* [Valaris] */
  2124. if(flag&1){
  2125. /* 個別にダメ?ジを?える */
  2126. if(bl->id!=skill_area_temp[1]){
  2127. int dist=0;
  2128. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,
  2129. 0x0500|dist );
  2130. if (bl->type == BL_MOB && skillid == AS_GRIMTOOTH) {
  2131. struct status_change *sc_data = status_get_sc_data(bl);
  2132. if (sc_data && sc_data[SC_SLOWDOWN].timer == -1)
  2133. status_change_start(bl,SC_SLOWDOWN,0,0,0,0,1000,0);
  2134. }
  2135. }
  2136. } else {
  2137. int ar;
  2138. int x = bl->x, y = bl->y;
  2139. switch (skillid) {
  2140. case AC_SHOWER:
  2141. ar=2;
  2142. break;
  2143. case NPC_SPLASHATTACK:
  2144. ar=3;
  2145. break;
  2146. default:
  2147. ar=1;
  2148. break;
  2149. }
  2150. skill_area_temp[1]=bl->id;
  2151. skill_area_temp[2]=x;
  2152. skill_area_temp[3]=y;
  2153. /* まずタ?ゲットに攻?を加える */
  2154. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0);
  2155. /* その後タ?ゲット以外の範??の敵全?に?理を行う */
  2156. map_foreachinarea(skill_area_sub,
  2157. bl->m,x-ar,y-ar,x+ar,y+ar,0,
  2158. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  2159. skill_castend_damage_id);
  2160. }
  2161. break;
  2162. case SM_MAGNUM: /* マグナムブレイク [celest] */
  2163. {
  2164. int dist = 0;
  2165. int dx = abs( bl->x - skill_area_temp[2] );
  2166. int dy = abs( bl->y - skill_area_temp[3] );
  2167. dist = ((dx>dy)?dx:dy);
  2168. map_foreachinarea (skill_attack_area,src->m,src->x-1,src->y-1,src->x+1,src->y+1,0,
  2169. BF_WEAPON,src,src,skillid,skilllv,tick,0x0500|dist,BCT_ENEMY);
  2170. status_change_start (src,SC_FLAMELAUNCHER,0,0,0,0,10000,0);
  2171. clif_skill_nodamage (src,src,skillid,skilllv,1);
  2172. }
  2173. break;
  2174. case KN_BOWLINGBASH: /* ボウリングバッシュ */
  2175. if(flag&1){
  2176. /* 個別にダメ?ジを?える */
  2177. if(bl->id!=skill_area_temp[1])
  2178. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0x0500);
  2179. } else {
  2180. int i,c; /* 他人から聞いた動きなので間違ってる可能性大&?率が?いっす>< */
  2181. /* まずターゲットに攻撃を加える */
  2182. if (!skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0))
  2183. break;
  2184. c = skill_get_blewcount(skillid,skilllv);
  2185. if(map[bl->m].flag.gvg) c = 0;
  2186. for(i=0;i<c;i++){
  2187. skill_blown(src,bl,1);
  2188. if(bl->type == BL_MOB)
  2189. clif_fixmobpos((struct mob_data *)bl);
  2190. else if(bl->type == BL_PET)
  2191. clif_fixpetpos((struct pet_data *)bl);
  2192. else
  2193. clif_fixpos(bl);
  2194. skill_area_temp[0]=0;
  2195. map_foreachinarea(skill_area_sub,
  2196. bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
  2197. src,skillid,skilllv,tick, flag|BCT_ENEMY ,
  2198. skill_area_sub_count);
  2199. if(skill_area_temp[0]>1) break;
  2200. }
  2201. skill_area_temp[1]=bl->id;
  2202. /* その後タ?ゲット以外の範??の敵全?に?理を行う */
  2203. map_foreachinarea(skill_area_sub,
  2204. bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
  2205. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  2206. skill_castend_damage_id);
  2207. }
  2208. break;
  2209. case KN_SPEARSTAB: /* スピアスタブ */
  2210. if(flag&1){
  2211. /* 個別にダメージを与える */
  2212. if (bl->id==skill_area_temp[1])
  2213. break;
  2214. if (skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0x0500))
  2215. skill_blown(src,bl,skill_area_temp[2]);
  2216. } else {
  2217. int x=bl->x,y=bl->y,i,dir;
  2218. /* まずターゲットに攻撃を加える */
  2219. dir = map_calc_dir(bl,src->x,src->y);
  2220. skill_area_temp[1] = bl->id;
  2221. skill_area_temp[2] = skill_get_blewcount(skillid,skilllv)|dir<<20;
  2222. if (skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0))
  2223. skill_blown(src,bl,skill_area_temp[2]);
  2224. for (i=0;i<4;i++) {
  2225. map_foreachinarea(skill_area_sub,bl->m,x,y,x,y,0,
  2226. src,skillid,skilllv,tick,flag|BCT_ENEMY|1,
  2227. skill_castend_damage_id);
  2228. x += dirx[dir];
  2229. y += diry[dir];
  2230. }
  2231. }
  2232. break;
  2233. case ALL_RESURRECTION: /* リザレクション */
  2234. case PR_TURNUNDEAD: /* タ?ンアンデッド */
  2235. if(bl->type != BL_PC && battle_check_undead(status_get_race(bl),status_get_elem_type(bl)))
  2236. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
  2237. else {
  2238. map_freeblock_unlock();
  2239. return 1;
  2240. }
  2241. break;
  2242. /* 魔法系スキル */
  2243. case MG_SOULSTRIKE: /* ソウルストライク */
  2244. case NPC_DARKSOULSTRIKE: /*闇ソウルストライク*/
  2245. case MG_COLDBOLT: /* コールドボルト */
  2246. case MG_FIREBOLT: /* ファイアーボルト */
  2247. case MG_LIGHTNINGBOLT: /* ライトニングボルト */
  2248. case WZ_EARTHSPIKE: /* アーススパイク */
  2249. case AL_HEAL: /* ヒール */
  2250. case AL_HOLYLIGHT: /* ホーリーライト */
  2251. case WZ_JUPITEL: /* ユピテルサンダー */
  2252. case NPC_DARKJUPITEL: /*闇ユピテル*/
  2253. case NPC_MAGICALATTACK: /* MOB:魔法打?攻? */
  2254. case PR_ASPERSIO: /* アスペルシオ */
  2255. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
  2256. break;
  2257. case MG_FROSTDIVER: /* フロストダイバー */
  2258. {
  2259. struct status_change *sc_data = status_get_sc_data(bl);
  2260. int sc_def_mdef, rate, damage;
  2261. sc_def_mdef = status_get_sc_def_mdef(bl);
  2262. rate = (skilllv*3+35)*sc_def_mdef/100-(status_get_int(bl)+status_get_luk(bl))/15;
  2263. rate = rate<=5?5:rate;
  2264. if (sc_data && sc_data[SC_FREEZE].timer != -1) {
  2265. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
  2266. if (sd)
  2267. clif_skill_fail(sd,skillid,0,0);
  2268. break;
  2269. }
  2270. damage = skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
  2271. if (status_get_hp(bl) > 0 && damage > 0 && rand()%100 < rate) {
  2272. status_change_start(bl,SC_FREEZE,skilllv,0,0,0,
  2273. skill_get_time2(skillid,skilllv)*(1-sc_def_mdef/100),0);
  2274. } else if (sd) {
  2275. clif_skill_fail(sd,skillid,0,0);
  2276. }
  2277. break;
  2278. }
  2279. case WZ_WATERBALL: /* ウォ?タ?ボ?ル */
  2280. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
  2281. if (skilllv>1) {
  2282. int cnt,range;
  2283. range = skilllv>5?2:skilllv/2;
  2284. if (sd)
  2285. cnt = skill_count_water(src,range)-1;
  2286. else
  2287. cnt = skill_get_num(skillid,skilllv)-1;
  2288. if (cnt>0)
  2289. skill_addtimerskill(src,tick+150,bl->id,0,0,
  2290. skillid,skilllv,cnt,flag);
  2291. }
  2292. break;
  2293. case PR_BENEDICTIO: /* 聖?降福 */
  2294. if(status_get_race(bl)==1 || status_get_race(bl)==6)
  2295. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
  2296. break;
  2297. /* 魔法系範?攻?スキル */
  2298. case MG_NAPALMBEAT: /* ナパ?ムビ?ト */
  2299. case MG_FIREBALL: /* ファイヤ?ボ?ル */
  2300. case WZ_SIGHTRASHER: /* サイトラッシャー */
  2301. if(flag&1){
  2302. /* 個別にダメ?ジを?える */
  2303. if(bl->id!=skill_area_temp[1]){
  2304. if(skillid==MG_FIREBALL){ /* ファイヤ?ボ?ルなら中心からの距離を計算 */
  2305. int dx=abs( bl->x - skill_area_temp[2] );
  2306. int dy=abs( bl->y - skill_area_temp[3] );
  2307. skill_area_temp[0]=((dx>dy)?dx:dy);
  2308. }
  2309. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,
  2310. skill_area_temp[0]| 0x0500);
  2311. }
  2312. }else{
  2313. int ar;
  2314. skill_area_temp[0]=0;
  2315. skill_area_temp[1]=bl->id;
  2316. switch (skillid) {
  2317. case MG_NAPALMBEAT:
  2318. ar = 1;
  2319. /* ナパームビートは分散ダメージなので敵の数を数える */
  2320. map_foreachinarea(skill_area_sub,
  2321. bl->m,bl->x-ar,bl->y-ar,bl->x+ar,bl->y+ar,0,
  2322. src,skillid,skilllv,tick,flag|BCT_ENEMY,
  2323. skill_area_sub_count);
  2324. break;
  2325. case MG_FIREBALL:
  2326. ar = 2;
  2327. skill_area_temp[2]=bl->x;
  2328. skill_area_temp[3]=bl->y;
  2329. /* ターゲットに攻撃を加える(スキルエフェクト表示) */
  2330. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,
  2331. skill_area_temp[0]);
  2332. break;
  2333. case WZ_SIGHTRASHER:
  2334. default:
  2335. ar = 3;
  2336. bl = src;
  2337. status_change_end(src,SC_SIGHT,-1);
  2338. break;
  2339. }
  2340. if (skillid==WZ_SIGHTRASHER) {
  2341. /* スキルエフェクト表示 */
  2342. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2343. } else {
  2344. /* ターゲットに攻撃を加える(スキルエフェクト表示) */
  2345. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,
  2346. skill_area_temp[0]);
  2347. }
  2348. /* ターゲット以外の範囲内の敵全体に処理を行う */
  2349. map_foreachinarea(skill_area_sub,
  2350. bl->m,bl->x-ar,bl->y-ar,bl->x+ar,bl->y+ar,0,
  2351. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  2352. skill_castend_damage_id);
  2353. }
  2354. break;
  2355. case HW_NAPALMVULCAN: // Fixed By SteelViruZ
  2356. if(flag&1){
  2357. if(bl->id!=skill_area_temp[1]){
  2358. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,
  2359. skill_area_temp[0]);
  2360. }
  2361. }else{
  2362. int ar=(skillid==HW_NAPALMVULCAN)?1:2;
  2363. skill_area_temp[1]=bl->id;
  2364. if(skillid==HW_NAPALMVULCAN){
  2365. skill_area_temp[0]=0;
  2366. map_foreachinarea(skill_area_sub,
  2367. bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
  2368. src,skillid,skilllv,tick, flag|BCT_ENEMY ,
  2369. skill_area_sub_count);
  2370. }else{
  2371. skill_area_temp[0]=0;
  2372. skill_area_temp[2]=bl->x;
  2373. skill_area_temp[3]=bl->y;
  2374. }
  2375. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,
  2376. skill_area_temp[0] );
  2377. map_foreachinarea(skill_area_sub,
  2378. bl->m,bl->x-ar,bl->y-ar,bl->x+ar,bl->y+ar,0,
  2379. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  2380. skill_castend_damage_id);
  2381. }
  2382. break;
  2383. case WZ_FROSTNOVA: /* フロストノヴァ */
  2384. //skill_castend_pos2(src,bl->x,bl->y,skillid,skilllv,tick,0);
  2385. //skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
  2386. map_foreachinarea(skill_attack_area,src->m,src->x-5,bl->y-5,bl->x+5,bl->y+5,0,BF_MAGIC,src,src,skillid,skilllv,tick,flag,BCT_ENEMY);
  2387. break;
  2388. /* その他 */
  2389. case HT_BLITZBEAT: /* ブリッツビ?ト */
  2390. if(flag&1){
  2391. /* 個別にダメ?ジを?える */
  2392. if(bl->id!=skill_area_temp[1])
  2393. skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,skill_area_temp[0]|(flag&0xf00000));
  2394. }else{
  2395. skill_area_temp[0]=0;
  2396. skill_area_temp[1]=bl->id;
  2397. if(flag&0xf00000)
  2398. map_foreachinarea(skill_area_sub,bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
  2399. src,skillid,skilllv,tick, flag|BCT_ENEMY ,skill_area_sub_count);
  2400. /* まずタ?ゲットに攻?を加える */
  2401. skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,skill_area_temp[0]|(flag&0xf00000));
  2402. /* その後タ?ゲット以外の範??の敵全?に?理を行う */
  2403. map_foreachinarea(skill_area_sub,
  2404. bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
  2405. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  2406. skill_castend_damage_id);
  2407. }
  2408. break;
  2409. case CR_GRANDCROSS: /* グランドクロス */
  2410. case NPC_DARKGRANDCROSS: /*闇グランドクロス*/
  2411. /* スキルユニット配置 */
  2412. skill_castend_pos2(src,bl->x,bl->y,skillid,skilllv,tick,0);
  2413. if(sd)
  2414. sd->canmove_tick = tick + 1000;
  2415. else if(src->type == BL_MOB)
  2416. mob_changestate((struct mob_data *)src,MS_DELAY,1000);
  2417. break;
  2418. case TF_THROWSTONE: /* 石投げ */
  2419. case NPC_SMOKING: /* スモ?キング */
  2420. skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,0 );
  2421. break;
  2422. // Celest
  2423. case PF_SOULBURN:
  2424. {
  2425. int per = skilllv < 5 ? 20+ skilllv*10 : 60;
  2426. if (rand()%100 < per) {
  2427. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2428. if (skilllv == 5)
  2429. skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,0 );
  2430. if (bl->type == BL_PC && (map[src->m].flag.pvp || map[src->m].flag.gvg)) {
  2431. struct map_session_data *tsd = (struct map_session_data *)bl;
  2432. if (tsd) {
  2433. tsd->status.sp = 0;
  2434. clif_updatestatus(tsd,SP_SP);
  2435. }
  2436. }
  2437. } else {
  2438. clif_skill_nodamage(src,src,skillid,skilllv,1);
  2439. if (skilllv == 5)
  2440. skill_attack(BF_MAGIC,src,src,src,skillid,skilllv,tick,0 );
  2441. if (sd) {
  2442. sd->status.sp = 0;
  2443. clif_updatestatus(sd,SP_SP);
  2444. }
  2445. }
  2446. if (sd)
  2447. pc_blockskill_start (sd, skillid, (skilllv < 5 ? 10000: 15000));
  2448. }
  2449. break;
  2450. case NPC_SELFDESTRUCTION: /* 自爆 */
  2451. case NPC_SELFDESTRUCTION2: /* 自爆2 */
  2452. if(flag&1){
  2453. /* 個別にダメ?ジを?える */
  2454. if(src->type==BL_MOB){
  2455. struct mob_data* mb = (struct mob_data*)src;
  2456. nullpo_retr(1, mb);
  2457. mb->hp=skill_area_temp[2];
  2458. if(bl->id!=skill_area_temp[1])
  2459. skill_attack(BF_MISC,src,src,bl,NPC_SELFDESTRUCTION,skilllv,tick,flag );
  2460. mb->hp=1;
  2461. }
  2462. }else{
  2463. struct mob_data *md;
  2464. if((md=(struct mob_data *)src)){
  2465. skill_area_temp[1]=bl->id;
  2466. skill_area_temp[2]=status_get_hp(src);
  2467. clif_skill_nodamage(src,src,NPC_SELFDESTRUCTION,-1,1);
  2468. map_foreachinarea(skill_area_sub,
  2469. bl->m,bl->x-5,bl->y-5,bl->x+5,bl->y+5,0,
  2470. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  2471. skill_castend_damage_id);
  2472. battle_damage(src,src,md->hp,0);
  2473. }
  2474. }
  2475. break;
  2476. /* HP吸?/HP吸?魔法 */
  2477. case NPC_BLOODDRAIN:
  2478. case NPC_ENERGYDRAIN:
  2479. {
  2480. int heal;
  2481. heal = skill_attack((skillid==NPC_BLOODDRAIN)?BF_WEAPON:BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
  2482. if( heal > 0 ){
  2483. struct block_list tbl;
  2484. tbl.id = 0;
  2485. tbl.m = src->m;
  2486. tbl.x = src->x;
  2487. tbl.y = src->y;
  2488. clif_skill_nodamage(&tbl,src,AL_HEAL,heal,1);
  2489. battle_heal(NULL,src,heal,0,0);
  2490. }
  2491. }
  2492. break;
  2493. // unknown skills [Celest]
  2494. case NPC_BIND:
  2495. case NPC_EXPLOSIONSPIRITS:
  2496. case NPC_INCAGI:
  2497. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2498. break;
  2499. case 0:
  2500. if(sd) {
  2501. if(flag&3){
  2502. if(bl->id!=skill_area_temp[1])
  2503. skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0x0500);
  2504. }
  2505. else{
  2506. int ar=sd->splash_range;
  2507. skill_area_temp[1]=bl->id;
  2508. map_foreachinarea(skill_area_sub,
  2509. bl->m, bl->x - ar, bl->y - ar, bl->x + ar, bl->y + ar, 0,
  2510. src, skillid, skilllv, tick, flag | BCT_ENEMY | 1,
  2511. skill_castend_damage_id);
  2512. }
  2513. }
  2514. break;
  2515. default:
  2516. printf("Unknown skill used:%d\n",skillid);
  2517. map_freeblock_unlock();
  2518. return 1;
  2519. }
  2520. if(sc_data) {
  2521. if (sc_data[SC_MAGICPOWER].timer != -1 && skillid != HW_MAGICPOWER) //マジックパワ?の?果終了
  2522. status_change_end(src,SC_MAGICPOWER,-1);
  2523. }
  2524. map_freeblock_unlock();
  2525. return 0;
  2526. }
  2527. /*==========================================
  2528. * スキル使用(詠唱完了、ID指定支援系)
  2529. *------------------------------------------
  2530. */
  2531. int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag )
  2532. {
  2533. struct map_session_data *sd=NULL;
  2534. struct map_session_data *dstsd=NULL;
  2535. struct mob_data *md=NULL;
  2536. struct mob_data *dstmd=NULL;
  2537. int i,abra_skillid=0,abra_skilllv;
  2538. int sc_def_vit,sc_def_mdef,strip_time,strip_per;
  2539. int sc_dex,sc_luk;
  2540. //クラスチェンジ用ボスモンスタ?ID
  2541. int changeclass[]={1038,1039,1046,1059,1086,1087,1112,1115
  2542. ,1157,1159,1190,1272,1312,1373,1492};
  2543. int poringclass[]={1002};
  2544. if(skillid < 0)
  2545. { // remove the debug print when this case is finished
  2546. printf("skill_castend_damage_id: skillid=%i\ncall: %p %p %i %i %i %i",skillid,
  2547. src, bl,skillid,skilllv,tick,flag);
  2548. return 0;
  2549. }
  2550. if(skillid > 0 && skilllv <= 0) return 0; // celest
  2551. nullpo_retr(1, src);
  2552. nullpo_retr(1, bl);
  2553. if(src->type==BL_PC)
  2554. sd=(struct map_session_data *)src;
  2555. else if(src->type==BL_MOB)
  2556. md=(struct mob_data *)src;
  2557. sc_dex=status_get_mdef(bl);
  2558. sc_luk=status_get_luk(bl);
  2559. sc_def_vit = status_get_sc_def_vit(bl);
  2560. sc_def_mdef = status_get_sc_def_mdef (bl);
  2561. if(bl->type==BL_PC){
  2562. nullpo_retr(1, dstsd=(struct map_session_data *)bl);
  2563. }else if(bl->type==BL_MOB){
  2564. nullpo_retr(1, dstmd=(struct mob_data *)bl);
  2565. }
  2566. if(bl == NULL || bl->prev == NULL)
  2567. return 1;
  2568. if(sd && pc_isdead(sd))
  2569. return 1;
  2570. if(dstsd && pc_isdead(dstsd) && skillid != ALL_RESURRECTION)
  2571. return 1;
  2572. if(status_get_class(bl) == 1288)
  2573. return 1;
  2574. if (sd && skillnotok(skillid, sd)) // [MouseJstr]
  2575. return 0;
  2576. map_freeblock_lock();
  2577. switch(skillid)
  2578. {
  2579. case AL_HEAL: /* ヒ?ル */
  2580. {
  2581. int heal=skill_calc_heal( src, skilllv );
  2582. int heal_get_jobexp;
  2583. int skill;
  2584. struct pc_base_job s_class;
  2585. if( dstsd && dstsd->special_state.no_magic_damage )
  2586. heal=0; /* ?金蟲カ?ド(ヒ?ル量0) */
  2587. if (sd){
  2588. s_class = pc_calc_base_job(sd->status.class_);
  2589. if((skill=pc_checkskill(sd,HP_MEDITATIO))>0) // メディテイティオ
  2590. heal += heal*skill*2/100;
  2591. if(sd && dstsd && sd->status.partner_id == dstsd->status.char_id && s_class.job == 23 && sd->status.sex == 0) //自分も?象もPC、?象が自分のパ?トナ?、自分がスパノビ、自分が♀なら
  2592. heal = heal*2; //スパノビの嫁が旦那にヒ?ルすると2倍になる
  2593. }
  2594. clif_skill_nodamage(src,bl,skillid,heal,1);
  2595. heal_get_jobexp = battle_heal(NULL,bl,heal,0,0);
  2596. // JOB??値獲得
  2597. if(src->type == BL_PC && bl->type==BL_PC && heal > 0 && src != bl && battle_config.heal_exp > 0){
  2598. heal_get_jobexp = heal_get_jobexp * battle_config.heal_exp / 100;
  2599. if(heal_get_jobexp <= 0)
  2600. heal_get_jobexp = 1;
  2601. pc_gainexp((struct map_session_data *)src,0,heal_get_jobexp);
  2602. }
  2603. }
  2604. break;
  2605. case ALL_RESURRECTION: /* リザレクション */
  2606. if(bl->type==BL_PC){
  2607. int per=0;
  2608. struct map_session_data *tsd = (struct map_session_data*)bl;
  2609. nullpo_retr(1, tsd);
  2610. if( (map[bl->m].flag.pvp) && tsd->pvp_point<0 )
  2611. break; /* PVPで復活不可能?態 */
  2612. if(pc_isdead(tsd)){ /* 死亡判定 */
  2613. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2614. switch(skilllv){
  2615. case 1: per=10; break;
  2616. case 2: per=30; break;
  2617. case 3: per=50; break;
  2618. case 4: per=80; break;
  2619. }
  2620. tsd->status.hp=tsd->status.max_hp*per/100;
  2621. if(tsd->status.hp<=0) tsd->status.hp=1;
  2622. if(tsd->special_state.restart_full_recover ){ /* オシリスカ?ド */
  2623. tsd->status.hp=tsd->status.max_hp;
  2624. tsd->status.sp=tsd->status.max_sp;
  2625. }
  2626. pc_setstand(tsd);
  2627. if(battle_config.pc_invincible_time > 0)
  2628. pc_setinvincibletimer(tsd,battle_config.pc_invincible_time);
  2629. clif_updatestatus(tsd,SP_HP);
  2630. clif_resurrection(&tsd->bl,1);
  2631. if(src != bl && sd && battle_config.resurrection_exp > 0) {
  2632. int exp = 0,jexp = 0;
  2633. int lv = tsd->status.base_level - sd->status.base_level, jlv = tsd->status.job_level - sd->status.job_level;
  2634. if(lv > 0) {
  2635. exp = (int)((double)tsd->status.base_exp * (double)lv * (double)battle_config.resurrection_exp / 1000000.);
  2636. if(exp < 1) exp = 1;
  2637. }
  2638. if(jlv > 0) {
  2639. jexp = (int)((double)tsd->status.job_exp * (double)lv * (double)battle_config.resurrection_exp / 1000000.);
  2640. if(jexp < 1) jexp = 1;
  2641. }
  2642. if(exp > 0 || jexp > 0)
  2643. pc_gainexp(sd,exp,jexp);
  2644. }
  2645. }
  2646. }
  2647. break;
  2648. case AL_DECAGI: /* 速度減少 */
  2649. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  2650. break;
  2651. if( rand()%100 < (50+skilllv*3+(status_get_lv(src)+status_get_int(src)/5)-sc_def_mdef) ) {
  2652. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2653. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
  2654. }
  2655. break;
  2656. case AL_CRUCIS:
  2657. if(flag&1) {
  2658. int race = status_get_race(bl),ele = status_get_elem_type(bl);
  2659. if(battle_check_target(src,bl,BCT_ENEMY) && (race == 6 || battle_check_undead(race,ele))) {
  2660. int slv=status_get_lv(src),tlv=status_get_lv(bl),rate;
  2661. rate = 25 + skilllv*2 + slv - tlv;
  2662. if(rand()%100 < rate)
  2663. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,0,0);
  2664. }
  2665. }
  2666. else {
  2667. int range = 15;
  2668. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2669. map_foreachinarea(skill_area_sub,
  2670. src->m,src->x-range,src->y-range,src->x+range,src->y+range,0,
  2671. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  2672. skill_castend_nodamage_id);
  2673. }
  2674. break;
  2675. case PR_LEXDIVINA: /* レックスディビ?ナ */
  2676. {
  2677. struct status_change *sc_data = status_get_sc_data(bl);
  2678. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2679. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  2680. break;
  2681. if(sc_data && sc_data[SC_DIVINA].timer != -1)
  2682. status_change_end(bl,SC_DIVINA,-1);
  2683. else if( rand()%100 < sc_def_vit ) {
  2684. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
  2685. }
  2686. }
  2687. break;
  2688. case SA_ABRACADABRA:
  2689. //require 1 yellow gemstone even with mistress card or Into the Abyss
  2690. if ((i=pc_search_inventory(sd, 715)) < 0 ) { //bug fixed by Lupus (item pos can be 0, too!)
  2691. clif_skill_fail(sd,sd->skillid,0,0);
  2692. break;
  2693. }
  2694. //pc_delitem(sd, pc_search_inventory(sd, 715), 1, 0);
  2695. pc_delitem(sd, i, 1, 0);
  2696. //
  2697. do{
  2698. abra_skillid=skill_abra_dataset(skilllv);
  2699. }while(abra_skillid == 0);
  2700. abra_skilllv=skill_get_max(abra_skillid)>pc_checkskill(sd,SA_ABRACADABRA)?pc_checkskill(sd,SA_ABRACADABRA):skill_get_max(abra_skillid);
  2701. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2702. sd->skillitem=abra_skillid;
  2703. sd->skillitemlv=abra_skilllv;
  2704. clif_item_skill(sd,abra_skillid,abra_skilllv,"アブラカダブラ");
  2705. break;
  2706. case SA_COMA:
  2707. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2708. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  2709. break;
  2710. if(dstsd){
  2711. dstsd->status.hp=1;
  2712. dstsd->status.sp=1;
  2713. clif_updatestatus(dstsd,SP_HP);
  2714. clif_updatestatus(dstsd,SP_SP);
  2715. }
  2716. if(dstmd) dstmd->hp=1;
  2717. break;
  2718. case SA_FULLRECOVERY:
  2719. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2720. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  2721. break;
  2722. if(dstsd) pc_heal(dstsd,dstsd->status.max_hp,dstsd->status.max_sp);
  2723. if(dstmd) dstmd->hp=status_get_max_hp(&dstmd->bl);
  2724. break;
  2725. case SA_SUMMONMONSTER:
  2726. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2727. if (sd) mob_once_spawn(sd,map[sd->bl.m].name,sd->bl.x,sd->bl.y,"--ja--",-1,1,"");
  2728. break;
  2729. case SA_LEVELUP:
  2730. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2731. if (sd && pc_nextbaseexp(sd)) pc_gainexp(sd,pc_nextbaseexp(sd)*10/100,0);
  2732. break;
  2733. case SA_INSTANTDEATH:
  2734. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2735. if (sd) pc_damage(NULL,sd,sd->status.max_hp);
  2736. break;
  2737. case SA_QUESTION:
  2738. case SA_GRAVITY:
  2739. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2740. break;
  2741. case SA_CLASSCHANGE:
  2742. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2743. if(dstmd) mob_class_change(dstmd,changeclass);
  2744. break;
  2745. case SA_MONOCELL:
  2746. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2747. if(dstmd) mob_class_change(dstmd,poringclass);
  2748. break;
  2749. case SA_DEATH:
  2750. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2751. if (dstsd) pc_damage(NULL,dstsd,dstsd->status.max_hp);
  2752. if (dstmd) mob_damage(NULL,dstmd,dstmd->hp,1);
  2753. break;
  2754. case SA_REVERSEORCISH:
  2755. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2756. if (dstsd) pc_setoption(dstsd,dstsd->status.option|0x0800);
  2757. break;
  2758. case SA_FORTUNE:
  2759. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2760. if(sd) pc_getzeny(sd,status_get_lv(bl)*100);
  2761. break;
  2762. case SA_TAMINGMONSTER:
  2763. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2764. if (dstmd){
  2765. for(i=0;i<MAX_PET_DB;i++){
  2766. if(dstmd->class_ == pet_db[i].class_){
  2767. pet_catch_process1(sd,dstmd->class_);
  2768. break;
  2769. }
  2770. }
  2771. }
  2772. break;
  2773. case AL_INCAGI: /* 速度?加 */
  2774. case AL_BLESSING: /* ブレッシング */
  2775. case PR_SLOWPOISON:
  2776. case PR_IMPOSITIO: /* イムポシティオマヌス */
  2777. case PR_LEXAETERNA: /* レックスエ?テルナ */
  2778. case PR_SUFFRAGIUM: /* サフラギウム */
  2779. case PR_BENEDICTIO: /* 聖?降福 */
  2780. case CR_PROVIDENCE: /* プロヴィデンス */
  2781. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage ){
  2782. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2783. }else{
  2784. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2785. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2786. }
  2787. break;
  2788. case CG_MARIONETTE: /* マリオネットコントロ?ル */
  2789. if(sd && dstsd){
  2790. struct status_change *sc_data = status_get_sc_data(src);
  2791. struct status_change *tsc_data = status_get_sc_data(bl);
  2792. int sc = SkillStatusChangeTable[skillid];
  2793. int sc2 = SC_MARIONETTE2;
  2794. if((dstsd->bl.type!=BL_PC)
  2795. || (sd->bl.id == dstsd->bl.id)
  2796. || (!sd->status.party_id)
  2797. || (sd->status.party_id != dstsd->status.party_id)) {
  2798. clif_skill_fail(sd,skillid,0,0);
  2799. map_freeblock_unlock();
  2800. return 1;
  2801. }
  2802. if(sc_data && tsc_data){
  2803. if(sc_data[sc].timer == -1 && tsc_data[sc2].timer == -1) {
  2804. status_change_start (src,sc,skilllv,0,bl->id,0,skill_get_time(skillid,skilllv),0);
  2805. status_change_start (bl,sc2,skilllv,0,src->id,0,skill_get_time(skillid,skilllv),0);
  2806. }
  2807. else if (sc_data[sc].timer != -1 && tsc_data[sc2].timer != -1 &&
  2808. sc_data[sc].val3 == bl->id && tsc_data[sc2].val3 == src->id) {
  2809. status_change_end(src, sc, -1);
  2810. status_change_end(bl, sc2, -1);
  2811. }
  2812. else {
  2813. clif_skill_fail(sd,skillid,0,0);
  2814. map_freeblock_unlock();
  2815. return 1;
  2816. }
  2817. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2818. }
  2819. }
  2820. break;
  2821. case SA_FLAMELAUNCHER: // added failure chance and chance to break weapon if turned on [Valaris]
  2822. case SA_FROSTWEAPON:
  2823. case SA_LIGHTNINGLOADER:
  2824. case SA_SEISMICWEAPON:
  2825. if(bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage ){
  2826. clif_skill_nodamage(src,bl,skillid,skilllv,0);
  2827. break;
  2828. }
  2829. if(bl->type==BL_PC) {
  2830. struct map_session_data *sd2=(struct map_session_data *)bl;
  2831. if(sd2->status.weapon==0 || sd2->sc_data[SC_FLAMELAUNCHER].timer!=-1 || sd2->sc_data[SC_FROSTWEAPON].timer!=-1 ||
  2832. sd2->sc_data[SC_LIGHTNINGLOADER].timer!=-1 || sd2->sc_data[SC_SEISMICWEAPON].timer!=-1 ||
  2833. sd2->sc_data[SC_ENCPOISON].timer!=-1) {
  2834. clif_skill_fail(sd,skillid,0,0);
  2835. clif_skill_nodamage(src,bl,skillid,skilllv,0);
  2836. break;
  2837. }
  2838. }
  2839. if(skilllv < 5 && rand()%100 > (60+skilllv*10) ) { //fixed by Lupus (4 -> 5) or else it has 100% success even at lv4
  2840. clif_skill_fail(sd,skillid,0,0);
  2841. clif_skill_nodamage(src,bl,skillid,skilllv,0);
  2842. if(bl->type==BL_PC && battle_config.equipment_breaking) {
  2843. struct map_session_data *sd2=(struct map_session_data *)bl;
  2844. if(sd!=sd2) clif_displaymessage(sd->fd,"You broke target's weapon");
  2845. pc_breakweapon(sd2);
  2846. }
  2847. break;
  2848. }
  2849. else {
  2850. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2851. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2852. }
  2853. break;
  2854. case PR_ASPERSIO: /* アスペルシオ */
  2855. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2856. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  2857. break;
  2858. if(bl->type==BL_MOB)
  2859. break;
  2860. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2861. break;
  2862. case PR_KYRIE: /* キリエエレイソン */
  2863. clif_skill_nodamage(bl,bl,skillid,skilllv,1);
  2864. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  2865. break;
  2866. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2867. break;
  2868. case KN_AUTOCOUNTER: /* オ?トカウンタ? */
  2869. case KN_TWOHANDQUICKEN: /* ツ?ハンドクイッケン */
  2870. case CR_SPEARQUICKEN: /* スピアクイッケン */
  2871. case CR_REFLECTSHIELD:
  2872. case AS_POISONREACT: /* ポイズンリアクト */
  2873. case MC_LOUD: /* ラウドボイス */
  2874. case MG_ENERGYCOAT: /* エナジ?コ?ト */
  2875. // case SM_ENDURE: /* インデュア */
  2876. case MG_SIGHT: /* サイト */
  2877. case AL_RUWACH: /* ルアフ */
  2878. case MO_EXPLOSIONSPIRITS: // 爆裂波動
  2879. case MO_STEELBODY: // 金剛
  2880. case LK_AURABLADE: /* オ?ラブレ?ド */
  2881. case LK_PARRYING: /* パリイング */
  2882. case LK_CONCENTRATION: /* コンセントレ?ション */
  2883. // case LK_BERSERK: /* バ?サ?ク */
  2884. case HP_ASSUMPTIO: /* */
  2885. case WS_CARTBOOST: /* カ?トブ?スト */
  2886. case SN_SIGHT: /* トゥル?サイト */
  2887. case WS_MELTDOWN: /* メルトダウン */
  2888. case ST_REJECTSWORD: /* リジェクトソ?ド */
  2889. case HW_MAGICPOWER: /* 魔法力?幅 */
  2890. case PF_MEMORIZE: /* メモライズ */
  2891. case PA_SACRIFICE:
  2892. case ASC_EDP: // [Celest]
  2893. case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
  2894. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2895. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2896. break;
  2897. case SM_ENDURE: /* インデュア */
  2898. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2899. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2900. if (sd)
  2901. pc_blockskill_start (sd, skillid, 10000);
  2902. break;
  2903. case SM_AUTOBERSERK: // Celest
  2904. {
  2905. struct status_change *tsc_data = status_get_sc_data(bl);
  2906. int sc=SkillStatusChangeTable[skillid];
  2907. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2908. if( tsc_data ){
  2909. if( tsc_data[sc].timer==-1 )
  2910. status_change_start(bl,sc,skilllv,0,0,0,0,0);
  2911. else
  2912. status_change_end(bl, sc, -1);
  2913. }
  2914. }
  2915. break;
  2916. case AS_ENCHANTPOISON: // Prevent spamming [Valaris]
  2917. if(bl->type==BL_PC) {
  2918. struct map_session_data *sd2=(struct map_session_data *)bl;
  2919. if(sd2->sc_data[SC_FLAMELAUNCHER].timer!=-1 || sd2->sc_data[SC_FROSTWEAPON].timer!=-1 ||
  2920. sd2->sc_data[SC_LIGHTNINGLOADER].timer!=-1 || sd2->sc_data[SC_SEISMICWEAPON].timer!=-1 ||
  2921. sd2->sc_data[SC_ENCPOISON].timer!=-1) {
  2922. clif_skill_nodamage(src,bl,skillid,skilllv,0);
  2923. clif_skill_fail(sd,skillid,0,0);
  2924. break;
  2925. }
  2926. }
  2927. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2928. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2929. break;
  2930. case LK_TENSIONRELAX: /* テンションリラックス */
  2931. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2932. pc_setsit(sd);
  2933. clif_sitting(sd);
  2934. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2935. break;
  2936. case LK_BERSERK: /* バ?サ?ク */
  2937. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2938. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2939. //sd->status.hp = sd->status.max_hp * 3;
  2940. break;
  2941. case MC_CHANGECART:
  2942. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2943. break;
  2944. case AC_CONCENTRATION: /* 集中力向上 */
  2945. {
  2946. int range = 1;
  2947. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2948. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2949. map_foreachinarea( status_change_timer_sub,
  2950. src->m, src->x-range, src->y-range, src->x+range,src->y+range,0,
  2951. src,SkillStatusChangeTable[skillid],tick);
  2952. }
  2953. break;
  2954. case SM_PROVOKE: /* プロボック */
  2955. {
  2956. struct status_change *sc_data = status_get_sc_data(bl);
  2957. /* MVPmobと不死には?かない */
  2958. if((bl->type==BL_MOB && status_get_mode(bl)&0x20) || battle_check_undead(status_get_race(bl),status_get_elem_type(bl))) //不死には?かない
  2959. {
  2960. map_freeblock_unlock();
  2961. return 1;
  2962. }
  2963. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  2964. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  2965. if(dstmd && dstmd->skilltimer!=-1 && dstmd->state.skillcastcancel) // 詠唱妨害
  2966. skill_castcancel(bl,0);
  2967. if(dstsd && dstsd->skilltimer!=-1 && (!dstsd->special_state.no_castcancel || map[bl->m].flag.gvg)
  2968. && dstsd->state.skillcastcancel && !dstsd->special_state.no_castcancel2)
  2969. skill_castcancel(bl,0);
  2970. if(sc_data){
  2971. if(sc_data[SC_FREEZE].timer!=-1)
  2972. status_change_end(bl,SC_FREEZE,-1);
  2973. if(sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2==0)
  2974. status_change_end(bl,SC_STONE,-1);
  2975. if(sc_data[SC_SLEEP].timer!=-1)
  2976. status_change_end(bl,SC_SLEEP,-1);
  2977. }
  2978. if(dstmd) {
  2979. int range = skill_get_range(skillid,skilllv);
  2980. if(range < 0)
  2981. range = status_get_range(src) - (range + 1);
  2982. dstmd->state.provoke_flag = src->id;
  2983. mob_target(dstmd,src,range);
  2984. }
  2985. }
  2986. break;
  2987. case CR_DEVOTION: /* ディボ?ション */
  2988. if(sd && dstsd){
  2989. //?生や養子の場合の元の職業を算出する
  2990. struct pc_base_job dst_s_class = pc_calc_base_job(dstsd->status.class_);
  2991. int lv = sd->status.base_level-dstsd->status.base_level;
  2992. lv = (lv<0)?-lv:lv;
  2993. if((dstsd->bl.type!=BL_PC) // 相手はPCじゃないとだめ
  2994. ||(sd->bl.id == dstsd->bl.id) // 相手が自分はだめ
  2995. ||(lv > battle_config.devotion_level_difference) // レベル差±10まで
  2996. ||(!sd->status.party_id && !sd->status.guild_id) // PTにもギルドにも所?無しはだめ
  2997. ||((sd->status.party_id != dstsd->status.party_id) // 同じパ?ティ?か、
  2998. &&(sd->status.guild_id != dstsd->status.guild_id)) // 同じギルドじゃないとだめ
  2999. ||(dst_s_class.job==14||dst_s_class.job==21)){ // クルセだめ
  3000. clif_skill_fail(sd,skillid,0,0);
  3001. map_freeblock_unlock();
  3002. return 1;
  3003. }
  3004. for(i=0;i<skilllv;i++){
  3005. if(!sd->dev.val1[i]){ // 空きがあったら入れる
  3006. sd->dev.val1[i] = bl->id;
  3007. sd->dev.val2[i] = bl->id;
  3008. break;
  3009. }else if(i==skilllv-1){ // 空きがなかった
  3010. clif_skill_fail(sd,skillid,0,0);
  3011. map_freeblock_unlock();
  3012. return 1;
  3013. }
  3014. }
  3015. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3016. clif_devotion(sd,bl->id);
  3017. status_change_start(bl,SkillStatusChangeTable[skillid],src->id,1,0,0,1000*(15+15*skilllv),0 );
  3018. }
  3019. else clif_skill_fail(sd,skillid,0,0);
  3020. break;
  3021. case MO_CALLSPIRITS: // ?功
  3022. if(sd) {
  3023. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3024. pc_addspiritball(sd,skill_get_time(skillid,skilllv),skilllv);
  3025. }
  3026. break;
  3027. case CH_SOULCOLLECT: // 狂?功
  3028. if(sd) {
  3029. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3030. for(i=0;i<5;i++)
  3031. pc_addspiritball(sd,skill_get_time(skillid,skilllv),5);
  3032. }
  3033. break;
  3034. case MO_BLADESTOP: // 白刃取り
  3035. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3036. status_change_start(src,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  3037. break;
  3038. case MO_ABSORBSPIRITS: // ?奪
  3039. i=0;
  3040. if(dstsd) {
  3041. if((sd && sd == dstsd) || map[src->m].flag.pvp || map[src->m].flag.gvg) {
  3042. if(dstsd->spiritball > 0) {
  3043. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3044. i = dstsd->spiritball * 7;
  3045. pc_delspiritball(dstsd,dstsd->spiritball,0);
  3046. if(i > 0x7FFF)
  3047. i = 0x7FFF;
  3048. if(sd && sd->status.sp + i > sd->status.max_sp)
  3049. i = sd->status.max_sp - sd->status.sp;
  3050. }
  3051. }
  3052. } else if (dstmd){ //?象がモンスタ?の場合
  3053. //20%の確率で?象のLv*2のSPを回復する。成功したときはタ?ゲット(σ?Д?)σ????!!
  3054. if(rand()%100<20){
  3055. i=2*mob_db[dstmd->class_].lv;
  3056. mob_target(dstmd,src,0);
  3057. }
  3058. }
  3059. if(i && sd){
  3060. sd->status.sp += i;
  3061. clif_heal(sd->fd,SP_SP,i);
  3062. } else clif_skill_nodamage(src,bl,skillid,skilllv,0);
  3063. break;
  3064. case AC_MAKINGARROW: /* 矢作成 */
  3065. if(sd) {
  3066. clif_arrow_create_list(sd);
  3067. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3068. }
  3069. break;
  3070. case AM_PHARMACY: /* ポ?ション作成 */
  3071. if(sd) {
  3072. clif_skill_produce_mix_list(sd,32);
  3073. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3074. }
  3075. break;
  3076. case WS_CREATECOIN: /* クリエイトコイン */
  3077. if(sd) {
  3078. clif_skill_produce_mix_list(sd,64);
  3079. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3080. }
  3081. break;
  3082. case WS_CREATENUGGET: /* 塊製造 */
  3083. if(sd) {
  3084. clif_skill_produce_mix_list(sd,128);
  3085. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3086. }
  3087. break;
  3088. case ASC_CDP: // [DracoRPG]
  3089. // notes: success rate (from emperium.org) = 20 + [(20*Dex)/50] + [(20*Luk)/100]
  3090. if(sd) {
  3091. clif_skill_produce_mix_list(sd,256);
  3092. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3093. }
  3094. break;
  3095. case BS_HAMMERFALL: /* ハンマ?フォ?ル */
  3096. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3097. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_weapon_damage )
  3098. break;
  3099. if( rand()%100 < (20+ 10*skilllv)*sc_def_vit/100 ) {
  3100. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  3101. }
  3102. break;
  3103. case RG_RAID: /* サプライズアタック */
  3104. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3105. map_foreachinarea(skill_area_sub,
  3106. bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
  3107. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  3108. skill_castend_damage_id);
  3109. status_change_end(src, SC_HIDING, -1); // ハイディング解除
  3110. break;
  3111. case ASC_METEORASSAULT: /* メテオアサルト */
  3112. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3113. map_foreachinarea(skill_area_sub,
  3114. bl->m,bl->x-2,bl->y-2,bl->x+2,bl->y+2,0,
  3115. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  3116. skill_castend_damage_id);
  3117. break;
  3118. case KN_BRANDISHSPEAR: /*ブランディッシュスピア*/
  3119. {
  3120. int c,n=4,ar;
  3121. int dir = map_calc_dir(src,bl->x,bl->y);
  3122. struct square tc;
  3123. int x=bl->x,y=bl->y;
  3124. ar=skilllv/3;
  3125. skill_brandishspear_first(&tc,dir,x,y);
  3126. skill_brandishspear_dir(&tc,dir,4);
  3127. /* 範?④ */
  3128. if(skilllv == 10){
  3129. for(c=1;c<4;c++){
  3130. map_foreachinarea(skill_area_sub,
  3131. bl->m,tc.val1[c],tc.val2[c],tc.val1[c],tc.val2[c],0,
  3132. src,skillid,skilllv,tick, flag|BCT_ENEMY|n,
  3133. skill_castend_damage_id);
  3134. }
  3135. }
  3136. /* 範?③② */
  3137. if(skilllv > 6){
  3138. skill_brandishspear_dir(&tc,dir,-1);
  3139. n--;
  3140. }else{
  3141. skill_brandishspear_dir(&tc,dir,-2);
  3142. n-=2;
  3143. }
  3144. if(skilllv > 3){
  3145. for(c=0;c<5;c++){
  3146. map_foreachinarea(skill_area_sub,
  3147. bl->m,tc.val1[c],tc.val2[c],tc.val1[c],tc.val2[c],0,
  3148. src,skillid,skilllv,tick, flag|BCT_ENEMY|n,
  3149. skill_castend_damage_id);
  3150. if(skilllv > 6 && n==3 && c==4){
  3151. skill_brandishspear_dir(&tc,dir,-1);
  3152. n--;c=-1;
  3153. }
  3154. }
  3155. }
  3156. /* 範?① */
  3157. for(c=0;c<10;c++){
  3158. if(c==0||c==5) skill_brandishspear_dir(&tc,dir,-1);
  3159. map_foreachinarea(skill_area_sub,
  3160. bl->m,tc.val1[c%5],tc.val2[c%5],tc.val1[c%5],tc.val2[c%5],0,
  3161. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  3162. skill_castend_damage_id);
  3163. }
  3164. }
  3165. break;
  3166. /* パ?ティスキル */
  3167. case AL_ANGELUS: /* エンジェラス */
  3168. case PR_MAGNIFICAT: /* マグニフィカ?ト */
  3169. case PR_GLORIA: /* グロリア */
  3170. case SN_WINDWALK: /* ウインドウォ?ク */
  3171. if(sd == NULL || sd->status.party_id==0 || (flag&1) ){
  3172. /* 個別の?理 */
  3173. clif_skill_nodamage(bl,bl,skillid,skilllv,1);
  3174. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  3175. break;
  3176. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
  3177. }
  3178. else{
  3179. /* パ?ティ全?への?理 */
  3180. party_foreachsamemap(skill_area_sub,
  3181. sd,1,
  3182. src,skillid,skilllv,tick, flag|BCT_PARTY|1,
  3183. skill_castend_nodamage_id);
  3184. }
  3185. break;
  3186. case BS_ADRENALINE: /* アドレナリンラッシュ */
  3187. case BS_WEAPONPERFECT: /* ウェポンパ?フェクション */
  3188. case BS_OVERTHRUST: /* オ?バ?トラスト */
  3189. if(sd == NULL || sd->status.party_id==0 || (flag&1) ){
  3190. /* 個別の?理 */
  3191. clif_skill_nodamage(bl,bl,skillid,skilllv,1);
  3192. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,(src == bl)? 1:0,0,0,skill_get_time(skillid,skilllv),0);
  3193. }
  3194. else{
  3195. /* パ?ティ全?への?理 */
  3196. party_foreachsamemap(skill_area_sub,
  3197. sd,1,
  3198. src,skillid,skilllv,tick, flag|BCT_PARTY|1,
  3199. skill_castend_nodamage_id);
  3200. }
  3201. break;
  3202. /*(付加と解除が必要) */
  3203. case BS_MAXIMIZE: /* マキシマイズパワ? */
  3204. case NV_TRICKDEAD: /* 死んだふり */
  3205. case CR_DEFENDER: /* ディフェンダ? */
  3206. case CR_AUTOGUARD: /* オ?トガ?ド */
  3207. {
  3208. struct status_change *tsc_data = status_get_sc_data(bl);
  3209. int sc=SkillStatusChangeTable[skillid];
  3210. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3211. if( tsc_data ){
  3212. if( tsc_data[sc].timer==-1 )
  3213. /* 付加する */
  3214. status_change_start(bl,sc,skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
  3215. else
  3216. /* 解除する */
  3217. status_change_end(bl, sc, -1);
  3218. }
  3219. }
  3220. break;
  3221. case TF_HIDING: /* ハイディング */
  3222. {
  3223. struct status_change *tsc_data = status_get_sc_data(bl);
  3224. int sc=SkillStatusChangeTable[skillid];
  3225. clif_skill_nodamage(src,bl,skillid,-1,1);
  3226. if(tsc_data && tsc_data[sc].timer!=-1 )
  3227. /* 解除する */
  3228. status_change_end(bl, sc, -1);
  3229. else
  3230. /* 付加する */
  3231. status_change_start(bl,sc,skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
  3232. }
  3233. break;
  3234. case AS_CLOAKING: /* クロ?キング */
  3235. {
  3236. struct status_change *tsc_data = status_get_sc_data(bl);
  3237. int sc=SkillStatusChangeTable[skillid];
  3238. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3239. if(tsc_data && tsc_data[sc].timer!=-1 )
  3240. /* 解除する */
  3241. status_change_end(bl, sc, -1);
  3242. else
  3243. /* 付加する */
  3244. status_change_start(bl,sc,skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
  3245. //skill_check_cloaking(bl);
  3246. }
  3247. break;
  3248. case ST_CHASEWALK: /* ハイディング */
  3249. {
  3250. struct status_change *tsc_data = status_get_sc_data(bl);
  3251. int sc=SkillStatusChangeTable[skillid];
  3252. clif_skill_nodamage(src,bl,skillid,-1,1);
  3253. if(tsc_data && tsc_data[sc].timer!=-1 )
  3254. /* 解除する */
  3255. status_change_end(bl, sc, -1);
  3256. else
  3257. /* 付加する */
  3258. status_change_start(bl,sc,skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
  3259. }
  3260. break;
  3261. /* ?地スキル */
  3262. case BD_LULLABY: /* 子守唄 */
  3263. case BD_RICHMANKIM: /* ニヨルドの宴 */
  3264. case BD_ETERNALCHAOS: /* 永遠の混沌 */
  3265. case BD_DRUMBATTLEFIELD: /* ?太鼓の響き */
  3266. case BD_RINGNIBELUNGEN: /* ニ?ベルングの指輪 */
  3267. case BD_ROKISWEIL: /* ロキの叫び */
  3268. case BD_INTOABYSS: /* 深淵の中に */
  3269. case BD_SIEGFRIED: /* 不死身のジ?クフリ?ド */
  3270. case BA_DISSONANCE: /* 不協和音 */
  3271. case BA_POEMBRAGI: /* ブラギの詩 */
  3272. case BA_WHISTLE: /* 口笛 */
  3273. case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
  3274. case BA_APPLEIDUN: /* イドゥンの林檎 */
  3275. case DC_UGLYDANCE: /* 自分勝手なダンス */
  3276. case DC_HUMMING: /* ハミング */
  3277. case DC_DONTFORGETME: /* 私を忘れないで… */
  3278. case DC_FORTUNEKISS: /* 幸運のキス */
  3279. case DC_SERVICEFORYOU: /* サ?ビスフォ?ユ? */
  3280. // case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
  3281. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3282. skill_unitsetting(src,skillid,skilllv,src->x,src->y,0);
  3283. break;
  3284. case HP_BASILICA: /* バジリカ */
  3285. {
  3286. struct skill_unit_group *sg;
  3287. battle_stopwalking(src,1);
  3288. skill_clear_unitgroup(src);
  3289. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3290. sg = skill_unitsetting(src,skillid,skilllv,src->x,src->y,0);
  3291. status_change_start(src,SkillStatusChangeTable[skillid],skilllv,0,0,(int)sg,
  3292. skill_get_time(skillid,skilllv),0);
  3293. }
  3294. break;
  3295. case PA_GOSPEL: /* ゴスペル */
  3296. skill_clear_unitgroup(src);
  3297. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3298. skill_unitsetting(src,skillid,skilllv,src->x,src->y,0);
  3299. status_change_start(src,SkillStatusChangeTable[skillid],skilllv,0,0,BCT_SELF,skill_get_time(skillid,skilllv),0);
  3300. break;
  3301. case BD_ADAPTATION: /* アドリブ */
  3302. {
  3303. struct status_change *sc_data = status_get_sc_data(src);
  3304. if(sc_data && sc_data[SC_DANCING].timer!=-1){
  3305. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3306. skill_stop_dancing(src,0);
  3307. }
  3308. }
  3309. break;
  3310. case BA_FROSTJOKE: /* 寒いジョ?ク */
  3311. case DC_SCREAM: /* スクリ?ム */
  3312. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3313. skill_addtimerskill(src,tick+3000,bl->id,0,0,skillid,skilllv,0,flag);
  3314. break;
  3315. case TF_STEAL: // スティ?ル
  3316. if(sd) {
  3317. if(pc_steal_item(sd,bl))
  3318. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3319. else
  3320. clif_skill_fail(sd,skillid,0x0a,0);
  3321. }
  3322. break;
  3323. case RG_STEALCOIN: // スティ?ルコイン
  3324. if(sd) {
  3325. if(pc_steal_coin(sd,bl)) {
  3326. int range = skill_get_range(skillid,skilllv);
  3327. if(range < 0)
  3328. range = status_get_range(src) - (range + 1);
  3329. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3330. mob_target((struct mob_data *)bl,src,range);
  3331. }
  3332. else
  3333. clif_skill_fail(sd,skillid,0,0);
  3334. }
  3335. break;
  3336. case MG_STONECURSE: /* スト?ンカ?ス */
  3337. {
  3338. struct status_change *sc_data = status_get_sc_data(bl);
  3339. // Level 6-10 doesn't consume a red gem if it fails [celest]
  3340. int i, gem_flag = 1;
  3341. if (bl->type==BL_MOB && status_get_mode(bl)&0x20) {
  3342. clif_skill_fail(sd,sd->skillid,0,0);
  3343. break;
  3344. }
  3345. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3346. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  3347. break;
  3348. if (sc_data && sc_data[SC_STONE].timer != -1) {
  3349. status_change_end(bl,SC_STONE,-1);
  3350. if (sd)
  3351. clif_skill_fail(sd,skillid,0,0);
  3352. }
  3353. else if( rand()%100 < skilllv*4+20 && !battle_check_undead(status_get_race(bl),status_get_elem_type(bl)))
  3354. status_change_start(bl,SC_STONE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  3355. else if(sd) {
  3356. if (skilllv > 5) gem_flag = 0;
  3357. clif_skill_fail(sd,skillid,0,0);
  3358. }
  3359. if (dstmd)
  3360. mob_target(dstmd,src,skill_get_range(skillid,skilllv));
  3361. if (sd && gem_flag) {
  3362. if ((i=pc_search_inventory(sd, skill_db[skillid].itemid[0])) < 0 ) {
  3363. clif_skill_fail(sd,sd->skillid,0,0);
  3364. break;
  3365. }
  3366. pc_delitem(sd, i, skill_db[skillid].amount[0], 0);
  3367. }
  3368. }
  3369. break;
  3370. case NV_FIRSTAID: /* ?急手? */
  3371. clif_skill_nodamage(src,bl,skillid,5,1);
  3372. battle_heal(NULL,bl,5,0,0);
  3373. break;
  3374. case AL_CURE: /* キュア? */
  3375. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3376. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  3377. break;
  3378. status_change_end(bl, SC_SILENCE , -1 );
  3379. status_change_end(bl, SC_BLIND , -1 );
  3380. status_change_end(bl, SC_CONFUSION, -1 );
  3381. if( battle_check_undead(status_get_race(bl),status_get_elem_type(bl)) ){//アンデッドなら暗闇?果
  3382. status_change_start(bl, SC_CONFUSION,1,0,0,0,6000,0);
  3383. }
  3384. break;
  3385. case TF_DETOXIFY: /* 解毒 */
  3386. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3387. status_change_end(bl, SC_POISON , -1 );
  3388. status_change_end(bl, SC_DPOISON , -1 );
  3389. break;
  3390. case PR_STRECOVERY: /* リカバリ? */
  3391. {
  3392. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3393. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  3394. break;
  3395. status_change_end(bl, SC_FREEZE , -1 );
  3396. status_change_end(bl, SC_STONE , -1 );
  3397. status_change_end(bl, SC_SLEEP , -1 );
  3398. status_change_end(bl, SC_STAN , -1 );
  3399. if( battle_check_undead(status_get_race(bl),status_get_elem_type(bl)) ){//アンデッドなら暗闇?果
  3400. int blind_time;
  3401. //blind_time=30-status_get_vit(bl)/10-status_get_int/15;
  3402. blind_time=30*(100-(status_get_int(bl)+status_get_vit(bl))/2)/100;
  3403. if(rand()%100 < (100-(status_get_int(bl)/2+status_get_vit(bl)/3+status_get_luk(bl)/10)))
  3404. status_change_start(bl, SC_BLIND,1,0,0,0,blind_time,0);
  3405. }
  3406. if(dstmd){
  3407. dstmd->attacked_id=0;
  3408. dstmd->target_id=0;
  3409. dstmd->state.targettype = NONE_ATTACKABLE;
  3410. dstmd->state.skillstate=MSS_IDLE;
  3411. dstmd->next_walktime=tick+rand()%3000+3000;
  3412. }
  3413. }
  3414. break;
  3415. case WZ_ESTIMATION: /* モンスタ?情報 */
  3416. if(src->type==BL_PC){
  3417. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3418. clif_skill_estimation((struct map_session_data *)src,bl);
  3419. }
  3420. break;
  3421. case MC_IDENTIFY: /* アイテム鑑定 */
  3422. if(sd)
  3423. clif_item_identify_list(sd);
  3424. break;
  3425. case BS_REPAIRWEAPON: /* 武器修理 */
  3426. if(sd) {
  3427. //動作しないのでとりあえずコメントアウト
  3428. /*if (pc_search_inventory(sd, 999) < 0 ) { //fixed by Lupus (item pos can be = 0!)
  3429. clif_skill_fail(sd,sd->skillid,0,0);
  3430. map_freeblock_unlock();
  3431. return 1;
  3432. }*/
  3433. clif_item_repair_list(sd);
  3434. }
  3435. break;
  3436. case MC_VENDING: /* 露店開設 */
  3437. if(sd)
  3438. clif_openvendingreq(sd,2+sd->skilllv);
  3439. break;
  3440. case AL_TELEPORT: /* テレポ?ト */
  3441. if( sd ){
  3442. if(map[sd->bl.m].flag.noteleport){ /* テレポ禁止 */
  3443. clif_skill_teleportmessage(sd,0);
  3444. break;
  3445. }
  3446. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3447. if( sd->skilllv==1 )
  3448. clif_skill_warppoint(sd,sd->skillid,"Random","","","");
  3449. else{
  3450. clif_skill_warppoint(sd,sd->skillid,"Random",
  3451. sd->status.save_point.map,"","");
  3452. }
  3453. }else if( bl->type==BL_MOB )
  3454. mob_warp((struct mob_data *)bl,-1,-1,-1,3);
  3455. break;
  3456. case AL_HOLYWATER: /* アクアベネディクタ */
  3457. if(sd) {
  3458. int eflag;
  3459. struct item item_tmp;
  3460. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3461. memset(&item_tmp,0,sizeof(item_tmp));
  3462. item_tmp.nameid = 523;
  3463. item_tmp.identify = 1;
  3464. if(battle_config.holywater_name_input) {
  3465. item_tmp.card[0] = 0xfe;
  3466. item_tmp.card[1] = 0;
  3467. *((unsigned long *)(&item_tmp.card[2]))=sd->char_id; /* キャラID */
  3468. }
  3469. eflag = pc_additem(sd,&item_tmp,1);
  3470. if(eflag) {
  3471. clif_additem(sd,0,0,eflag);
  3472. map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
  3473. }
  3474. }
  3475. break;
  3476. case TF_PICKSTONE:
  3477. if(sd) {
  3478. int eflag;
  3479. struct item item_tmp;
  3480. struct block_list tbl;
  3481. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3482. memset(&item_tmp,0,sizeof(item_tmp));
  3483. memset(&tbl,0,sizeof(tbl)); // [MouseJstr]
  3484. item_tmp.nameid = 7049;
  3485. item_tmp.identify = 1;
  3486. tbl.id = 0;
  3487. clif_takeitem(&sd->bl,&tbl);
  3488. eflag = pc_additem(sd,&item_tmp,1);
  3489. if(eflag) {
  3490. clif_additem(sd,0,0,eflag);
  3491. map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
  3492. }
  3493. }
  3494. break;
  3495. case RG_STRIPWEAPON: /* ストリップウェポン */
  3496. case RG_STRIPSHIELD: /* ストリップシールド */
  3497. case RG_STRIPARMOR: /* ストリップアーマー */
  3498. case RG_STRIPHELM: /* ストリップヘルム */
  3499. case ST_FULLSTRIP: // Celest
  3500. {
  3501. struct status_change *tsc_data = status_get_sc_data(bl);
  3502. int scid, cp_scid = 0, equip, strip_fix, strip_num = 0;
  3503. scid = SkillStatusChangeTable[skillid];
  3504. switch (skillid) {
  3505. case RG_STRIPWEAPON:
  3506. equip = EQP_WEAPON;
  3507. cp_scid = SC_CP_WEAPON;
  3508. break;
  3509. case RG_STRIPSHIELD:
  3510. equip = EQP_SHIELD;
  3511. cp_scid = SC_CP_SHIELD;
  3512. break;
  3513. case RG_STRIPARMOR:
  3514. equip = EQP_ARMOR;
  3515. cp_scid = SC_CP_ARMOR;
  3516. break;
  3517. case RG_STRIPHELM:
  3518. equip = EQP_HELM;
  3519. cp_scid = SC_CP_HELM;
  3520. break;
  3521. case ST_FULLSTRIP:
  3522. equip = EQP_WEAPON | EQP_SHIELD | EQP_ARMOR | EQP_HELM;
  3523. strip_num = 3;
  3524. break;
  3525. default:
  3526. map_freeblock_unlock();
  3527. return 1;
  3528. }
  3529. if (tsc_data && (tsc_data[scid].timer != -1 || tsc_data[cp_scid].timer != -1))
  3530. break;
  3531. if (dstsd && dstsd->unstripable_equip & equip)
  3532. break;
  3533. strip_fix = status_get_dex(src) - status_get_dex(bl);
  3534. if(strip_fix < 0)
  3535. strip_fix=0;
  3536. strip_per = 5+2*skilllv+strip_fix/5;
  3537. if (rand()%100 >= strip_per)
  3538. break;
  3539. if (dstsd) {
  3540. for (i=0;i<MAX_INVENTORY;i++) {
  3541. if (dstsd->status.inventory[i].equip && (dstsd->status.inventory[i].equip & equip)){
  3542. pc_unequipitem(dstsd,i,3);
  3543. if ((--strip_num) <= 0)
  3544. break;
  3545. }
  3546. }
  3547. if (i == MAX_INVENTORY)
  3548. break;
  3549. }
  3550. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3551. strip_time = skill_get_time(skillid,skilllv)+strip_fix/2;
  3552. status_change_start(bl,scid,skilllv,0,0,0,strip_time,0 );
  3553. break;
  3554. }
  3555. /* PotionPitcher */
  3556. case AM_POTIONPITCHER: /* ポ?ションピッチャ? */
  3557. {
  3558. struct block_list tbl;
  3559. int i,x,hp = 0,sp = 0;
  3560. if(sd) {
  3561. x = skilllv%11 - 1;
  3562. i = pc_search_inventory(sd,skill_db[skillid].itemid[x]);
  3563. if(i < 0 || skill_db[skillid].itemid[x] <= 0) {
  3564. clif_skill_fail(sd,skillid,0,0);
  3565. map_freeblock_unlock();
  3566. return 1;
  3567. }
  3568. if(sd->inventory_data[i] == NULL || sd->status.inventory[i].amount < skill_db[skillid].amount[x]) {
  3569. clif_skill_fail(sd,skillid,0,0);
  3570. map_freeblock_unlock();
  3571. return 1;
  3572. }
  3573. sd->state.potionpitcher_flag = 1;
  3574. sd->potion_hp = sd->potion_sp = sd->potion_per_hp = sd->potion_per_sp = 0;
  3575. sd->skilltarget = bl->id;
  3576. run_script(sd->inventory_data[i]->use_script,0,sd->bl.id,0);
  3577. pc_delitem(sd,i,skill_db[skillid].amount[x],0);
  3578. sd->state.potionpitcher_flag = 0;
  3579. if(sd->potion_per_hp > 0 || sd->potion_per_sp > 0) {
  3580. hp = status_get_max_hp(bl) * sd->potion_per_hp / 100;
  3581. hp = hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)/100;
  3582. if(dstsd) {
  3583. sp = dstsd->status.max_sp * sd->potion_per_sp / 100;
  3584. sp = sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)/100;
  3585. }
  3586. }
  3587. else {
  3588. if(sd->potion_hp > 0) {
  3589. hp = sd->potion_hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)/100;
  3590. hp = hp * (100 + (status_get_vit(bl)<<1)) / 100;
  3591. if(dstsd)
  3592. hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100;
  3593. }
  3594. if(sd->potion_sp > 0) {
  3595. sp = sd->potion_sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)/100;
  3596. sp = sp * (100 + (status_get_int(bl)<<1)) / 100;
  3597. if(dstsd)
  3598. sp = sp * (100 + pc_checkskill(dstsd,MG_SRECOVERY)*10) / 100;
  3599. }
  3600. }
  3601. }
  3602. else {
  3603. hp = (1 + rand()%400) * (100 + skilllv*10) / 100;
  3604. hp = hp * (100 + (status_get_vit(bl)<<1)) / 100;
  3605. if(dstsd)
  3606. hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100;
  3607. }
  3608. tbl.id = 0;
  3609. tbl.m = src->m;
  3610. tbl.x = src->x;
  3611. tbl.y = src->y;
  3612. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3613. if(hp > 0 || (hp <= 0 && sp <= 0))
  3614. clif_skill_nodamage(&tbl,bl,AL_HEAL,hp,1);
  3615. if(sp > 0)
  3616. clif_skill_nodamage(&tbl,bl,MG_SRECOVERY,sp,1);
  3617. battle_heal(src,bl,hp,sp,0);
  3618. }
  3619. break;
  3620. case AM_CP_WEAPON:
  3621. case AM_CP_SHIELD:
  3622. case AM_CP_ARMOR:
  3623. case AM_CP_HELM:
  3624. {
  3625. int scid = SC_STRIPWEAPON + (skillid - AM_CP_WEAPON);
  3626. struct status_change *tsc_data = status_get_sc_data(bl);
  3627. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3628. if(tsc_data && tsc_data[scid].timer != -1)
  3629. status_change_end(bl, scid, -1 );
  3630. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  3631. }
  3632. break;
  3633. case SA_DISPELL: /* ディスペル */
  3634. {
  3635. int i;
  3636. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3637. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  3638. break;
  3639. for(i=0;i<136;i++){
  3640. if(i==SC_RIDING || i== SC_FALCON || i==SC_HALLUCINATION || i==SC_WEIGHT50
  3641. || i==SC_WEIGHT90 || i==SC_STRIPWEAPON || i==SC_STRIPSHIELD || i==SC_STRIPARMOR
  3642. || i==SC_STRIPHELM || i==SC_CP_WEAPON || i==SC_CP_SHIELD || i==SC_CP_ARMOR
  3643. || i==SC_CP_HELM || i==SC_COMBO)
  3644. continue;
  3645. status_change_end(bl,i,-1);
  3646. }
  3647. }
  3648. break;
  3649. case TF_BACKSLIDING: /* バックステップ */
  3650. battle_stopwalking(src,1);
  3651. skill_blown(src,bl,skill_get_blewcount(skillid,skilllv)|0x10000);
  3652. if(src->type == BL_MOB)
  3653. clif_fixmobpos((struct mob_data *)src);
  3654. else if(src->type == BL_PET)
  3655. clif_fixpetpos((struct pet_data *)src);
  3656. else if(src->type == BL_PC)
  3657. clif_fixpos(src);
  3658. skill_addtimerskill(src,tick + 200,src->id,0,0,skillid,skilllv,0,flag);
  3659. break;
  3660. case SA_CASTCANCEL:
  3661. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3662. skill_castcancel(src,1);
  3663. if(sd) {
  3664. int sp = skill_get_sp(sd->skillid_old,sd->skilllv_old);
  3665. sp = sp * (90 - (skilllv-1)*20) / 100;
  3666. if(sp < 0) sp = 0;
  3667. pc_heal(sd,0,-sp);
  3668. }
  3669. break;
  3670. case SA_SPELLBREAKER: // スペルブレイカ?
  3671. {
  3672. struct status_change *sc_data = status_get_sc_data(bl);
  3673. int sp;
  3674. if(sc_data && sc_data[SC_MAGICROD].timer != -1) {
  3675. if(dstsd) {
  3676. sp = skill_get_sp(skillid,skilllv);
  3677. sp = sp * sc_data[SC_MAGICROD].val2 / 100;
  3678. if(sp > 0x7fff) sp = 0x7fff;
  3679. else if(sp < 1) sp = 1;
  3680. if(dstsd->status.sp + sp > dstsd->status.max_sp) {
  3681. sp = dstsd->status.max_sp - dstsd->status.sp;
  3682. dstsd->status.sp = dstsd->status.max_sp;
  3683. }
  3684. else
  3685. dstsd->status.sp += sp;
  3686. clif_heal(dstsd->fd,SP_SP,sp);
  3687. }
  3688. clif_skill_nodamage(bl,bl,SA_MAGICROD,sc_data[SC_MAGICROD].val1,1);
  3689. if(sd) {
  3690. sp = sd->status.max_sp/5;
  3691. if(sp < 1) sp = 1;
  3692. pc_heal(sd,0,-sp);
  3693. }
  3694. }
  3695. else {
  3696. int bl_skillid=0,bl_skilllv=0;
  3697. if(bl->type == BL_PC) {
  3698. if(dstsd && dstsd->skilltimer != -1) {
  3699. bl_skillid = dstsd->skillid;
  3700. bl_skilllv = dstsd->skilllv;
  3701. }
  3702. }
  3703. else if(bl->type == BL_MOB) {
  3704. if(dstmd && dstmd->skilltimer != -1) {
  3705. bl_skillid = dstmd->skillid;
  3706. bl_skilllv = dstmd->skilllv;
  3707. }
  3708. }
  3709. if(bl_skillid > 0 && skill_db[bl_skillid].skill_type == BF_MAGIC) {
  3710. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3711. skill_castcancel(bl,0);
  3712. sp = skill_get_sp(bl_skillid,bl_skilllv);
  3713. if(dstsd)
  3714. pc_heal(dstsd,0,-sp);
  3715. if(sd) {
  3716. sp = sp*(25*(skilllv-1))/100;
  3717. if(skilllv > 1 && sp < 1) sp = 1;
  3718. if(sp > 0x7fff) sp = 0x7fff;
  3719. else if(sp < 1) sp = 1;
  3720. if(sd->status.sp + sp > sd->status.max_sp) {
  3721. sp = sd->status.max_sp - sd->status.sp;
  3722. sd->status.sp = sd->status.max_sp;
  3723. }
  3724. else
  3725. sd->status.sp += sp;
  3726. clif_heal(sd->fd,SP_SP,sp);
  3727. }
  3728. }
  3729. else if(sd)
  3730. clif_skill_fail(sd,skillid,0,0);
  3731. }
  3732. }
  3733. break;
  3734. case SA_MAGICROD:
  3735. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  3736. break;
  3737. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  3738. break;
  3739. case SA_AUTOSPELL: /* オ?トスペル */
  3740. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3741. if(sd)
  3742. clif_autospell(sd,skilllv);
  3743. else {
  3744. int maxlv=1,spellid=0;
  3745. static const int spellarray[3] = { MG_COLDBOLT,MG_FIREBOLT,MG_LIGHTNINGBOLT };
  3746. if(skilllv >= 10) {
  3747. spellid = MG_FROSTDIVER;
  3748. maxlv = skilllv - 9;
  3749. }
  3750. else if(skilllv >=8) {
  3751. spellid = MG_FIREBALL;
  3752. maxlv = skilllv - 7;
  3753. }
  3754. else if(skilllv >=5) {
  3755. spellid = MG_SOULSTRIKE;
  3756. maxlv = skilllv - 4;
  3757. }
  3758. else if(skilllv >=2) {
  3759. int i = rand()%3;
  3760. spellid = spellarray[i];
  3761. maxlv = skilllv - 1;
  3762. }
  3763. else if(skilllv > 0) {
  3764. spellid = MG_NAPALMBEAT;
  3765. maxlv = 3;
  3766. }
  3767. if(spellid > 0)
  3768. status_change_start(src,SC_AUTOSPELL,skilllv,spellid,maxlv,0,
  3769. skill_get_time(SA_AUTOSPELL,skilllv),0);
  3770. }
  3771. break;
  3772. /* ランダム?性?化、水?性?化、地、火、風 */
  3773. case NPC_ATTRICHANGE:
  3774. case NPC_CHANGEWATER:
  3775. case NPC_CHANGEGROUND:
  3776. case NPC_CHANGEFIRE:
  3777. case NPC_CHANGEWIND:
  3778. /* 毒、聖、念、闇 */
  3779. case NPC_CHANGEPOISON:
  3780. case NPC_CHANGEHOLY:
  3781. case NPC_CHANGEDARKNESS:
  3782. case NPC_CHANGETELEKINESIS:
  3783. if(md){
  3784. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3785. md->def_ele=skill_get_pl(skillid);
  3786. if(md->def_ele==0) /* ランダム?化、ただし、*/
  3787. md->def_ele=rand()%10; /* 不死?性は除く */
  3788. md->def_ele+=(1+rand()%4)*20; /* ?性レベルはランダム */
  3789. }
  3790. break;
  3791. case NPC_PROVOCATION:
  3792. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3793. if(md)
  3794. clif_pet_performance(src,mob_db[md->class_].skill[md->skillidx].val[0]);
  3795. break;
  3796. case NPC_HALLUCINATION:
  3797. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3798. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  3799. break;
  3800. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  3801. break;
  3802. case NPC_KEEPING:
  3803. case NPC_BARRIER:
  3804. {
  3805. int skill_time = skill_get_time(skillid,skilllv);
  3806. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3807. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_time,0 );
  3808. if (src->type == BL_MOB)
  3809. mob_changestate((struct mob_data *)src,MS_DELAY,skill_time);
  3810. else if (src->type == BL_PC)
  3811. sd->attackabletime = sd->canmove_tick = tick + skill_time;
  3812. }
  3813. break;
  3814. case NPC_DARKBLESSING:
  3815. {
  3816. int sc_def = 100 - status_get_mdef(bl);
  3817. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3818. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  3819. break;
  3820. if(status_get_elem_type(bl) == 7 || status_get_race(bl) == 6)
  3821. break;
  3822. if(rand()%100 < sc_def*(50+skilllv*5)/100) {
  3823. if(dstsd) {
  3824. int hp = status_get_hp(bl)-1;
  3825. pc_heal(dstsd,-hp,0);
  3826. }
  3827. else if(dstmd)
  3828. dstmd->hp = 1;
  3829. }
  3830. }
  3831. break;
  3832. case NPC_SELFDESTRUCTION: /* 自爆 */
  3833. case NPC_SELFDESTRUCTION2: /* 自爆2 */
  3834. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,skillid,0,0,skill_get_time(skillid,skilllv),0);
  3835. break;
  3836. case NPC_LICK:
  3837. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3838. if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_weapon_damage )
  3839. break;
  3840. if(dstsd)
  3841. pc_heal(dstsd,0,-100);
  3842. if(rand()%100 < (skilllv*5)*sc_def_vit/100)
  3843. status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
  3844. break;
  3845. case NPC_SUICIDE: /* 自決 */
  3846. if(src && bl){
  3847. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3848. if (md)
  3849. mob_damage(NULL,md,md->hp,0);
  3850. else if (sd)
  3851. pc_damage(NULL,sd,sd->status.hp);
  3852. }
  3853. break;
  3854. case NPC_SUMMONSLAVE: /* 手下召喚 */
  3855. case NPC_SUMMONMONSTER: /* MOB召喚 */
  3856. if(md)
  3857. mob_summonslave(md,mob_db[md->class_].skill[md->skillidx].val,skilllv,(skillid==NPC_SUMMONSLAVE)?1:0);
  3858. break;
  3859. case NPC_TRANSFORMATION:
  3860. case NPC_METAMORPHOSIS:
  3861. if(md)
  3862. mob_class_change(md,mob_db[md->class_].skill[md->skillidx].val);
  3863. break;
  3864. case NPC_EMOTION: /* エモ?ション */
  3865. if(md)
  3866. clif_emotion(&md->bl,mob_db[md->class_].skill[md->skillidx].val[0]);
  3867. break;
  3868. case NPC_DEFENDER:
  3869. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3870. break;
  3871. // Equipment breaking monster skills [Celest]
  3872. case NPC_BREAKWEAPON:
  3873. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3874. if(bl->type == BL_PC && battle_config.equipment_breaking)
  3875. pc_breakweapon(dstsd);
  3876. break;
  3877. case NPC_BREAKARMOR:
  3878. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3879. if(bl->type == BL_PC && battle_config.equipment_breaking)
  3880. pc_breakarmor(dstsd);
  3881. break;
  3882. case NPC_BREAKHELM:
  3883. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3884. if(bl->type == BL_PC && battle_config.equipment_breaking)
  3885. pc_breakhelm(dstsd);
  3886. break;
  3887. case NPC_BREAKSHIELD:
  3888. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3889. if(bl->type == BL_PC && battle_config.equipment_breaking)
  3890. pc_breakshield(dstsd);
  3891. break;
  3892. case NPC_EXPLOSIONSPIRITS: //NPC爆裂波動
  3893. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3894. status_change_start(bl,SC_EXPLOSIONSPIRITS,skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  3895. break;
  3896. case WE_MALE: /* 君だけは護るよ */
  3897. if(sd && dstsd){
  3898. int hp_rate=(skilllv <= 0)? 0:skill_db[skillid].hp_rate[skilllv-1];
  3899. int gain_hp=sd->status.max_hp*abs(hp_rate)/100;// 15%
  3900. clif_skill_nodamage(src,bl,skillid,gain_hp,1);
  3901. battle_heal(NULL,bl,gain_hp,0,0);
  3902. }
  3903. break;
  3904. case WE_FEMALE: /* あなたの?に?牲になります */
  3905. if(sd && dstsd){
  3906. int sp_rate=(skilllv <= 0)? 0:skill_db[skillid].sp_rate[skilllv-1];
  3907. int gain_sp=sd->status.max_sp*abs(sp_rate)/100;// 15%
  3908. clif_skill_nodamage(src,bl,skillid,gain_sp,1);
  3909. battle_heal(NULL,bl,0,gain_sp,0);
  3910. }
  3911. break;
  3912. case WE_CALLPARTNER: /* あなたに?いたい */
  3913. if(sd && dstsd){
  3914. if((dstsd = pc_get_partner(sd)) == NULL){
  3915. clif_skill_fail(sd,skillid,0,0);
  3916. map_freeblock_unlock();
  3917. return 0;
  3918. }
  3919. if(map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto || map[dstsd->bl.m].flag.nowarp){
  3920. clif_skill_teleportmessage(sd,1);
  3921. map_freeblock_unlock();
  3922. return 0;
  3923. }
  3924. skill_unitsetting(src,skillid,skilllv,sd->bl.x,sd->bl.y,0);
  3925. }
  3926. break;
  3927. case PF_HPCONVERSION: /* ライフ置き換え */
  3928. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3929. if(sd){
  3930. int conv_hp=0,conv_sp=0;
  3931. conv_hp=sd->status.hp/10; //基本はHPの10%
  3932. sd->status.hp -= conv_hp; //HPを減らす
  3933. conv_sp=conv_hp*10*skilllv/100;
  3934. conv_sp=(sd->status.sp+conv_sp>sd->status.max_sp)?sd->status.max_sp-sd->status.sp:conv_sp;
  3935. sd->status.sp += conv_sp; //SPを?やす
  3936. pc_heal(sd,-conv_hp,conv_sp);
  3937. clif_heal(sd->fd,SP_SP,conv_sp);
  3938. }
  3939. break;
  3940. case HT_REMOVETRAP: /* リム?ブトラップ */
  3941. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3942. {
  3943. struct skill_unit *su=NULL;
  3944. struct item item_tmp;
  3945. int flag;
  3946. if((bl->type==BL_SKILL) &&
  3947. (su=(struct skill_unit *)bl) &&
  3948. (su->group->src_id == src->id || map[bl->m].flag.pvp || map[bl->m].flag.gvg) &&
  3949. (su->group->unit_id >= 0x8f && su->group->unit_id <= 0x99) &&
  3950. (su->group->unit_id != 0x92)){ //?を取り返す
  3951. if(sd){
  3952. if(battle_config.skill_removetrap_type == 1){
  3953. for(i=0;i<10;i++) {
  3954. if(skill_db[su->group->skill_id].itemid[i] > 0){
  3955. memset(&item_tmp,0,sizeof(item_tmp));
  3956. item_tmp.nameid = skill_db[su->group->skill_id].itemid[i];
  3957. item_tmp.identify = 1;
  3958. if(item_tmp.nameid && (flag=pc_additem(sd,&item_tmp,skill_db[su->group->skill_id].amount[i]))){
  3959. clif_additem(sd,0,0,flag);
  3960. map_addflooritem(&item_tmp,skill_db[su->group->skill_id].amount[i],sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
  3961. }
  3962. }
  3963. }
  3964. }else{
  3965. memset(&item_tmp,0,sizeof(item_tmp));
  3966. item_tmp.nameid = 1065;
  3967. item_tmp.identify = 1;
  3968. if(item_tmp.nameid && (flag=pc_additem(sd,&item_tmp,1))){
  3969. clif_additem(sd,0,0,flag);
  3970. map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
  3971. }
  3972. }
  3973. }
  3974. if(su->group->unit_id == 0x91 && su->group->val2){
  3975. struct block_list *target=map_id2bl(su->group->val2);
  3976. if(target && (target->type == BL_PC || target->type == BL_MOB))
  3977. status_change_end(target,SC_ANKLE,-1);
  3978. }
  3979. skill_delunit(su);
  3980. }
  3981. }
  3982. break;
  3983. case HT_SPRINGTRAP: /* スプリングトラップ */
  3984. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  3985. {
  3986. struct skill_unit *su=NULL;
  3987. if((bl->type==BL_SKILL) && (su=(struct skill_unit *)bl) && (su->group) ){
  3988. switch(su->group->unit_id){
  3989. case 0x91: // ankle snare
  3990. if (su->group->val2 != 0)
  3991. // if it is already trapping something don't spring it,
  3992. // remove trap should be used instead
  3993. break;
  3994. // otherwise fallthrough to below
  3995. case 0x8f: /* ブラストマイン */
  3996. case 0x90: /* スキッドトラップ */
  3997. case 0x93: /* ランドマイン */
  3998. case 0x94: /* ショックウェ?ブトラップ */
  3999. case 0x95: /* サンドマン */
  4000. case 0x96: /* フラッシャ? */
  4001. case 0x97: /* フリ?ジングトラップ */
  4002. case 0x98: /* クレイモア?トラップ */
  4003. case 0x99: /* ト?キ?ボックス */
  4004. su->group->unit_id = 0x8c;
  4005. clif_changelook(bl,LOOK_BASE,su->group->unit_id);
  4006. su->group->limit=DIFF_TICK(tick+1500,su->group->tick);
  4007. su->limit=DIFF_TICK(tick+1500,su->group->tick);
  4008. }
  4009. }
  4010. }
  4011. break;
  4012. case BD_ENCORE: /* アンコ?ル */
  4013. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4014. if(sd)
  4015. skill_use_id(sd,src->id,sd->skillid_dance,sd->skilllv_dance);
  4016. break;
  4017. case AS_SPLASHER: /* ベナムスプラッシャ? */
  4018. if((double)status_get_max_hp(bl)*2/3 < status_get_hp(bl)) { //HPが2/3以上?っていたら失敗
  4019. map_freeblock_unlock();
  4020. return 1;
  4021. }
  4022. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4023. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,skillid,src->id,skill_get_time(skillid,skilllv),1000,0 );
  4024. break;
  4025. case PF_MINDBREAKER: /* プロボック */
  4026. {
  4027. struct status_change *sc_data = status_get_sc_data(bl);
  4028. /* MVPmobと不死には?かない */
  4029. if((bl->type==BL_MOB && status_get_mode(bl)&0x20) || battle_check_undead(status_get_race(bl),status_get_elem_type(bl))) //不死には?かない
  4030. {
  4031. map_freeblock_unlock();
  4032. return 1;
  4033. }
  4034. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4035. status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
  4036. if(dstmd && dstmd->skilltimer!=-1 && dstmd->state.skillcastcancel) // 詠唱妨害
  4037. skill_castcancel(bl,0);
  4038. if(dstsd && dstsd->skilltimer!=-1 && (!dstsd->special_state.no_castcancel || map[bl->m].flag.gvg)
  4039. && dstsd->state.skillcastcancel && !dstsd->special_state.no_castcancel2)
  4040. skill_castcancel(bl,0);
  4041. if(sc_data){
  4042. if(sc_data[SC_FREEZE].timer!=-1)
  4043. status_change_end(bl,SC_FREEZE,-1);
  4044. if(sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2==0)
  4045. status_change_end(bl,SC_STONE,-1);
  4046. if(sc_data[SC_SLEEP].timer!=-1)
  4047. status_change_end(bl,SC_SLEEP,-1);
  4048. }
  4049. if(bl->type==BL_MOB) {
  4050. int range = skill_get_range(skillid,skilllv);
  4051. if(range < 0)
  4052. range = status_get_range(src) - (range + 1);
  4053. mob_target((struct mob_data *)bl,src,range);
  4054. }
  4055. }
  4056. break;
  4057. case PF_SOULCHANGE:
  4058. {
  4059. int sp1 = 0, sp2 = 0;
  4060. if (sd) {
  4061. if (dstsd) {
  4062. sp1 = sd->status.sp > dstsd->status.max_sp ? dstsd->status.max_sp : sd->status.sp;
  4063. sp2 = dstsd->status.sp > sd->status.max_sp ? sd->status.max_sp : dstsd->status.sp;
  4064. sd->status.sp = sp2;
  4065. dstsd->status.sp = sp1;
  4066. clif_heal(sd->fd,SP_SP,sp2);
  4067. clif_updatestatus(sd,SP_SP);
  4068. clif_heal(dstsd->fd,SP_SP,sp1);
  4069. clif_updatestatus(dstsd,SP_SP);
  4070. } else if (dstmd) {
  4071. if (dstmd->state.soul_change_flag) {
  4072. clif_skill_fail(sd,skillid,0,0);
  4073. map_freeblock_unlock();
  4074. return 0;
  4075. }
  4076. sp2 = sd->status.max_sp * 3 /100;
  4077. if (sd->status.sp + sp2 > sd->status.max_sp)
  4078. sp2 = sd->status.max_sp - sd->status.sp;
  4079. sd->status.sp += sp2;
  4080. clif_heal(sd->fd,SP_SP,sp2);
  4081. clif_updatestatus(sd,SP_SP);
  4082. dstmd->state.soul_change_flag = 1;
  4083. }
  4084. }
  4085. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4086. }
  4087. break;
  4088. // Weapon Refining [Celest]
  4089. case WS_WEAPONREFINE:
  4090. if(sd)
  4091. clif_item_refine_list(sd);
  4092. break;
  4093. // Slim Pitcher
  4094. case CR_SLIMPITCHER:
  4095. {
  4096. if (sd && flag&1) {
  4097. struct block_list tbl;
  4098. int hp = sd->potion_hp * (100 + pc_checkskill(sd,CR_SLIMPITCHER)*10 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)/100;
  4099. hp = hp * (100 + (status_get_vit(bl)<<1))/100;
  4100. if (dstsd) {
  4101. hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10)/100;
  4102. }
  4103. tbl.id = 0;
  4104. tbl.m = src->m;
  4105. tbl.x = src->x;
  4106. tbl.y = src->y;
  4107. clif_skill_nodamage(&tbl,bl,AL_HEAL,hp,1);
  4108. battle_heal(NULL,bl,hp,0,0);
  4109. }
  4110. }
  4111. break;
  4112. // Full Chemical Protection
  4113. case CR_FULLPROTECTION:
  4114. {
  4115. int i, skilltime;
  4116. struct status_change *tsc_data = status_get_sc_data(bl);
  4117. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4118. skilltime = skill_get_time(skillid,skilllv);
  4119. for (i=0; i<4; i++) {
  4120. if(tsc_data && tsc_data[SC_STRIPWEAPON + i].timer != -1)
  4121. status_change_end(bl, SC_STRIPWEAPON + i, -1 );
  4122. status_change_start(bl,SC_CP_WEAPON + i,skilllv,0,0,0,skilltime,0 );
  4123. }
  4124. }
  4125. break;
  4126. case RG_CLEANER: //AppleGirl
  4127. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4128. {
  4129. struct skill_unit *su=NULL;
  4130. if((bl->type==BL_SKILL) &&
  4131. (su=(struct skill_unit *)bl) &&
  4132. (su->group->src_id == src->id || map[bl->m].flag.pvp || map[bl->m].flag.gvg) &&
  4133. (su->group->unit_id == 0xb0)){ //?を取り返す
  4134. if(sd)
  4135. skill_delunit(su);
  4136. }
  4137. }
  4138. break;
  4139. case ST_PRESERVE:
  4140. if (sd){
  4141. if (sd->sc_count && sd->sc_data[SC_PRESERVE].timer != -1)
  4142. status_change_end(src, SC_PRESERVE, -1 );
  4143. else
  4144. status_change_start(src,SC_PRESERVE,skilllv,0,0,0,skill_get_time(skillid, skilllv),0 );
  4145. clif_skill_nodamage(src,src,skillid,skilllv,1);
  4146. }
  4147. break;
  4148. // New guild skills [Celest]
  4149. case GD_BATTLEORDER:
  4150. {
  4151. struct guild *g = NULL;
  4152. // Only usable during WoE
  4153. if (!agit_flag) {
  4154. clif_skill_fail(sd,skillid,0,0);
  4155. map_freeblock_unlock();
  4156. return 0;
  4157. }
  4158. if(flag&1) {
  4159. if (dstsd && dstsd->status.guild_id == sd->status.guild_id) {
  4160. status_change_start(&dstsd->bl,SC_BATTLEORDERS,skilllv,0,0,0,0,0 );
  4161. }
  4162. }
  4163. else if (sd && sd->status.guild_id > 0 && (g = guild_search(sd->status.guild_id)) &&
  4164. strcmp(sd->status.name,g->master)==0) {
  4165. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4166. map_foreachinarea(skill_area_sub,
  4167. src->m,src->x-15,src->y-15,src->x+15,src->y+15,0,
  4168. src,skillid,skilllv,tick, flag|BCT_ALL|1,
  4169. skill_castend_nodamage_id);
  4170. pc_blockskill_start (sd, skillid, 300000);
  4171. }
  4172. }
  4173. break;
  4174. case GD_REGENERATION:
  4175. {
  4176. struct guild *g = NULL;
  4177. // Only usable during WoE
  4178. if (!agit_flag) {
  4179. clif_skill_fail(sd,skillid,0,0);
  4180. map_freeblock_unlock();
  4181. return 0;
  4182. }
  4183. if(flag&1) {
  4184. if (dstsd && dstsd->status.guild_id == sd->status.guild_id) {
  4185. status_change_start(&dstsd->bl,SC_REGENERATION,skilllv,0,0,0,0,0 );
  4186. }
  4187. }
  4188. else if (sd && sd->status.guild_id > 0 && (g = guild_search(sd->status.guild_id)) &&
  4189. strcmp(sd->status.name,g->master)==0) {
  4190. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4191. map_foreachinarea(skill_area_sub,
  4192. src->m,src->x-15,src->y-15,src->x+15,src->y+15,0,
  4193. src,skillid,skilllv,tick, flag|BCT_ALL|1,
  4194. skill_castend_nodamage_id);
  4195. pc_blockskill_start (sd, skillid, 300000);
  4196. }
  4197. }
  4198. break;
  4199. case GD_RESTORE:
  4200. {
  4201. struct guild *g = NULL;
  4202. // Only usable during WoE
  4203. if (!agit_flag) {
  4204. clif_skill_fail(sd,skillid,0,0);
  4205. map_freeblock_unlock();
  4206. return 0;
  4207. }
  4208. if(flag&1) {
  4209. if (dstsd && dstsd->status.guild_id == sd->status.guild_id) {
  4210. int hp, sp;
  4211. hp = dstsd->status.max_hp*9/10;
  4212. sp = dstsd->status.max_sp*9/10;
  4213. sp = dstsd->status.sp + sp <= dstsd->status.max_sp ? sp : dstsd->status.max_sp - dstsd->status.sp;
  4214. clif_skill_nodamage(src,bl,AL_HEAL,hp,1);
  4215. battle_heal(NULL,bl,hp,sp,0);
  4216. }
  4217. }
  4218. else if (sd && sd->status.guild_id > 0 && (g = guild_search(sd->status.guild_id)) &&
  4219. strcmp(sd->status.name,g->master)==0) {
  4220. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4221. map_foreachinarea(skill_area_sub,
  4222. src->m,src->x-15,src->y-15,src->x+15,src->y+15,0,
  4223. src,skillid,skilllv,tick, flag|BCT_ALL|1,
  4224. skill_castend_nodamage_id);
  4225. pc_blockskill_start (sd, skillid, 300000);
  4226. }
  4227. }
  4228. break;
  4229. case GD_EMERGENCYCALL:
  4230. {
  4231. int dx[9]={-1, 1, 0, 0,-1, 1,-1, 1, 0};
  4232. int dy[9]={ 0, 0, 1,-1, 1,-1,-1, 1, 0};
  4233. int j = 0;
  4234. struct guild *g = NULL;
  4235. // Only usable during WoE
  4236. if (!agit_flag ||
  4237. (sd && map[sd->bl.m].flag.nowarpto && // if not allowed to warp to the map
  4238. guild_mapname2gc(sd->mapname) == NULL)) { // and it's not a castle...
  4239. clif_skill_fail(sd,skillid,0,0);
  4240. map_freeblock_unlock();
  4241. return 0;
  4242. }
  4243. // i don't know if it actually summons in a circle, but oh well. ;P
  4244. if (sd && sd->status.guild_id > 0 && (g = guild_search(sd->status.guild_id)) &&
  4245. strcmp(sd->status.name,g->master)==0) {
  4246. for(i = 0; i < g->max_member; i++, j++) {
  4247. if (j>8) j=0;
  4248. if ((dstsd = g->member[i].sd) != NULL && sd != dstsd) {
  4249. if (map[dstsd->bl.m].flag.nowarp &&
  4250. guild_mapname2gc(sd->mapname) == NULL)
  4251. continue;
  4252. clif_skill_nodamage(src,bl,skillid,skilllv,1);
  4253. if(map_getcell(sd->bl.m,sd->bl.x+dx[j],sd->bl.y+dy[j],CELL_CHKNOPASS))
  4254. dx[j] = dy[j] = 0;
  4255. pc_setpos(dstsd, sd->mapname, sd->bl.x+dx[j], sd->bl.y+dy[j], 2);
  4256. }
  4257. }
  4258. pc_blockskill_start (sd, skillid, 300000);
  4259. }
  4260. }
  4261. break;
  4262. default:
  4263. printf("Unknown skill used:%d\n",skillid);
  4264. map_freeblock_unlock();
  4265. return 1;
  4266. }
  4267. map_freeblock_unlock();
  4268. return 0;
  4269. }
  4270. /*==========================================
  4271. * スキル使用(詠唱完了、ID指定)
  4272. *------------------------------------------
  4273. */
  4274. int skill_castend_id( int tid, unsigned int tick, int id,int data )
  4275. {
  4276. struct map_session_data* sd = map_id2sd(id)/*,*target_sd=NULL*/;
  4277. struct block_list *bl;
  4278. int range,inf2;
  4279. nullpo_retr(0, sd);
  4280. if( sd->bl.prev == NULL ) //prevが無いのはありなの?
  4281. return 0;
  4282. if(sd->skillid != SA_CASTCANCEL && sd->skilltimer != tid ) /* タイマIDの確認 */
  4283. return 0;
  4284. if(sd->skillid != SA_CASTCANCEL && sd->skilltimer != -1 && pc_checkskill(sd,SA_FREECAST) > 0) {
  4285. sd->speed = sd->prev_speed;
  4286. clif_updatestatus(sd,SP_SPEED);
  4287. }
  4288. if(sd->skillid != SA_CASTCANCEL)
  4289. sd->skilltimer=-1;
  4290. if((bl=map_id2bl(sd->skilltarget))==NULL || bl->prev==NULL) {
  4291. sd->canact_tick = tick;
  4292. sd->canmove_tick = tick;
  4293. sd->skillitem = sd->skillitemlv = -1;
  4294. return 0;
  4295. }
  4296. if(sd->bl.m != bl->m || pc_isdead(sd)) { //マップが違うか自分が死んでいる
  4297. sd->canact_tick = tick;
  4298. sd->canmove_tick = tick;
  4299. sd->skillitem = sd->skillitemlv = -1;
  4300. return 0;
  4301. }
  4302. if(sd->skillid == PR_LEXAETERNA) {
  4303. struct status_change *sc_data = status_get_sc_data(bl);
  4304. if(sc_data && (sc_data[SC_FREEZE].timer != -1 || (sc_data[SC_STONE].timer != -1 && sc_data[SC_STONE].val2 == 0))) {
  4305. clif_skill_fail(sd,sd->skillid,0,0);
  4306. sd->canact_tick = tick;
  4307. sd->canmove_tick = tick;
  4308. sd->skillitem = sd->skillitemlv = -1;
  4309. return 0;
  4310. }
  4311. }
  4312. else if(sd->skillid == RG_BACKSTAP) {
  4313. int dir = map_calc_dir(&sd->bl,bl->x,bl->y),t_dir = status_get_dir(bl);
  4314. int dist = distance(sd->bl.x,sd->bl.y,bl->x,bl->y);
  4315. if(bl->type != BL_SKILL && (dist == 0 || map_check_dir(dir,t_dir))) {
  4316. clif_skill_fail(sd,sd->skillid,0,0);
  4317. sd->canact_tick = tick;
  4318. sd->canmove_tick = tick;
  4319. sd->skillitem = sd->skillitemlv = -1;
  4320. return 0;
  4321. }
  4322. }
  4323. inf2 = skill_get_inf2(sd->skillid);
  4324. if( ( (skill_get_inf(sd->skillid)&1) || inf2&4 ) && // 彼我敵??係チェック
  4325. battle_check_target(&sd->bl,bl, BCT_ENEMY)<=0 ) {
  4326. sd->canact_tick = tick;
  4327. sd->canmove_tick = tick;
  4328. sd->skillitem = sd->skillitemlv = -1;
  4329. return 0;
  4330. }
  4331. if(inf2 & 0xC00 && sd->bl.id != bl->id) {
  4332. int fail_flag = 1;
  4333. if(inf2 & 0x400 && battle_check_target(&sd->bl,bl, BCT_PARTY) > 0)
  4334. fail_flag = 0;
  4335. if(inf2 & 0x800 && sd->status.guild_id > 0 && sd->status.guild_id == status_get_guild_id(bl))
  4336. fail_flag = 0;
  4337. if(fail_flag) {
  4338. clif_skill_fail(sd,sd->skillid,0,0);
  4339. sd->canact_tick = tick;
  4340. sd->canmove_tick = tick;
  4341. sd->skillitem = sd->skillitemlv = -1;
  4342. return 0;
  4343. }
  4344. }
  4345. range = skill_get_range(sd->skillid,sd->skilllv);
  4346. if(range < 0)
  4347. range = status_get_range(&sd->bl) - (range + 1);
  4348. range += battle_config.pc_skill_add_range;
  4349. if((sd->skillid == MO_EXTREMITYFIST && sd->sc_data[SC_COMBO].timer != -1 && sd->sc_data[SC_COMBO].val1 == MO_COMBOFINISH) ||
  4350. (sd->skillid == CH_TIGERFIST && sd->sc_data[SC_COMBO].timer != -1 && sd->sc_data[SC_COMBO].val1 == MO_COMBOFINISH) ||
  4351. (sd->skillid == CH_CHAINCRUSH && sd->sc_data[SC_COMBO].timer != -1 && sd->sc_data[SC_COMBO].val1 == MO_COMBOFINISH) ||
  4352. (sd->skillid == CH_CHAINCRUSH && sd->sc_data[SC_COMBO].timer != -1 && sd->sc_data[SC_COMBO].val1 == CH_TIGERFIST))
  4353. range += skill_get_blewcount(MO_COMBOFINISH,sd->sc_data[SC_COMBO].val2);
  4354. if(battle_config.skill_out_range_consume) { // changed to allow casting when target walks out of range [Valaris]
  4355. if(range < distance(sd->bl.x,sd->bl.y,bl->x,bl->y)) {
  4356. clif_skill_fail(sd,sd->skillid,0,0);
  4357. sd->canact_tick = tick;
  4358. sd->canmove_tick = tick;
  4359. sd->skillitem = sd->skillitemlv = -1;
  4360. return 0;
  4361. }
  4362. }
  4363. if(!skill_check_condition(sd,1)) { /* 使用?件チェック */
  4364. sd->canact_tick = tick;
  4365. sd->canmove_tick = tick;
  4366. sd->skillitem = sd->skillitemlv = -1;
  4367. return 0;
  4368. }
  4369. sd->skillitem = sd->skillitemlv = -1;
  4370. if(battle_config.skill_out_range_consume) {
  4371. if(range < distance(sd->bl.x,sd->bl.y,bl->x,bl->y)) {
  4372. clif_skill_fail(sd,sd->skillid,0,0);
  4373. sd->canact_tick = tick;
  4374. sd->canmove_tick = tick;
  4375. return 0;
  4376. }
  4377. }
  4378. if(battle_config.pc_skill_log)
  4379. printf("PC %d skill castend skill=%d\n",sd->bl.id,sd->skillid);
  4380. pc_stop_walking(sd,0);
  4381. switch( skill_get_nk(sd->skillid) )
  4382. {
  4383. /* 攻?系/吹き飛ばし系 */
  4384. case 0: case 2:
  4385. skill_castend_damage_id(&sd->bl,bl,sd->skillid,sd->skilllv,tick,0);
  4386. break;
  4387. case 1:/* 支援系 */
  4388. if( (sd->skillid==AL_HEAL || (sd->skillid==ALL_RESURRECTION && bl->type != BL_PC) || sd->skillid==PR_ASPERSIO) && battle_check_undead(status_get_race(bl),status_get_elem_type(bl)))
  4389. skill_castend_damage_id(&sd->bl,bl,sd->skillid,sd->skilllv,tick,0);
  4390. else
  4391. skill_castend_nodamage_id(&sd->bl,bl,sd->skillid,sd->skilllv,tick,0);
  4392. break;
  4393. }
  4394. return 0;
  4395. }
  4396. /*==========================================
  4397. * スキル使用(詠唱完了、場所指定の?際の?理)
  4398. *------------------------------------------
  4399. */
  4400. int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skilllv,unsigned int tick,int flag)
  4401. {
  4402. struct map_session_data *sd=NULL;
  4403. int i,tmpx = 0,tmpy = 0, x1 = 0, y1 = 0;
  4404. //if(skilllv <= 0) return 0;
  4405. if(skillid > 0 && skilllv <= 0) return 0; // celest
  4406. nullpo_retr(0, src);
  4407. if(src->type==BL_PC){
  4408. nullpo_retr(0, sd=(struct map_session_data *)src);
  4409. }
  4410. if( skillid != WZ_METEOR &&
  4411. skillid != AM_CANNIBALIZE &&
  4412. skillid != AM_SPHEREMINE)
  4413. clif_skill_poseffect(src,skillid,skilllv,x,y,tick);
  4414. if (sd && skillnotok(skillid, sd)) // [MouseJstr]
  4415. return 0;
  4416. switch(skillid)
  4417. {
  4418. case PR_BENEDICTIO: /* 聖?降福 */
  4419. skill_area_temp[1]=src->id;
  4420. map_foreachinarea(skill_area_sub,
  4421. src->m,x-1,y-1,x+1,y+1,0,
  4422. src,skillid,skilllv,tick, flag|BCT_NOENEMY|1,
  4423. skill_castend_nodamage_id);
  4424. map_foreachinarea(skill_area_sub,
  4425. src->m,x-1,y-1,x+1,y+1,0,
  4426. src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
  4427. skill_castend_damage_id);
  4428. break;
  4429. case BS_HAMMERFALL: /* ハンマ?フォ?ル */
  4430. skill_area_temp[1]=src->id;
  4431. skill_area_temp[2]=x;
  4432. skill_area_temp[3]=y;
  4433. map_foreachinarea(skill_area_sub,
  4434. src->m,x-2,y-2,x+2,y+2,0,
  4435. src,skillid,skilllv,tick, flag|BCT_ENEMY|2,
  4436. skill_castend_nodamage_id);
  4437. break;
  4438. case HT_DETECTING: /* ディテクティング */
  4439. {
  4440. const int range=7;
  4441. if(src->x!=x)
  4442. x+=(src->x-x>0)?-range:range;
  4443. if(src->y!=y)
  4444. y+=(src->y-y>0)?-range:range;
  4445. map_foreachinarea( status_change_timer_sub,
  4446. src->m, x-range, y-range, x+range,y+range,0,
  4447. src,SC_SIGHT,tick);
  4448. }
  4449. break;
  4450. case MG_SAFETYWALL: /* セイフティウォ?ル */
  4451. case MG_FIREWALL: /* ファイヤ?ウォ?ル */
  4452. case MG_THUNDERSTORM: /* サンダ?スト?ム */
  4453. case AL_PNEUMA: /* ニュ?マ */
  4454. case WZ_ICEWALL: /* アイスウォ?ル */
  4455. case WZ_FIREPILLAR: /* ファイアピラ? */
  4456. case WZ_QUAGMIRE: /* クァグマイア */
  4457. case WZ_VERMILION: /* ロ?ドオブヴァ?ミリオン */
  4458. //case WZ_FROSTNOVA: /* フロストノヴァ */
  4459. case WZ_STORMGUST: /* スト?ムガスト */
  4460. case WZ_HEAVENDRIVE: /* ヘヴンズドライブ */
  4461. case PR_SANCTUARY: /* サンクチュアリ */
  4462. case PR_MAGNUS: /* マグヌスエクソシズム */
  4463. case CR_GRANDCROSS: /* グランドクロス */
  4464. case NPC_DARKGRANDCROSS: /*闇グランドクロス*/
  4465. case HT_SKIDTRAP: /* スキッドトラップ */
  4466. case HT_LANDMINE: /* ランドマイン */
  4467. case HT_ANKLESNARE: /* アンクルスネア */
  4468. case HT_SHOCKWAVE: /* ショックウェ?ブトラップ */
  4469. case HT_SANDMAN: /* サンドマン */
  4470. case HT_FLASHER: /* フラッシャ? */
  4471. case HT_FREEZINGTRAP: /* フリ?ジングトラップ */
  4472. case HT_BLASTMINE: /* ブラストマイン */
  4473. case HT_CLAYMORETRAP: /* クレイモア?トラップ */
  4474. case AS_VENOMDUST: /* ベノムダスト */
  4475. case AM_DEMONSTRATION: /* デモンストレ?ション */
  4476. case PF_SPIDERWEB: /* スパイダ?ウェッブ */
  4477. case PF_FOGWALL: /* フォグウォ?ル */
  4478. case HT_TALKIEBOX: /* ト?キ?ボックス */
  4479. skill_unitsetting(src,skillid,skilllv,x,y,0);
  4480. break;
  4481. case RG_GRAFFITI: /* Graffiti [Valaris] */
  4482. skill_clear_unitgroup(src);
  4483. skill_unitsetting(src,skillid,skilllv,x,y,0);
  4484. break;
  4485. case SA_VOLCANO: /* ボルケ?ノ */
  4486. case SA_DELUGE: /* デリュ?ジ */
  4487. case SA_VIOLENTGALE: /* バイオレントゲイル */
  4488. case SA_LANDPROTECTOR: /* ランドプロテクタ? */
  4489. skill_clear_element_field(src);//?に自分が?動している?性場をクリア
  4490. skill_unitsetting(src,skillid,skilllv,x,y,0);
  4491. break;
  4492. case WZ_METEOR: //メテオスト?ム
  4493. {
  4494. int flag=0;
  4495. for(i=0;i<2+(skilllv>>1);i++) {
  4496. int j=0;
  4497. do {
  4498. tmpx = x + (rand()%7 - 3);
  4499. tmpy = y + (rand()%7 - 3);
  4500. if(tmpx < 0)
  4501. tmpx = 0;
  4502. else if(tmpx >= map[src->m].xs)
  4503. tmpx = map[src->m].xs - 1;
  4504. if(tmpy < 0)
  4505. tmpy = 0;
  4506. else if(tmpy >= map[src->m].ys)
  4507. tmpy = map[src->m].ys - 1;
  4508. j++;
  4509. } while((map_getcell(src->m,tmpx,tmpy,CELL_CHKNOPASS)) && j<100);
  4510. if(j >= 100)
  4511. continue;
  4512. if(flag==0){
  4513. clif_skill_poseffect(src,skillid,skilllv,tmpx,tmpy,tick);
  4514. flag=1;
  4515. }
  4516. if(i > 0)
  4517. skill_addtimerskill(src,tick+i*1000,0,tmpx,tmpy,skillid,skilllv,(x1<<16)|y1,flag);
  4518. x1 = tmpx;
  4519. y1 = tmpy;
  4520. }
  4521. skill_addtimerskill(src,tick+i*1000,0,tmpx,tmpy,skillid,skilllv,-1,flag);
  4522. }
  4523. break;
  4524. case AL_WARP: /* ワ?プポ?タル */
  4525. if(sd) {
  4526. if(map[sd->bl.m].flag.noteleport) /* テレポ禁止 */
  4527. break;
  4528. clif_skill_warppoint(sd,sd->skillid,sd->status.save_point.map,
  4529. (sd->skilllv>1)?sd->status.memo_point[0].map:"",
  4530. (sd->skilllv>2)?sd->status.memo_point[1].map:"",
  4531. (sd->skilllv>3)?sd->status.memo_point[2].map:"");
  4532. }
  4533. break;
  4534. case MO_BODYRELOCATION:
  4535. if(sd){
  4536. pc_movepos(sd,x,y);
  4537. }else if( src->type==BL_MOB )
  4538. mob_warp((struct mob_data *)src,-1,x,y,0);
  4539. if (sd)
  4540. pc_blockskill_start (sd, MO_EXTREMITYFIST, 2000);
  4541. break;
  4542. case AM_CANNIBALIZE: // バイオプラント
  4543. if(sd){
  4544. int mx,my,id=0;
  4545. int summons[5] = { 1020, 1068, 1118, 1500, 1368 };
  4546. struct mob_data *md;
  4547. mx = x;// + (rand()%10 - 5);
  4548. my = y;// + (rand()%10 - 5);
  4549. id=mob_once_spawn(sd,"this",mx,my,"--ja--", summons[skilllv-1] ,1,"");
  4550. if( (md=(struct mob_data *)map_id2bl(id)) !=NULL ){
  4551. md->master_id=sd->bl.id;
  4552. md->hp=2210+skilllv*200;
  4553. md->state.special_mob_ai=1;
  4554. md->deletetimer=add_timer(gettick()+skill_get_time(skillid,skilllv),mob_timer_delete,id,0);
  4555. }
  4556. clif_skill_poseffect(src,skillid,skilllv,x,y,tick);
  4557. }
  4558. break;
  4559. case AM_SPHEREMINE: // スフィア?マイン
  4560. if(sd){
  4561. int mx,my,id=0;
  4562. struct mob_data *md;
  4563. mx = x;// + (rand()%10 - 5);
  4564. my = y;// + (rand()%10 - 5);
  4565. id=mob_once_spawn(sd,"this",mx,my,"--ja--",1142,1,"");
  4566. if( (md=(struct mob_data *)map_id2bl(id)) !=NULL ){
  4567. md->master_id=sd->bl.id;
  4568. md->hp=2000+skilllv*400;
  4569. md->state.special_mob_ai=2;
  4570. md->deletetimer=add_timer(gettick()+skill_get_time(skillid,skilllv),mob_timer_delete,id,0);
  4571. }
  4572. clif_skill_poseffect(src,skillid,skilllv,x,y,tick);
  4573. }
  4574. break;
  4575. // Slim Pitcher [Celest]
  4576. case CR_SLIMPITCHER:
  4577. {
  4578. if (sd) {
  4579. int i = skilllv%11 - 1;
  4580. int j = pc_search_inventory(sd,skill_db[skillid].itemid[i]);
  4581. if(j < 0 || skill_db[skillid].itemid[i] <= 0 || sd->inventory_data[j] == NULL ||
  4582. sd->status.inventory[j].amount < skill_db[skillid].amount[i]) {
  4583. clif_skill_fail(sd,skillid,0,0);
  4584. return 1;
  4585. }
  4586. sd->state.potionpitcher_flag = 1;
  4587. sd->potion_hp = 0;
  4588. run_script(sd->inventory_data[j]->use_script,0,sd->bl.id,0);
  4589. pc_delitem(sd,j,skill_db[skillid].amount[i],0);
  4590. sd->state.potionpitcher_flag = 0;
  4591. clif_skill_poseffect(src,skillid,skilllv,x,y,tick);
  4592. if(sd->potion_hp > 0) {
  4593. map_foreachinarea(skill_area_sub,
  4594. src->m,x-3,y-3,x+3,y+3,0,
  4595. src,skillid,skilllv,tick,flag|BCT_PARTY|1,
  4596. skill_castend_nodamage_id);
  4597. }
  4598. }
  4599. }
  4600. break;
  4601. }
  4602. return 0;
  4603. }
  4604. /*==========================================
  4605. * スキル使用(詠唱完了、map指定)
  4606. *------------------------------------------
  4607. */
  4608. int skill_castend_map( struct map_session_data *sd,int skill_num, const char *map)
  4609. {
  4610. int x=0,y=0;
  4611. nullpo_retr(0, sd);
  4612. if( sd->bl.prev == NULL || pc_isdead(sd) )
  4613. return 0;
  4614. if(skillnotok(skill_num, sd))
  4615. return 0;
  4616. if( sd->opt1>0 || sd->status.option&2 )
  4617. return 0;
  4618. //スキルが使えない?態異常中
  4619. if(sd->sc_count){
  4620. if( sd->sc_data[SC_DIVINA].timer!=-1 ||
  4621. sd->sc_data[SC_ROKISWEIL].timer!=-1 ||
  4622. sd->sc_data[SC_AUTOCOUNTER].timer != -1 ||
  4623. sd->sc_data[SC_STEELBODY].timer != -1 ||
  4624. sd->sc_data[SC_DANCING].timer!=-1 ||
  4625. sd->sc_data[SC_BERSERK].timer != -1 ||
  4626. sd->sc_data[SC_MARIONETTE].timer != -1)
  4627. return 0;
  4628. }
  4629. if( skill_num != sd->skillid) /* 不正パケットらしい */
  4630. return 0;
  4631. pc_stopattack(sd);
  4632. if(battle_config.pc_skill_log)
  4633. printf("PC %d skill castend skill =%d map=%s\n",sd->bl.id,skill_num,map);
  4634. pc_stop_walking(sd,0);
  4635. if(strcmp(map,"cancel")==0)
  4636. return 0;
  4637. switch(skill_num){
  4638. case AL_TELEPORT: /* テレポ?ト */
  4639. if(strcmp(map,"Random")==0)
  4640. pc_randomwarp(sd,3);
  4641. else
  4642. pc_setpos(sd,sd->status.save_point.map,
  4643. sd->status.save_point.x,sd->status.save_point.y,3);
  4644. break;
  4645. case AL_WARP: /* ワ?プポ?タル */
  4646. {
  4647. const struct point *p[4];
  4648. struct skill_unit_group *group;
  4649. int i;
  4650. int maxcount=0;
  4651. p[0] = &sd->status.save_point;
  4652. p[1] = &sd->status.memo_point[0];
  4653. p[2] = &sd->status.memo_point[1];
  4654. p[3] = &sd->status.memo_point[2];
  4655. if((maxcount = skill_get_maxcount(sd->skillid)) > 0) {
  4656. int c;
  4657. for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
  4658. if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == sd->skillid)
  4659. c++;
  4660. }
  4661. if(c >= maxcount) {
  4662. clif_skill_fail(sd,sd->skillid,0,0);
  4663. sd->canact_tick = gettick();
  4664. sd->canmove_tick = gettick();
  4665. sd->skillitem = sd->skillitemlv = -1;
  4666. return 0;
  4667. }
  4668. }
  4669. if(sd->skilllv <= 0) return 0;
  4670. for(i=0;i<sd->skilllv;i++){
  4671. if(strcmp(map,p[i]->map)==0){
  4672. x=p[i]->x;
  4673. y=p[i]->y;
  4674. break;
  4675. }
  4676. }
  4677. if(x==0 || y==0) /* 不正パケット? */
  4678. return 0;
  4679. if(!skill_check_condition(sd,3))
  4680. return 0;
  4681. if((group=skill_unitsetting(&sd->bl,sd->skillid,sd->skilllv,sd->skillx,sd->skilly,0))==NULL)
  4682. return 0;
  4683. group->valstr=(char *)aCallocA(24,sizeof(char));
  4684. memcpy(group->valstr,map,24);
  4685. group->val2=(x<<16)|y;
  4686. }
  4687. break;
  4688. }
  4689. return 0;
  4690. }
  4691. /*==========================================
  4692. * スキルユニット設定?理
  4693. *------------------------------------------
  4694. */
  4695. struct skill_unit_group *skill_unitsetting( struct block_list *src, int skillid,int skilllv,int x,int y,int flag)
  4696. {
  4697. struct skill_unit_group *group;
  4698. int i,limit,val1=0,val2=0,val3=0;
  4699. int count=0;
  4700. int target,interval,range,unit_flag;
  4701. struct skill_unit_layout *layout;
  4702. struct status_change *sc_data;
  4703. int active_flag=1;
  4704. nullpo_retr(0, src);
  4705. limit = skill_get_time(skillid,skilllv);
  4706. range = skill_get_unit_range(skillid);
  4707. interval = skill_get_unit_interval(skillid);
  4708. target = skill_get_unit_target(skillid);
  4709. unit_flag = skill_get_unit_flag(skillid);
  4710. layout = skill_get_unit_layout(skillid,skilllv,src,x,y);
  4711. if (unit_flag&UF_DEFNOTENEMY && battle_config.defnotenemy)
  4712. target = BCT_NOENEMY;
  4713. sc_data = status_get_sc_data(src); // for firewall and fogwall - celest
  4714. switch(skillid){ /* 設定 */
  4715. case MG_SAFETYWALL: /* セイフティウォ?ル */
  4716. val2=skilllv+1;
  4717. break;
  4718. case MG_FIREWALL: /* ファイヤ?ウォ?ル */
  4719. if(sc_data && sc_data[SC_VIOLENTGALE].timer!=-1)
  4720. limit = limit*3/2;
  4721. val2=4+skilllv;
  4722. break;
  4723. case AL_WARP: /* ワ?プポ?タル */
  4724. val1=skilllv+6;
  4725. if(flag==0)
  4726. limit=2000;
  4727. active_flag=0;
  4728. break;
  4729. case PR_SANCTUARY: /* サンクチュアリ */
  4730. val1=(skilllv+3)*2;
  4731. val2=(skilllv>6)?777:skilllv*100;
  4732. interval += 500;
  4733. break;
  4734. case WZ_FIREPILLAR: /* ファイア?ピラ? */
  4735. if(flag!=0)
  4736. limit=1000;
  4737. val1=skilllv+2;
  4738. if(skilllv >= 6)
  4739. range=2;
  4740. break;
  4741. case HT_SANDMAN: /* サンドマン */
  4742. case HT_CLAYMORETRAP: /* クレイモア?トラップ */
  4743. case HT_SKIDTRAP: /* スキッドトラップ */
  4744. case HT_LANDMINE: /* ランドマイン */
  4745. case HT_ANKLESNARE: /* アンクルスネア */
  4746. case HT_FLASHER: /* フラッシャ? */
  4747. case HT_FREEZINGTRAP: /* フリ?ジングトラップ */
  4748. case HT_BLASTMINE: /* ブラストマイン */
  4749. // longer trap times in WOE [celest]
  4750. if (map[src->m].flag.gvg) limit *= 4;
  4751. break;
  4752. case HT_SHOCKWAVE: /* ショックウェ?ブトラップ */
  4753. val1=skilllv*15+10;
  4754. break;
  4755. case SA_LANDPROTECTOR: /* グランドクロス */
  4756. {
  4757. int aoe_diameter; // -- aoe_diameter (moonsoul) added for sage Area Of Effect skills
  4758. val1=skilllv*15+10;
  4759. aoe_diameter=skilllv+skilllv%2+5;
  4760. count=aoe_diameter*aoe_diameter; // -- this will not function if changed to ^2 (moonsoul)
  4761. }
  4762. break;
  4763. case BA_WHISTLE: /* 口笛 */
  4764. if(src->type == BL_PC)
  4765. val1 = (pc_checkskill((struct map_session_data *)src,BA_MUSICALLESSON)+1)>>1;
  4766. val2 = ((status_get_agi(src)/10)&0xffff)<<16;
  4767. val2 |= (status_get_luk(src)/10)&0xffff;
  4768. break;
  4769. case DC_HUMMING: /* ハミング */
  4770. if(src->type == BL_PC)
  4771. val1 = (pc_checkskill((struct map_session_data *)src,DC_DANCINGLESSON)+1)>>1;
  4772. val2 = status_get_dex(src)/10;
  4773. break;
  4774. case DC_DONTFORGETME: /* 私を忘れないで… */
  4775. if(src->type == BL_PC)
  4776. val1 = (pc_checkskill((struct map_session_data *)src,DC_DANCINGLESSON)+1)>>1;
  4777. val2 = ((status_get_str(src)/20)&0xffff)<<16;
  4778. val2 |= (status_get_agi(src)/10)&0xffff;
  4779. break;
  4780. case BA_POEMBRAGI: /* ブラギの詩 */
  4781. if(src->type == BL_PC)
  4782. val1 = pc_checkskill((struct map_session_data *)src,BA_MUSICALLESSON);
  4783. val2 = ((status_get_dex(src)/10)&0xffff)<<16;
  4784. val2 |= (status_get_int(src)/5)&0xffff;
  4785. break;
  4786. case BA_APPLEIDUN: /* イドゥンの林檎 */
  4787. if(src->type == BL_PC)
  4788. val1 = pc_checkskill((struct map_session_data *)src,BA_MUSICALLESSON)&0xffff;
  4789. val2 |= (status_get_vit(src))&0xffff;
  4790. val3 = 0;//回復用タイムカウンタ(6秒?に1?加)
  4791. break;
  4792. case DC_SERVICEFORYOU: /* サ?ビスフォ?ユ? */
  4793. if(src->type == BL_PC)
  4794. val1 = (pc_checkskill((struct map_session_data *)src,DC_DANCINGLESSON)+1)>>1;
  4795. val2 = status_get_int(src)/10;
  4796. break;
  4797. case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
  4798. if(src->type == BL_PC)
  4799. val1 = (pc_checkskill((struct map_session_data *)src,BA_MUSICALLESSON)+1)>>1;
  4800. val2 = status_get_agi(src)/20;
  4801. break;
  4802. case DC_FORTUNEKISS: /* 幸運のキス */
  4803. if(src->type == BL_PC)
  4804. val1 = (pc_checkskill((struct map_session_data *)src,DC_DANCINGLESSON)+1)>>1;
  4805. val2 = status_get_luk(src)/10;
  4806. break;
  4807. case PF_FOGWALL: /* フォグウォ?ル */
  4808. if(sc_data && sc_data[SC_DELUGE].timer!=-1) limit *= 2;
  4809. break;
  4810. case RG_GRAFFITI: /* Graffiti */
  4811. count=1; // Leave this at 1 [Valaris]
  4812. break;
  4813. }
  4814. nullpo_retr(NULL, group=skill_initunitgroup(src,(count > 0 ? count : layout->count),
  4815. skillid,skilllv,skill_get_unit_id(skillid,flag&1)));
  4816. group->limit=limit;
  4817. group->val1=val1;
  4818. group->val2=val2;
  4819. group->val3=val3;
  4820. group->target_flag=target;
  4821. group->interval=interval;
  4822. if(skillid==HT_TALKIEBOX ||
  4823. skillid==RG_GRAFFITI){
  4824. group->valstr=aCallocA(80, 1);
  4825. if(group->valstr==NULL){
  4826. printf("skill_castend_map: out of memory !\n");
  4827. exit(1);
  4828. }
  4829. memcpy(group->valstr,talkie_mes,80);
  4830. }
  4831. for(i=0;i<layout->count;i++){
  4832. struct skill_unit *unit;
  4833. int ux,uy,val1=skilllv,val2=0,limit=group->limit,alive=1;
  4834. ux = x + layout->dx[i];
  4835. uy = y + layout->dy[i];
  4836. switch (skillid) {
  4837. case MG_FIREWALL: /* ファイヤ?ウォ?ル */
  4838. val2=group->val2;
  4839. break;
  4840. case WZ_ICEWALL: /* アイスウォ?ル */
  4841. if(skilllv <= 1)
  4842. val1 = 500;
  4843. else
  4844. val1 = 200 + 200*skilllv;
  4845. break;
  4846. case RG_GRAFFITI: /* Graffiti [Valaris] */
  4847. ux+=(i%5-2);
  4848. uy+=(i/5-2);
  4849. break;
  4850. }
  4851. //直上スキルの場合設置座標上にランドプロテクタ?がないかチェック
  4852. if(range<=0)
  4853. map_foreachinarea(skill_landprotector,src->m,ux,uy,ux,uy,BL_SKILL,skillid,&alive);
  4854. if(skillid==WZ_ICEWALL && alive){
  4855. val2=map_getcell(src->m,ux,uy,CELL_GETTYPE);
  4856. if(val2==5 || val2==1)
  4857. alive=0;
  4858. else {
  4859. map_setcell(src->m,ux,uy,5);
  4860. clif_changemapcell(src->m,ux,uy,5,0);
  4861. }
  4862. }
  4863. if(alive){
  4864. nullpo_retr(NULL, unit=skill_initunit(group,i,ux,uy));
  4865. unit->val1=val1;
  4866. unit->val2=val2;
  4867. unit->limit=limit;
  4868. unit->range=range;
  4869. if (range==0 && active_flag)
  4870. map_foreachinarea(skill_unit_effect,unit->bl.m
  4871. ,unit->bl.x,unit->bl.y,unit->bl.x,unit->bl.y
  4872. ,0,&unit->bl,gettick(),1);
  4873. }
  4874. }
  4875. return group;
  4876. }
  4877. /*==========================================
  4878. * スキルユニットの?動イベント
  4879. *------------------------------------------
  4880. */
  4881. int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int tick)
  4882. {
  4883. struct skill_unit_group *sg;
  4884. struct block_list *ss;
  4885. struct skill_unit *unit2;
  4886. struct status_change *sc_data;
  4887. int type;
  4888. nullpo_retr(0, src);
  4889. nullpo_retr(0, bl);
  4890. if(bl->prev==NULL || !src->alive ||
  4891. (bl->type == BL_PC && pc_isdead((struct map_session_data *)bl)))
  4892. return 0;
  4893. nullpo_retr(0, sg=src->group);
  4894. nullpo_retr(0, ss=map_id2bl(sg->src_id));
  4895. sc_data = status_get_sc_data(bl);
  4896. type = SkillStatusChangeTable[sg->skill_id];
  4897. if (battle_check_target(&src->bl,bl,sg->target_flag)<=0)
  4898. return 0;
  4899. // 対象がLP上に居る場合は無効
  4900. if (map_find_skill_unit_oncell(bl,bl->x,bl->y,SA_LANDPROTECTOR,NULL))
  4901. return 0;
  4902. switch (sg->unit_id) {
  4903. case 0x85: /* ニューマ */
  4904. case 0x7e: /* セイフティウォール */
  4905. if (sc_data && sc_data[type].timer == -1)
  4906. status_change_start(bl,type,sg->skill_lv,(int)src,0,0,0,0);
  4907. break;
  4908. case 0x80: /* ワープポータル(発動後) */
  4909. if(bl->type==BL_PC){
  4910. struct map_session_data *sd = (struct map_session_data *)bl;
  4911. if(sd && src->bl.m == bl->m && src->bl.x == bl->x && src->bl.y == bl->y &&
  4912. src->bl.x == sd->to_x && src->bl.y == sd->to_y) {
  4913. if( battle_config.chat_warpportal || !sd->chatID ){
  4914. pc_setpos(sd,sg->valstr,sg->val2>>16,sg->val2&0xffff,3);
  4915. if(sg->src_id == bl->id || (strcmp(map[src->bl.m].name,sg->valstr) == 0 &&
  4916. src->bl.x == (sg->val2>>16) && src->bl.y == (sg->val2&0xffff) ))
  4917. skill_delunitgroup(sg);
  4918. if (--sg->val1<=0)
  4919. skill_delunitgroup(sg);
  4920. }
  4921. }
  4922. } else if(bl->type==BL_MOB && battle_config.mob_warpportal){
  4923. int m = map_mapname2mapid(sg->valstr);
  4924. mob_warp((struct mob_data *)bl,m,sg->val2>>16,sg->val2&0xffff,3);
  4925. }
  4926. break;
  4927. case 0x8e: /* クァグマイア */
  4928. if(bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
  4929. break;
  4930. if(sc_data && sc_data[type].timer==-1)
  4931. status_change_start(bl,type,sg->skill_lv,(int)src,0,0,
  4932. skill_get_time2(sg->skill_id,sg->skill_lv),0);
  4933. break;
  4934. case 0x9a: /* ボルケ?ノ */
  4935. case 0x9b: /* デリュ?ジ */
  4936. case 0x9c: /* バイオレントゲイル */
  4937. if (sc_data && sc_data[type].timer!=-1) {
  4938. unit2 = (struct skill_unit *)sc_data[type].val4;
  4939. if (unit2 && unit2->group &&
  4940. (unit2==src || DIFF_TICK(sg->tick,unit2->group->tick)<=0))
  4941. break;
  4942. }
  4943. status_change_start(bl,type,sg->skill_lv,(int)src,0,0,
  4944. skill_get_time2(sg->skill_id,sg->skill_lv),0);
  4945. break;
  4946. case 0x9e: /* 子守唄 */
  4947. case 0x9f: /* ニヨルドの宴 */
  4948. case 0xa0: /* 永遠の混沌 */
  4949. case 0xa1: /* ?太鼓の響き */
  4950. case 0xa2: /* ニ?ベルングの指輪 */
  4951. case 0xa3: /* ロキの叫び */
  4952. case 0xa4: /* 深淵の中に */
  4953. case 0xa5: /* 不死身のジ?クフリ?ド */
  4954. case 0xa6: /* 不協和音 */
  4955. case 0xa7: /* 口笛 */
  4956. case 0xa8: /* 夕陽のアサシンクロス */
  4957. case 0xa9: /* ブラギの詩 */
  4958. case 0xaa: /* イドゥンの林檎 */
  4959. case 0xab: /* 自分勝手なダンス */
  4960. case 0xac: /* ハミング */
  4961. case 0xad: /* 私を忘れないで… */
  4962. case 0xae: /* 幸運のキス */
  4963. case 0xaf: /* サ?ビスフォ?ユ? */
  4964. if (sg->src_id==bl->id)
  4965. break;
  4966. if (sc_data && sc_data[type].timer!=-1) {
  4967. unit2 = (struct skill_unit *)sc_data[type].val4;
  4968. if (unit2 && unit2->group &&
  4969. (unit2 == src || DIFF_TICK(sg->tick,unit2->group->tick)<=0))
  4970. break;
  4971. }
  4972. status_change_start(bl,type,sg->skill_lv,sg->val1,sg->val2,
  4973. (int)src,skill_get_time2(sg->skill_id,sg->skill_lv),0);
  4974. break;
  4975. case 0xb4: // Basilica
  4976. if (battle_check_target(&src->bl,bl,BCT_NOENEMY)>0) {
  4977. if (sc_data && sc_data[type].timer!=-1) {
  4978. struct skill_unit_group *sg2 = (struct skill_unit_group *)sc_data[type].val4;
  4979. if (sg2 && (sg2 == src->group || DIFF_TICK(sg->tick,sg2->tick)<=0))
  4980. break;
  4981. } else
  4982. status_change_start(bl,type,sg->skill_lv,(int)src,0,0,
  4983. skill_get_time2(sg->skill_id,sg->skill_lv),0);
  4984. } else if (!status_get_mode(bl)&0x20)
  4985. skill_blown(&src->bl,bl,1);
  4986. break;
  4987. case 0xb6: /* フォグウォ?ル */
  4988. if (sc_data && sc_data[type].timer!=-1) {
  4989. unit2 = (struct skill_unit *)sc_data[type].val4;
  4990. if (unit2 && unit2->group &&
  4991. (unit2 == src || DIFF_TICK(sg->tick,unit2->group->tick)<=0))
  4992. break;
  4993. }
  4994. status_change_start(bl,type,sg->skill_lv,sg->val1,sg->val2,
  4995. (int)src,skill_get_time2(sg->skill_id,sg->skill_lv),0);
  4996. skill_additional_effect(ss,bl,sg->skill_id,sg->skill_lv,BF_MISC,tick);
  4997. break;
  4998. case 0xb2: /* あなたを_?いたいです */
  4999. case 0xb3: /* ゴスペル */
  5000. //case 0xb6: /* フォグウォ?ル */ - moved [celest]
  5001. //とりあえず何もしない
  5002. break;
  5003. /* default:
  5004. if(battle_config.error_log)
  5005. printf("skill_unit_onplace: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
  5006. break;*/
  5007. }
  5008. return 0;
  5009. }
  5010. /*==========================================
  5011. * スキルユニットの発動イベント(タイマー発動)
  5012. *------------------------------------------
  5013. */
  5014. int skill_unit_onplace_timer(struct skill_unit *src,struct block_list *bl,unsigned int tick)
  5015. {
  5016. struct skill_unit_group *sg;
  5017. struct block_list *ss;
  5018. int splash_count=0;
  5019. struct status_change *sc_data;
  5020. struct skill_unit_group_tickset *ts;
  5021. int type;
  5022. int diff=0;
  5023. nullpo_retr(0, src);
  5024. nullpo_retr(0, bl);
  5025. if (bl->type!=BL_PC && bl->type!=BL_MOB)
  5026. return 0;
  5027. if (bl->prev==NULL || !src->alive ||
  5028. (bl->type==BL_PC && pc_isdead((struct map_session_data *)bl)))
  5029. return 0;
  5030. nullpo_retr(0, sg=src->group);
  5031. nullpo_retr(0, ss=map_id2bl(sg->src_id));
  5032. sc_data = status_get_sc_data(bl);
  5033. type = SkillStatusChangeTable[sg->skill_id];
  5034. // 対象がLP上に居る場合は無効
  5035. if (map_find_skill_unit_oncell(bl,bl->x,bl->y,SA_LANDPROTECTOR,NULL))
  5036. return 0;
  5037. // 前に影響を受けてからintervalの間は影響を受けない
  5038. nullpo_retr(0,ts = skill_unitgrouptickset_search(bl,sg,tick));
  5039. diff = DIFF_TICK(tick,ts->tick);
  5040. if (sg->skill_id == PR_SANCTUARY)
  5041. diff += 500; // 新規に回復したユニットだけカウントするための仕掛け
  5042. if (diff < 0)
  5043. return 0;
  5044. ts->tick = tick+sg->interval;
  5045. // GXは重なっていたら3HITしない
  5046. if (sg->skill_id==CR_GRANDCROSS && !battle_config.gx_allhit)
  5047. ts->tick += sg->interval*(map_count_oncell(bl->m,bl->x,bl->y)-1);
  5048. switch (sg->unit_id) {
  5049. case 0x83: /* サンクチュアリ */
  5050. {
  5051. int race=status_get_race(bl);
  5052. if (battle_check_undead(race,status_get_elem_type(bl)) || race==6) {
  5053. if (skill_attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0)) {
  5054. // reduce healing count if this was meant for damaging [celest]
  5055. // sg->val1 /= 2;
  5056. sg->val1--; // チャットキャンセルに対応
  5057. }
  5058. } else {
  5059. int heal = sg->val2;
  5060. if (status_get_hp(bl)>=status_get_max_hp(bl))
  5061. break;
  5062. if(bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage)
  5063. heal=0; /* 黄金蟲カード(ヒール量0) */
  5064. clif_skill_nodamage(&src->bl,bl,AL_HEAL,heal,1);
  5065. battle_heal(NULL,bl,heal,0,0);
  5066. if (diff>=500)
  5067. sg->val1--; // 新規に入ったユニットだけカウント
  5068. }
  5069. if (sg->val1<=0)
  5070. skill_delunitgroup(sg);
  5071. break;
  5072. }
  5073. case 0x84: /* マグヌスエクソシズム */
  5074. {
  5075. int race = status_get_race(bl);
  5076. if (!battle_check_undead(race,status_get_elem_type(bl)) && race!=6)
  5077. return 0;
  5078. skill_attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
  5079. src->val2++;
  5080. break;
  5081. }
  5082. case 0x7f: /* ファイヤーウォール */
  5083. skill_attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
  5084. if (--src->val2<=0)
  5085. skill_delunit(src);
  5086. break;
  5087. case 0x86: /* ロードオブヴァーミリオン(TS,MS,FN,SG,HD,GX,闇GX) */
  5088. skill_attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
  5089. break;
  5090. case 0x87: /* ファイアーピラー(発動前) */
  5091. skill_delunit(src);
  5092. skill_unitsetting(ss,sg->skill_id,sg->skill_lv,src->bl.x,src->bl.y,1);
  5093. break;
  5094. case 0x88: /* ファイアーピラー(発動後) */
  5095. map_foreachinarea(skill_attack_area,bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
  5096. BF_MAGIC,ss,&src->bl,sg->skill_id,sg->skill_lv,tick,0,BCT_ENEMY); // area damage [Celest]
  5097. //skill_attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
  5098. break;
  5099. case 0x90: /* スキッドトラップ */
  5100. {
  5101. int i,c = skill_get_blewcount(sg->skill_id,sg->skill_lv);
  5102. if(map[bl->m].flag.gvg) c = 0;
  5103. for(i=0;i<c;i++)
  5104. skill_blown(&src->bl,bl,1|0x30000);
  5105. sg->unit_id = 0x8c;
  5106. clif_changelook(&src->bl,LOOK_BASE,sg->unit_id);
  5107. sg->limit=DIFF_TICK(tick,sg->tick)+1500;
  5108. }
  5109. break;
  5110. case 0x93: /* ランドマイン */
  5111. skill_attack(BF_MISC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
  5112. sg->unit_id = 0x8c;
  5113. clif_changelook(&src->bl,LOOK_BASE,0x88);
  5114. sg->limit=DIFF_TICK(tick,sg->tick)+1500;
  5115. break;
  5116. case 0x8f: /* ブラストマイン */
  5117. case 0x94: /* ショックウェ?ブトラップ */
  5118. case 0x95: /* サンドマン */
  5119. case 0x96: /* フラッシャ? */
  5120. case 0x97: /* フリ?ジングトラップ */
  5121. case 0x98: /* クレイモア?トラップ */
  5122. map_foreachinarea(skill_count_target,src->bl.m
  5123. ,src->bl.x-src->range,src->bl.y-src->range
  5124. ,src->bl.x+src->range,src->bl.y+src->range
  5125. ,0,&src->bl,&splash_count);
  5126. map_foreachinarea(skill_trap_splash,src->bl.m
  5127. ,src->bl.x-src->range,src->bl.y-src->range
  5128. ,src->bl.x+src->range,src->bl.y+src->range
  5129. ,0,&src->bl,tick,splash_count);
  5130. sg->unit_id = 0x8c;
  5131. clif_changelook(&src->bl,LOOK_BASE,sg->unit_id);
  5132. sg->limit=DIFF_TICK(tick,sg->tick)+1500;
  5133. break;
  5134. case 0x91: /* アンクルスネア */
  5135. if(sg->val2==0 && sc_data && sc_data[SC_ANKLE].timer==-1){
  5136. int moveblock = ( bl->x/BLOCK_SIZE != src->bl.x/BLOCK_SIZE || bl->y/BLOCK_SIZE != src->bl.y/BLOCK_SIZE);
  5137. int sec = skill_get_time2(sg->skill_id,sg->skill_lv) - status_get_agi(bl)*100;
  5138. if(status_get_mode(bl)&0x20)
  5139. sec = sec/5;
  5140. if (sec < 3000) // minimum time of 3 seconds [celest]
  5141. sec = 3000;
  5142. battle_stopwalking(bl,1);
  5143. status_change_start(bl,SC_ANKLE,sg->skill_lv,0,0,0,sec,0);
  5144. skill_unit_move(bl,tick,0);
  5145. if(moveblock) map_delblock(bl);
  5146. bl->x = src->bl.x;
  5147. bl->y = src->bl.y;
  5148. if(moveblock) map_addblock(bl);
  5149. skill_unit_move(bl,tick,1);
  5150. if(bl->type == BL_MOB)
  5151. clif_fixmobpos((struct mob_data *)bl);
  5152. else if(bl->type == BL_PET)
  5153. clif_fixpetpos((struct pet_data *)bl);
  5154. else
  5155. clif_fixpos(bl);
  5156. clif_01ac(&src->bl);
  5157. sg->limit=DIFF_TICK(tick,sg->tick) + sec;
  5158. sg->val2=bl->id;
  5159. sg->interval = -1;
  5160. src->range = 0;
  5161. }
  5162. break;
  5163. case 0x92: /* ベノムダスト */
  5164. if(sc_data && sc_data[type].timer==-1 )
  5165. status_change_start(bl,type,sg->skill_lv,(int)src,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),0);
  5166. break;
  5167. case 0xb1: /* デモンストレ?ション */
  5168. skill_attack(BF_WEAPON,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
  5169. if(bl->type == BL_PC && rand()%100 < sg->skill_lv && battle_config.equipment_breaking)
  5170. pc_breakweapon((struct map_session_data *)bl);
  5171. break;
  5172. case 0x99: /* トーキーボックス */
  5173. if(sg->src_id == bl->id) //自分が踏んでも発動しない
  5174. break;
  5175. if(sg->val2==0){
  5176. clif_talkiebox(&src->bl,sg->valstr);
  5177. sg->unit_id = 0x8c;
  5178. clif_changelook(&src->bl,LOOK_BASE,sg->unit_id);
  5179. sg->limit=DIFF_TICK(tick,sg->tick)+5000;
  5180. sg->val2=-1; //踏んだ
  5181. }
  5182. break;
  5183. // Basilica
  5184. case 0xb4: /* バジリカ */
  5185. if (battle_check_target(&src->bl,bl,BCT_ENEMY)>0 &&
  5186. !(status_get_mode(bl)&0x20))
  5187. skill_blown(&src->bl,bl,1);
  5188. if (sg->src_id==bl->id)
  5189. break;
  5190. if (battle_check_target(&src->bl,bl,BCT_NOENEMY)>0 && sc_data && sc_data[type].timer == -1)
  5191. status_change_start(bl,type,sg->skill_lv,(int)src,0,0,
  5192. skill_get_time2(sg->skill_id,sg->skill_lv),0);
  5193. break;
  5194. case 0xb7: /* スパイダ?ウェッブ */
  5195. if(sg->val2==0){
  5196. int moveblock = ( bl->x/BLOCK_SIZE != src->bl.x/BLOCK_SIZE || bl->y/BLOCK_SIZE != src->bl.y/BLOCK_SIZE);
  5197. skill_additional_effect(ss,bl,sg->skill_id,sg->skill_lv,BF_MISC,tick);
  5198. skill_unit_move(bl,tick,0);
  5199. if(moveblock) map_delblock(bl);
  5200. bl->x = src->bl.x;
  5201. bl->y = src->bl.y;
  5202. if(moveblock) map_addblock(bl);
  5203. skill_unit_move(bl,tick,1);
  5204. if(bl->type == BL_MOB)
  5205. clif_fixmobpos((struct mob_data *)bl);
  5206. else if(bl->type == BL_PET)
  5207. clif_fixpetpos((struct pet_data *)bl);
  5208. else
  5209. clif_fixpos(bl);
  5210. sg->limit = DIFF_TICK(tick,sg->tick)+skill_get_time2(sg->skill_id,sg->skill_lv);
  5211. sg->val2=bl->id;
  5212. sg->interval = -1;
  5213. src->range = 0;
  5214. }
  5215. break;
  5216. /* default:
  5217. if(battle_config.error_log)
  5218. printf("skill_unit_onplace: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
  5219. break;*/
  5220. }
  5221. if(bl->type==BL_MOB && ss!=bl) /* スキル使用?件のMOBスキル */
  5222. {
  5223. if(battle_config.mob_changetarget_byskill == 1)
  5224. {
  5225. int target=((struct mob_data *)bl)->target_id;
  5226. if(ss->type == BL_PC)
  5227. ((struct mob_data *)bl)->target_id=ss->id;
  5228. mobskill_use((struct mob_data *)bl,tick,MSC_SKILLUSED|(sg->skill_id<<16));
  5229. ((struct mob_data *)bl)->target_id=target;
  5230. }
  5231. else
  5232. mobskill_use((struct mob_data *)bl,tick,MSC_SKILLUSED|(sg->skill_id<<16));
  5233. }
  5234. return 0;
  5235. }
  5236. /*==========================================
  5237. * スキルユニットから離?する(もしくはしている)場合
  5238. *------------------------------------------
  5239. */
  5240. int skill_unit_onout(struct skill_unit *src,struct block_list *bl,unsigned int tick)
  5241. {
  5242. struct skill_unit_group *sg;
  5243. struct status_change *sc_data;
  5244. int type;
  5245. nullpo_retr(0, src);
  5246. nullpo_retr(0, bl);
  5247. nullpo_retr(0, sg=src->group);
  5248. sc_data = status_get_sc_data(bl);
  5249. type = SkillStatusChangeTable[sg->skill_id];
  5250. if (bl->prev==NULL || !src->alive ||
  5251. (bl->type == BL_PC && pc_isdead((struct map_session_data *)bl)))
  5252. return 0;
  5253. switch(sg->unit_id){
  5254. case 0x7e: /* セイフティウォール */
  5255. case 0x85: /* ニューマ */
  5256. case 0x8e: /* クァグマイア */
  5257. case 0x9a: /* ボルケーノ */
  5258. case 0x9b: /* デリュージ */
  5259. case 0x9c: /* バイオレントゲイル */
  5260. if (type==SC_QUAGMIRE && bl->type==BL_MOB)
  5261. break;
  5262. if (sc_data && sc_data[type].timer!=-1 && sc_data[type].val2==(int)src) {
  5263. status_change_end(bl,type,-1);
  5264. }
  5265. break;
  5266. case 0x91: /* アンクルスネア */
  5267. {
  5268. struct block_list *target = map_id2bl(sg->val2);
  5269. if(target && target == bl){
  5270. status_change_end(bl,SC_ANKLE,-1);
  5271. sg->limit=DIFF_TICK(tick,sg->tick)+1000;
  5272. }
  5273. break;
  5274. }
  5275. case 0x9e: /* 子守唄 */
  5276. case 0x9f: /* ニヨルドの宴 */
  5277. case 0xa0: /* 永遠の混沌 */
  5278. case 0xa1: /* 戦太鼓の響き */
  5279. case 0xa2: /* ニーベルングの指輪 */
  5280. case 0xa3: /* ロキの叫び */
  5281. case 0xa4: /* 深淵の中に */
  5282. case 0xa5: /* 不死身のジークフリード */
  5283. case 0xad: /* 私を忘れないで… */
  5284. if (sc_data[type].timer!=-1 && sc_data[type].val4==(int)src) {
  5285. status_change_end(bl,type,-1);
  5286. }
  5287. break;
  5288. case 0xa6: /* 不協和音 */
  5289. case 0xa7: /* 口笛 */
  5290. case 0xa8: /* 夕陽のアサシンクロス */
  5291. case 0xa9: /* ブラギの詩 */
  5292. case 0xaa: /* イドゥンの林檎 */
  5293. case 0xab: /* 自分勝手なダンス */
  5294. case 0xac: /* ハミング */
  5295. case 0xae: /* 幸運のキス */
  5296. case 0xaf: /* サ?ビスフォ?ユ? */
  5297. status_change_start(bl,SkillStatusChangeTable[sg->skill_id],sg->skill_lv,0,0,0,20000,0 );
  5298. break;
  5299. case 0xb4: // Basilica
  5300. if (sc_data[type].timer!=-1 && sc_data[type].val4==(int)sg) {
  5301. status_change_end(bl,type,-1);
  5302. }
  5303. break;
  5304. case 0xb6:
  5305. {
  5306. struct block_list *target = map_id2bl(sg->val2);
  5307. if(target && target==bl) {
  5308. status_change_end(bl,SC_FOGWALL,-1);
  5309. if (sc_data && sc_data[SC_BLIND].timer!=-1)
  5310. sc_data[SC_BLIND].timer = add_timer(
  5311. gettick() + 30000, status_change_timer, bl->id, 0);
  5312. }
  5313. break;
  5314. }
  5315. case 0xb7: /* スパイダ?ウェッブ */
  5316. {
  5317. struct block_list *target = map_id2bl(sg->val2);
  5318. if (target && target==bl)
  5319. status_change_end(bl,SC_SPIDERWEB,-1);
  5320. sg->limit = DIFF_TICK(tick,sg->tick)+1000;
  5321. break;
  5322. }
  5323. /* default:
  5324. if(battle_config.error_log)
  5325. printf("skill_unit_onout: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
  5326. break;*/
  5327. }
  5328. return 0;
  5329. }
  5330. /*==========================================
  5331. * スキルユニット効果発動/離脱処理(foreachinarea)
  5332. * bl: ユニット(BL_PC/BL_MOB)
  5333. *------------------------------------------
  5334. */
  5335. int skill_unit_effect(struct block_list *bl,va_list ap)
  5336. {
  5337. struct skill_unit *unit;
  5338. struct skill_unit_group *group;
  5339. int flag;
  5340. unsigned int tick;
  5341. nullpo_retr(0, bl);
  5342. nullpo_retr(0, ap);
  5343. nullpo_retr(0, unit=va_arg(ap,struct skill_unit*));
  5344. tick = va_arg(ap,unsigned int);
  5345. flag = va_arg(ap,unsigned int);
  5346. if (bl->type!=BL_PC && bl->type!=BL_MOB)
  5347. return 0;
  5348. if (!unit->alive || bl->prev==NULL)
  5349. return 0;
  5350. nullpo_retr(0, group=unit->group);
  5351. if (flag)
  5352. skill_unit_onplace(unit,bl,tick);
  5353. else {
  5354. skill_unit_onout(unit,bl,tick);
  5355. unit = map_find_skill_unit_oncell(bl,bl->x,bl->y,group->skill_id,unit);
  5356. if (unit)
  5357. skill_unit_onplace(unit,bl,tick);
  5358. }
  5359. return 0;
  5360. }
  5361. /*==========================================
  5362. * スキルユニットの限界イベント
  5363. *------------------------------------------
  5364. */
  5365. int skill_unit_onlimit(struct skill_unit *src,unsigned int tick)
  5366. {
  5367. struct skill_unit_group *sg;
  5368. nullpo_retr(0, src);
  5369. nullpo_retr(0, sg=src->group);
  5370. switch(sg->unit_id){
  5371. case 0x81: /* ワ?プポ?タル(?動前) */
  5372. {
  5373. struct skill_unit_group *group=
  5374. skill_unitsetting(map_id2bl(sg->src_id),sg->skill_id,sg->skill_lv,
  5375. src->bl.x,src->bl.y,1);
  5376. if(group == NULL)
  5377. return 0;
  5378. group->valstr=aCallocA(24, 1);
  5379. if(group->valstr==NULL){
  5380. printf("skill_unit_onlimit: out of memory !\n");
  5381. exit(1);
  5382. }
  5383. memcpy(group->valstr,sg->valstr,24);
  5384. group->val2=sg->val2;
  5385. }
  5386. break;
  5387. case 0x8d: /* アイスウォ?ル */
  5388. map_setcell(src->bl.m,src->bl.x,src->bl.y,src->val2);
  5389. clif_changemapcell(src->bl.m,src->bl.x,src->bl.y,src->val2,1);
  5390. break;
  5391. case 0xb2: /* あなたに?いたい */
  5392. {
  5393. struct map_session_data *sd = NULL;
  5394. struct map_session_data *p_sd = NULL;
  5395. if((sd = map_id2sd(sg->src_id)) == NULL)
  5396. return 0;
  5397. if((p_sd = pc_get_partner(sd)) == NULL)
  5398. return 0;
  5399. pc_setpos(p_sd,map[src->bl.m].name,src->bl.x,src->bl.y,3);
  5400. }
  5401. break;
  5402. }
  5403. return 0;
  5404. }
  5405. /*==========================================
  5406. * スキルユニットのダメ?ジイベント
  5407. *------------------------------------------
  5408. */
  5409. int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl,
  5410. int damage,unsigned int tick)
  5411. {
  5412. struct skill_unit_group *sg;
  5413. nullpo_retr(0, src);
  5414. nullpo_retr(0, sg=src->group);
  5415. switch(sg->unit_id){
  5416. case 0x8d: /* アイスウォ?ル */
  5417. src->val1-=damage;
  5418. break;
  5419. case 0x8f: /* ブラストマイン */
  5420. case 0x98: /* クレイモア?トラップ */
  5421. skill_blown(bl,&src->bl,2); //吹き飛ばしてみる
  5422. break;
  5423. default:
  5424. damage = 0;
  5425. break;
  5426. }
  5427. return damage;
  5428. }
  5429. /*---------------------------------------------------------------------------- */
  5430. /*==========================================
  5431. * スキル使用(詠唱完了、場所指定)
  5432. *------------------------------------------
  5433. */
  5434. int skill_castend_pos( int tid, unsigned int tick, int id,int data )
  5435. {
  5436. struct map_session_data* sd=map_id2sd(id)/*,*target_sd=NULL*/;
  5437. int range,maxcount;
  5438. nullpo_retr(0, sd);
  5439. if( sd->bl.prev == NULL )
  5440. return 0;
  5441. if( sd->skilltimer != tid ) /* タイマIDの確認 */
  5442. return 0;
  5443. if(sd->skilltimer != -1 && pc_checkskill(sd,SA_FREECAST) > 0) {
  5444. sd->speed = sd->prev_speed;
  5445. clif_updatestatus(sd,SP_SPEED);
  5446. }
  5447. sd->skilltimer=-1;
  5448. if(pc_isdead(sd)) {
  5449. sd->canact_tick = tick;
  5450. sd->canmove_tick = tick;
  5451. sd->skillitem = sd->skillitemlv = -1;
  5452. return 0;
  5453. }
  5454. /*case MG_SAFETYWALL:
  5455. case WZ_FIREPILLAR:
  5456. case HT_SKIDTRAP:
  5457. case HT_LANDMINE:
  5458. case HT_ANKLESNARE:
  5459. case HT_SHOCKWAVE:
  5460. case HT_SANDMAN:
  5461. case HT_FLASHER:
  5462. case HT_FREEZINGTRAP:
  5463. case HT_BLASTMINE:
  5464. case HT_CLAYMORETRAP:
  5465. case HT_TALKIEBOX:
  5466. case AL_WARP:
  5467. case PF_SPIDERWEB:
  5468. case RG_GRAFFITI:
  5469. range = 0;
  5470. break;
  5471. case AL_PNEUMA:
  5472. range = 1;
  5473. break;*/
  5474. if (!battle_config.pc_skill_reiteration &&
  5475. skill_get_unit_flag(sd->skillid)&UF_NOREITERATION &&
  5476. skill_check_unit_range(sd->bl.m,sd->skillx,sd->skilly,sd->skillid,sd->skilllv)) {
  5477. clif_skill_fail(sd,sd->skillid,0,0);
  5478. sd->canact_tick = tick;
  5479. sd->canmove_tick = tick;
  5480. sd->skillitem = sd->skillitemlv = -1;
  5481. return 0;
  5482. }
  5483. /*case WZ_FIREPILLAR:
  5484. case HT_SKIDTRAP:
  5485. case HT_LANDMINE:
  5486. case HT_ANKLESNARE:
  5487. case HT_SHOCKWAVE:
  5488. case HT_SANDMAN:
  5489. case HT_FLASHER:
  5490. case HT_FREEZINGTRAP:
  5491. case HT_BLASTMINE:
  5492. case HT_CLAYMORETRAP:
  5493. case HT_TALKIEBOX:
  5494. case PF_SPIDERWEB:
  5495. case WZ_ICEWALL:
  5496. range = 2;
  5497. break;
  5498. case AL_WARP:
  5499. range = 0;
  5500. break;*/
  5501. if (battle_config.pc_skill_nofootset &&
  5502. skill_get_unit_flag(sd->skillid)&UF_NOFOOTSET &&
  5503. skill_check_unit_range2(sd->bl.m,sd->skillx,sd->skilly,sd->skillid,sd->skilllv)) {
  5504. clif_skill_fail(sd,sd->skillid,0,0);
  5505. sd->canact_tick = tick;
  5506. sd->canmove_tick = tick;
  5507. sd->skillitem = sd->skillitemlv = -1;
  5508. return 0;
  5509. }
  5510. if(battle_config.pc_land_skill_limit) {
  5511. maxcount = skill_get_maxcount(sd->skillid);
  5512. if(maxcount > 0) {
  5513. int i,c;
  5514. for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
  5515. if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == sd->skillid)
  5516. c++;
  5517. }
  5518. if(c >= maxcount) {
  5519. clif_skill_fail(sd,sd->skillid,0,0);
  5520. sd->canact_tick = tick;
  5521. sd->canmove_tick = tick;
  5522. sd->skillitem = sd->skillitemlv = -1;
  5523. return 0;
  5524. }
  5525. }
  5526. }
  5527. if(sd->skilllv <= 0) return 0;
  5528. range = skill_get_range(sd->skillid,sd->skilllv);
  5529. if(range < 0)
  5530. range = status_get_range(&sd->bl) - (range + 1);
  5531. range += battle_config.pc_skill_add_range;
  5532. if(battle_config.skill_out_range_consume) { // changed to allow casting when target walks out of range [Valaris]
  5533. if(range < distance(sd->bl.x,sd->bl.y,sd->skillx,sd->skilly)) {
  5534. clif_skill_fail(sd,sd->skillid,0,0);
  5535. sd->canact_tick = tick;
  5536. sd->canmove_tick = tick;
  5537. sd->skillitem = sd->skillitemlv = -1;
  5538. return 0;
  5539. }
  5540. }
  5541. if(!skill_check_condition(sd,1)) { /* 使用?件チェック */
  5542. sd->canact_tick = tick;
  5543. sd->canmove_tick = tick;
  5544. sd->skillitem = sd->skillitemlv = -1;
  5545. return 0;
  5546. }
  5547. sd->skillitem = sd->skillitemlv = -1;
  5548. if(battle_config.skill_out_range_consume) {
  5549. if(range < distance(sd->bl.x,sd->bl.y,sd->skillx,sd->skilly)) {
  5550. clif_skill_fail(sd,sd->skillid,0,0);
  5551. sd->canact_tick = tick;
  5552. sd->canmove_tick = tick;
  5553. return 0;
  5554. }
  5555. }
  5556. if(battle_config.pc_skill_log)
  5557. printf("PC %d skill castend skill=%d\n",sd->bl.id,sd->skillid);
  5558. pc_stop_walking(sd,0);
  5559. skill_castend_pos2(&sd->bl,sd->skillx,sd->skilly,sd->skillid,sd->skilllv,tick,0);
  5560. return 0;
  5561. }
  5562. /*==========================================
  5563. * 範??キャラ存在確認判定?理(foreachinarea)
  5564. *------------------------------------------
  5565. */
  5566. static int skill_check_condition_char_sub(struct block_list *bl,va_list ap)
  5567. {
  5568. int *c;
  5569. struct block_list *src;
  5570. struct map_session_data *sd;
  5571. struct map_session_data *ssd;
  5572. struct pc_base_job s_class;
  5573. struct pc_base_job ss_class;
  5574. nullpo_retr(0, bl);
  5575. nullpo_retr(0, ap);
  5576. nullpo_retr(0, sd=(struct map_session_data*)bl);
  5577. nullpo_retr(0, src=va_arg(ap,struct block_list *));
  5578. nullpo_retr(0, c=va_arg(ap,int *));
  5579. nullpo_retr(0, ssd=(struct map_session_data*)src);
  5580. s_class = pc_calc_base_job(sd->status.class_);
  5581. //チェックしない設定ならcにありえない大きな?字を返して終了
  5582. if(!battle_config.player_skill_partner_check){ //本?はforeachの前にやりたいけど設定適用箇所をまとめるためにここへ
  5583. (*c)=99;
  5584. return 0;
  5585. }
  5586. ss_class = pc_calc_base_job(ssd->status.class_);
  5587. switch(ssd->skillid){
  5588. case PR_BENEDICTIO: /* 聖?降福 */
  5589. if(sd != ssd && (s_class.job == 4 || s_class.job == 8 || s_class.job == 15) &&
  5590. (sd->bl.x == ssd->bl.x - 1 || sd->bl.x == ssd->bl.x + 1) && sd->status.sp >= 10)
  5591. (*c)++;
  5592. break;
  5593. case BD_LULLABY: /* 子守歌 */
  5594. case BD_RICHMANKIM: /* ニヨルドの宴 */
  5595. case BD_ETERNALCHAOS: /* 永遠の混沌 */
  5596. case BD_DRUMBATTLEFIELD: /* ?太鼓の響き */
  5597. case BD_RINGNIBELUNGEN: /* ニ?ベルングの指輪 */
  5598. case BD_ROKISWEIL: /* ロキの叫び */
  5599. case BD_INTOABYSS: /* 深淵の中に */
  5600. case BD_SIEGFRIED: /* 不死身のジ?クフリ?ド */
  5601. case BD_RAGNAROK: /* 神?の?昏 */
  5602. case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
  5603. if(sd != ssd &&
  5604. ((ss_class.job==19 && s_class.job==20) ||
  5605. (ss_class.job==20 && s_class.job==19)) &&
  5606. pc_checkskill(sd,ssd->skillid) > 0 &&
  5607. (*c)==0 &&
  5608. sd->status.party_id == ssd->status.party_id &&
  5609. !pc_issit(sd) &&
  5610. sd->sc_data[SC_DANCING].timer==-1
  5611. )
  5612. (*c)=pc_checkskill(sd,ssd->skillid);
  5613. break;
  5614. }
  5615. return 0;
  5616. }
  5617. /*==========================================
  5618. * 範??キャラ存在確認判定後スキル使用?理(foreachinarea)
  5619. *------------------------------------------
  5620. */
  5621. static int skill_check_condition_use_sub(struct block_list *bl,va_list ap)
  5622. {
  5623. int *c;
  5624. struct block_list *src;
  5625. struct map_session_data *sd;
  5626. struct map_session_data *ssd;
  5627. struct pc_base_job s_class;
  5628. struct pc_base_job ss_class;
  5629. int skillid,skilllv;
  5630. nullpo_retr(0, bl);
  5631. nullpo_retr(0, ap);
  5632. nullpo_retr(0, sd=(struct map_session_data*)bl);
  5633. nullpo_retr(0, src=va_arg(ap,struct block_list *));
  5634. nullpo_retr(0, c=va_arg(ap,int *));
  5635. nullpo_retr(0, ssd=(struct map_session_data*)src);
  5636. s_class = pc_calc_base_job(sd->status.class_);
  5637. //チェックしない設定ならcにありえない大きな?字を返して終了
  5638. if(!battle_config.player_skill_partner_check){ //本?はforeachの前にやりたいけど設定適用箇所をまとめるためにここへ
  5639. (*c)=99;
  5640. return 0;
  5641. }
  5642. ss_class = pc_calc_base_job(ssd->status.class_);
  5643. skillid=ssd->skillid;
  5644. skilllv=ssd->skilllv;
  5645. //if(skilllv <= 0) return 0;
  5646. if(skillid > 0 && skilllv <= 0) return 0; // celest
  5647. switch(skillid){
  5648. case PR_BENEDICTIO: /* 聖?降福 */
  5649. if(sd != ssd && (s_class.job == 4 || s_class.job == 8 || s_class.job == 15) &&
  5650. (sd->bl.x == ssd->bl.x - 1 || sd->bl.x == ssd->bl.x + 1) && sd->status.sp >= 10){
  5651. sd->status.sp -= 10;
  5652. status_calc_pc(sd,0);
  5653. (*c)++;
  5654. }
  5655. break;
  5656. case BD_LULLABY: /* 子守歌 */
  5657. case BD_RICHMANKIM: /* ニヨルドの宴 */
  5658. case BD_ETERNALCHAOS: /* 永遠の混沌 */
  5659. case BD_DRUMBATTLEFIELD: /* ?太鼓の響き */
  5660. case BD_RINGNIBELUNGEN: /* ニ?ベルングの指輪 */
  5661. case BD_ROKISWEIL: /* ロキの叫び */
  5662. case BD_INTOABYSS: /* 深淵の中に */
  5663. case BD_SIEGFRIED: /* 不死身のジ?クフリ?ド */
  5664. case BD_RAGNAROK: /* 神?の?昏 */
  5665. case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
  5666. if(sd != ssd && //本人以外で
  5667. ((ss_class.job==19 && s_class.job==20) || //自分がバ?ドならダンサ?で
  5668. (ss_class.job==20 && s_class.job==19)) && //自分がダンサ?ならバ?ドで
  5669. pc_checkskill(sd,skillid) > 0 && //スキルを持っていて
  5670. (*c)==0 && //最初の一人で
  5671. sd->status.party_id == ssd->status.party_id && //パ?ティ?が同じで
  5672. !pc_issit(sd) && //座ってない
  5673. sd->sc_data[SC_DANCING].timer==-1 //ダンス中じゃない
  5674. ){
  5675. ssd->sc_data[SC_DANCING].val4=bl->id;
  5676. clif_skill_nodamage(bl,src,skillid,skilllv,1);
  5677. status_change_start(bl,SC_DANCING,skillid,ssd->sc_data[SC_DANCING].val2,0,src->id,skill_get_time(skillid,skilllv)+1000,0);
  5678. sd->skillid_dance=sd->skillid=skillid;
  5679. sd->skilllv_dance=sd->skilllv=skilllv;
  5680. (*c)++;
  5681. }
  5682. break;
  5683. }
  5684. return 0;
  5685. }
  5686. /*==========================================
  5687. * 範??バイオプラント、スフィアマイン用Mob存在確認判定?理(foreachinarea)
  5688. *------------------------------------------
  5689. */
  5690. static int skill_check_condition_mob_master_sub(struct block_list *bl,va_list ap)
  5691. {
  5692. int *c,src_id=0,mob_class=0;
  5693. struct mob_data *md;
  5694. nullpo_retr(0, bl);
  5695. nullpo_retr(0, ap);
  5696. nullpo_retr(0, md=(struct mob_data*)bl);
  5697. nullpo_retr(0, src_id=va_arg(ap,int));
  5698. nullpo_retr(0, mob_class=va_arg(ap,int));
  5699. nullpo_retr(0, c=va_arg(ap,int *));
  5700. if(md->class_==mob_class && md->master_id==src_id)
  5701. (*c)++;
  5702. return 0;
  5703. }
  5704. /*==========================================
  5705. * スキル使用?件(?で使用失敗)
  5706. *------------------------------------------
  5707. */
  5708. int skill_check_condition(struct map_session_data *sd,int type)
  5709. {
  5710. int i,hp,sp,hp_rate,sp_rate,zeny,weapon,state,spiritball,skill,lv,mhp;
  5711. int index[10],itemid[10],amount[10];
  5712. int arrow_flag = 0;
  5713. nullpo_retr(0, sd);
  5714. if( battle_config.gm_skilluncond>0 && pc_isGM(sd)>= battle_config.gm_skilluncond ) {
  5715. sd->skillitem = sd->skillitemlv = -1;
  5716. return 1;
  5717. }
  5718. if( sd->opt1>0) {
  5719. clif_skill_fail(sd,sd->skillid,0,0);
  5720. sd->skillitem = sd->skillitemlv = -1;
  5721. return 0;
  5722. }
  5723. if(pc_is90overweight(sd)) {
  5724. clif_skill_fail(sd,sd->skillid,9,0);
  5725. sd->skillitem = sd->skillitemlv = -1;
  5726. return 0;
  5727. }
  5728. if(sd->skillid == AC_MAKINGARROW && sd->state.make_arrow_flag == 1) {
  5729. sd->skillitem = sd->skillitemlv = -1;
  5730. return 0;
  5731. }
  5732. if((sd->skillid == AM_PHARMACY || sd->skillid == ASC_CDP)
  5733. && sd->state.produce_flag == 1) {
  5734. sd->skillitem = sd->skillitemlv = -1;
  5735. return 0;
  5736. }
  5737. if(sd->skillitem == sd->skillid) { /* アイテムの場合無?件成功 */
  5738. if(type&1)
  5739. sd->skillitem = sd->skillitemlv = -1;
  5740. return 1;
  5741. }
  5742. if( sd->opt1>0 ){
  5743. clif_skill_fail(sd,sd->skillid,0,0);
  5744. return 0;
  5745. }
  5746. if(sd->sc_count){
  5747. if( sd->sc_data[SC_DIVINA].timer!=-1 ||
  5748. sd->sc_data[SC_ROKISWEIL].timer!=-1 ||
  5749. (sd->sc_data[SC_AUTOCOUNTER].timer != -1 && sd->skillid != KN_AUTOCOUNTER) ||
  5750. sd->sc_data[SC_STEELBODY].timer != -1 ||
  5751. sd->sc_data[SC_BERSERK].timer != -1 ||
  5752. (sd->sc_data[SC_MARIONETTE].timer != -1 && sd->skillid != CG_MARIONETTE)){
  5753. clif_skill_fail(sd,sd->skillid,0,0);
  5754. return 0; /* ?態異常や沈?など */
  5755. }
  5756. }
  5757. skill = sd->skillid;
  5758. lv = sd->skilllv;
  5759. if(lv <= 0) return 0;
  5760. // for the guild skills [celest]
  5761. if (skill >= 10000 && skill < 10015) skill-= 9500;
  5762. hp=skill_get_hp(skill, lv); /* 消費HP */
  5763. sp=skill_get_sp(skill, lv); /* 消費SP */
  5764. if((sd->skillid_old == BD_ENCORE) && skill==sd->skillid_dance)
  5765. sp=sp/2; //アンコ?ル時はSP消費が半分
  5766. hp_rate = (lv <= 0)? 0:skill_db[skill].hp_rate[lv-1];
  5767. sp_rate = (lv <= 0)? 0:skill_db[skill].sp_rate[lv-1];
  5768. zeny = skill_get_zeny(skill,lv);
  5769. weapon = skill_db[skill].weapon;
  5770. state = skill_db[skill].state;
  5771. spiritball = (lv <= 0)? 0:skill_db[skill].spiritball[lv-1];
  5772. mhp=skill_get_mhp(skill, lv); /* 消費HP */
  5773. for(i=0;i<10;i++) {
  5774. itemid[i] = skill_db[skill].itemid[i];
  5775. amount[i] = skill_db[skill].amount[i];
  5776. }
  5777. if(mhp > 0)
  5778. hp += (sd->status.max_hp * mhp)/100;
  5779. if(hp_rate > 0)
  5780. hp += (sd->status.hp * hp_rate)/100;
  5781. else
  5782. hp += (sd->status.max_hp * abs(hp_rate))/100;
  5783. if(sp_rate > 0)
  5784. sp += (sd->status.sp * sp_rate)/100;
  5785. else
  5786. sp += (sd->status.max_sp * abs(sp_rate))/100;
  5787. if(sd->dsprate!=100)
  5788. sp=sp*sd->dsprate/100; /* 消費SP修正 */
  5789. switch(skill) {
  5790. case SA_CASTCANCEL:
  5791. if(sd->skilltimer == -1) {
  5792. clif_skill_fail(sd,skill,0,0);
  5793. return 0;
  5794. }
  5795. break;
  5796. case BS_MAXIMIZE: /* マキシマイズパワ? */
  5797. case NV_TRICKDEAD: /* 死んだふり */
  5798. case TF_HIDING: /* ハイディング */
  5799. case AS_CLOAKING: /* クロ?キング */
  5800. case CR_AUTOGUARD: /* オ?トガ?ド */
  5801. case CR_DEFENDER: /* ディフェンダ? */
  5802. case ST_CHASEWALK:
  5803. if(sd->sc_data[SkillStatusChangeTable[skill]].timer!=-1)
  5804. return 1; /* 解除する場合はSP消費しない */
  5805. break;
  5806. case AL_TELEPORT:
  5807. case AL_WARP:
  5808. if(map[sd->bl.m].flag.noteleport) {
  5809. clif_skill_teleportmessage(sd,0);
  5810. return 0;
  5811. }
  5812. break;
  5813. case MO_CALLSPIRITS: /* ?功 */
  5814. if(sd->spiritball >= lv) {
  5815. clif_skill_fail(sd,skill,0,0);
  5816. return 0;
  5817. }
  5818. break;
  5819. case CH_SOULCOLLECT: /* 狂?功 */
  5820. if(sd->spiritball >= 5) {
  5821. clif_skill_fail(sd,skill,0,0);
  5822. return 0;
  5823. }
  5824. break;
  5825. case MO_FINGEROFFENSIVE: //指?
  5826. if (sd->spiritball > 0 && sd->spiritball < spiritball) {
  5827. spiritball = sd->spiritball;
  5828. sd->spiritball_old = sd->spiritball;
  5829. }
  5830. else sd->spiritball_old = lv;
  5831. break;
  5832. case MO_BODYRELOCATION:
  5833. if (sd->sc_count && sd->sc_data[SC_EXPLOSIONSPIRITS].timer!=-1)
  5834. spiritball = 0;
  5835. break;
  5836. case MO_CHAINCOMBO: //連打掌
  5837. if(sd->sc_data[SC_BLADESTOP].timer==-1){
  5838. if(sd->sc_data[SC_COMBO].timer == -1 || sd->sc_data[SC_COMBO].val1 != MO_TRIPLEATTACK)
  5839. return 0;
  5840. }
  5841. break;
  5842. case MO_COMBOFINISH: //猛龍拳
  5843. if(sd->sc_data[SC_COMBO].timer == -1 || sd->sc_data[SC_COMBO].val1 != MO_CHAINCOMBO)
  5844. return 0;
  5845. break;
  5846. case CH_TIGERFIST: //伏虎拳
  5847. if((sd->sc_data[SC_COMBO].timer == -1 || sd->sc_data[SC_COMBO].val1 != MO_COMBOFINISH) && !sd->state.skill_flag)
  5848. return 0;
  5849. break;
  5850. case CH_CHAINCRUSH: //連柱崩?
  5851. if(sd->sc_data[SC_COMBO].timer == -1)
  5852. return 0;
  5853. if(sd->sc_data[SC_COMBO].val1 != MO_COMBOFINISH && sd->sc_data[SC_COMBO].val1 != CH_TIGERFIST)
  5854. return 0;
  5855. break;
  5856. case MO_EXTREMITYFIST: // 阿修羅覇鳳拳
  5857. if((sd->sc_data[SC_COMBO].timer != -1 && (sd->sc_data[SC_COMBO].val1 == MO_COMBOFINISH || sd->sc_data[SC_COMBO].val1 == CH_CHAINCRUSH)) || sd->sc_data[SC_BLADESTOP].timer!=-1)
  5858. spiritball--;
  5859. break;
  5860. case BD_ADAPTATION: /* アドリブ */
  5861. {
  5862. struct skill_unit_group *group=NULL;
  5863. if(sd->sc_data[SC_DANCING].timer==-1 || ((group=(struct skill_unit_group*)sd->sc_data[SC_DANCING].val2) && (skill_get_time(sd->sc_data[SC_DANCING].val1,group->skill_lv) - sd->sc_data[SC_DANCING].val3*1000) <= skill_get_time2(skill,lv))){ //ダンス中で使用後5秒以上のみ?
  5864. clif_skill_fail(sd,skill,0,0);
  5865. return 0;
  5866. }
  5867. }
  5868. break;
  5869. case PR_BENEDICTIO: /* 聖?降福 */
  5870. {
  5871. int range=1;
  5872. int c=0;
  5873. if(!(type&1)){
  5874. map_foreachinarea(skill_check_condition_char_sub,sd->bl.m,
  5875. sd->bl.x-range,sd->bl.y-range,
  5876. sd->bl.x+range,sd->bl.y+range,BL_PC,&sd->bl,&c);
  5877. if(c<2){
  5878. clif_skill_fail(sd,skill,0,0);
  5879. return 0;
  5880. }
  5881. }else{
  5882. map_foreachinarea(skill_check_condition_use_sub,sd->bl.m,
  5883. sd->bl.x-range,sd->bl.y-range,
  5884. sd->bl.x+range,sd->bl.y+range,BL_PC,&sd->bl,&c);
  5885. }
  5886. }
  5887. break;
  5888. case WE_CALLPARTNER: /* あなたに逢いたい */
  5889. if(!sd->status.partner_id){
  5890. clif_skill_fail(sd,skill,0,0);
  5891. return 0;
  5892. }
  5893. break;
  5894. case AM_CANNIBALIZE: /* バイオプラント */
  5895. case AM_SPHEREMINE: /* スフィア?マイン */
  5896. if(type&1){
  5897. int c=0;
  5898. int summons[5] = { 1020, 1068, 1118, 1500, 1368 };
  5899. int maxcount = (skill==AM_CANNIBALIZE)? 6-lv : skill_get_maxcount(skill);
  5900. int mob_class = (skill==AM_CANNIBALIZE)? summons[lv-1] :1142;
  5901. if(battle_config.pc_land_skill_limit && maxcount>0) {
  5902. map_foreachinarea(skill_check_condition_mob_master_sub ,sd->bl.m, 0, 0, map[sd->bl.m].xs, map[sd->bl.m].ys, BL_MOB, sd->bl.id, mob_class,&c );
  5903. if(c >= maxcount){
  5904. clif_skill_fail(sd,skill,0,0);
  5905. return 0;
  5906. }
  5907. }
  5908. }
  5909. break;
  5910. case MG_FIREWALL: /* ファイア?ウォ?ル */
  5911. case WZ_QUAGMIRE:
  5912. case WZ_FIREPILLAR: // celest
  5913. case PF_FOGWALL:
  5914. /* ?制限 */
  5915. if(battle_config.pc_land_skill_limit) {
  5916. int maxcount = skill_get_maxcount(skill);
  5917. if(maxcount > 0) {
  5918. int i,c;
  5919. for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
  5920. if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == skill)
  5921. c++;
  5922. }
  5923. if(c >= maxcount) {
  5924. clif_skill_fail(sd,skill,0,0);
  5925. return 0;
  5926. }
  5927. }
  5928. }
  5929. break;
  5930. // skills require arrows as of 12/07 [celest]
  5931. case AC_DOUBLE:
  5932. case AC_SHOWER:
  5933. case AC_CHARGEARROW:
  5934. case BA_MUSICALSTRIKE:
  5935. case DC_THROWARROW:
  5936. case SN_SHARPSHOOTING:
  5937. case CG_ARROWVULCAN:
  5938. if(sd->equip_index[10] < 0) {
  5939. clif_arrow_fail(sd,0);
  5940. return 0;
  5941. }
  5942. arrow_flag = 1;
  5943. break;
  5944. case RG_BACKSTAP:
  5945. if(sd->status.weapon == 11) {
  5946. if (sd->equip_index[10] < 0) {
  5947. clif_arrow_fail(sd,0);
  5948. return 0;
  5949. }
  5950. arrow_flag = 1;
  5951. }
  5952. break;
  5953. }
  5954. if(!(type&2)){
  5955. if( hp>0 && sd->status.hp < hp) { /* HPチェック */
  5956. clif_skill_fail(sd,skill,2,0); /* HP不足:失敗通知 */
  5957. return 0;
  5958. }
  5959. if( sp>0 && sd->status.sp < sp) { /* SPチェック */
  5960. clif_skill_fail(sd,skill,1,0); /* SP不足:失敗通知 */
  5961. return 0;
  5962. }
  5963. if( zeny>0 && sd->status.zeny < zeny) {
  5964. clif_skill_fail(sd,skill,5,0);
  5965. return 0;
  5966. }
  5967. if(!(weapon & (1<<sd->status.weapon) ) ) {
  5968. clif_skill_fail(sd,skill,6,0);
  5969. return 0;
  5970. }
  5971. if( spiritball > 0 && sd->spiritball < spiritball) {
  5972. clif_skill_fail(sd,skill,0,0); // 氣球不足
  5973. return 0;
  5974. }
  5975. }
  5976. switch(state) {
  5977. case ST_HIDING:
  5978. if(!(sd->status.option&2)) {
  5979. clif_skill_fail(sd,skill,0,0);
  5980. return 0;
  5981. }
  5982. break;
  5983. case ST_CLOAKING:
  5984. if(!(sd->status.option&4)) {
  5985. clif_skill_fail(sd,skill,0,0);
  5986. return 0;
  5987. }
  5988. break;
  5989. case ST_HIDDEN:
  5990. if(!pc_ishiding(sd)) {
  5991. clif_skill_fail(sd,skill,0,0);
  5992. return 0;
  5993. }
  5994. break;
  5995. case ST_RIDING:
  5996. if(!pc_isriding(sd)) {
  5997. clif_skill_fail(sd,skill,0,0);
  5998. return 0;
  5999. }
  6000. break;
  6001. case ST_FALCON:
  6002. if(!pc_isfalcon(sd)) {
  6003. clif_skill_fail(sd,skill,0,0);
  6004. return 0;
  6005. }
  6006. break;
  6007. case ST_CART:
  6008. if(!pc_iscarton(sd)) {
  6009. clif_skill_fail(sd,skill,0,0);
  6010. return 0;
  6011. }
  6012. break;
  6013. case ST_SHIELD:
  6014. if(sd->status.shield <= 0) {
  6015. clif_skill_fail(sd,skill,0,0);
  6016. return 0;
  6017. }
  6018. break;
  6019. case ST_SIGHT:
  6020. if(sd->sc_data[SC_SIGHT].timer == -1 && type&1) {
  6021. clif_skill_fail(sd,skill,0,0);
  6022. return 0;
  6023. }
  6024. break;
  6025. case ST_EXPLOSIONSPIRITS:
  6026. if (skill == MO_EXTREMITYFIST && ((sd->sc_data[SC_COMBO].timer != -1 && (sd->sc_data[SC_COMBO].val1 == MO_COMBOFINISH || sd->sc_data[SC_COMBO].val1 == CH_CHAINCRUSH)) || sd->sc_data[SC_BLADESTOP].timer!=-1)) {
  6027. break;
  6028. }
  6029. if(sd->sc_data[SC_EXPLOSIONSPIRITS].timer == -1) {
  6030. clif_skill_fail(sd,skill,0,0);
  6031. return 0;
  6032. }
  6033. break;
  6034. case ST_RECOV_WEIGHT_RATE:
  6035. if(battle_config.natural_heal_weight_rate <= 100 && sd->weight*100/sd->max_weight >= battle_config.natural_heal_weight_rate) {
  6036. clif_skill_fail(sd,skill,0,0);
  6037. return 0;
  6038. }
  6039. break;
  6040. case ST_MOVE_ENABLE:
  6041. {
  6042. struct walkpath_data wpd;
  6043. if(path_search(&wpd,sd->bl.m,sd->bl.x,sd->bl.y,sd->skillx,sd->skilly,1)==-1) {
  6044. clif_skill_fail(sd,skill,0,0);
  6045. return 0;
  6046. }
  6047. }
  6048. break;
  6049. case ST_WATER:
  6050. if((!map_getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKWATER))&& (sd->sc_data[SC_DELUGE].timer==-1)){ //水場判定
  6051. clif_skill_fail(sd,skill,0,0);
  6052. return 0;
  6053. }
  6054. break;
  6055. }
  6056. for(i=0;i<10;i++) {
  6057. int x = lv%11 - 1;
  6058. index[i] = -1;
  6059. if(itemid[i] <= 0)
  6060. continue;
  6061. if(itemid[i] >= 715 && itemid[i] <= 717 && sd->special_state.no_gemstone)
  6062. continue;
  6063. if(((itemid[i] >= 715 && itemid[i] <= 717) || itemid[i] == 1065) && sd->sc_data[SC_INTOABYSS].timer != -1)
  6064. continue;
  6065. if(skill == WZ_FIREPILLAR && lv<=5)
  6066. continue; // no gemstones for 1-5 [Celest]
  6067. if((skill == AM_POTIONPITCHER ||
  6068. skill == CR_SLIMPITCHER) && i != x)
  6069. continue;
  6070. index[i] = pc_search_inventory(sd,itemid[i]);
  6071. if(index[i] < 0 || sd->status.inventory[index[i]].amount < amount[i]) {
  6072. if(itemid[i] == 716 || itemid[i] == 717)
  6073. clif_skill_fail(sd,skill,(7+(itemid[i]-716)),0);
  6074. else
  6075. clif_skill_fail(sd,skill,0,0);
  6076. return 0;
  6077. }
  6078. }
  6079. if(!(type&1))
  6080. return 1;
  6081. if(skill != AM_POTIONPITCHER &&
  6082. skill != CR_SLIMPITCHER &&
  6083. skill != MG_STONECURSE) {
  6084. if(skill == AL_WARP && !(type&2))
  6085. return 1;
  6086. for(i=0;i<10;i++) {
  6087. if(index[i] >= 0)
  6088. pc_delitem(sd,index[i],amount[i],0); // アイテム消費
  6089. }
  6090. if (arrow_flag && battle_config.arrow_decrement)
  6091. pc_delitem(sd,sd->equip_index[10],1,0);
  6092. }
  6093. if(type&2)
  6094. return 1;
  6095. if(sp > 0) { // SP消費
  6096. sd->status.sp-=sp;
  6097. clif_updatestatus(sd,SP_SP);
  6098. }
  6099. if(hp > 0) { // HP消費
  6100. sd->status.hp-=hp;
  6101. clif_updatestatus(sd,SP_HP);
  6102. }
  6103. if(zeny > 0) // Zeny消費
  6104. pc_payzeny(sd,zeny);
  6105. if(spiritball > 0) // 氣球消費
  6106. pc_delspiritball(sd,spiritball,0);
  6107. return 1;
  6108. }
  6109. /*==========================================
  6110. * 詠唱時間計算
  6111. *------------------------------------------
  6112. */
  6113. int skill_castfix( struct block_list *bl, int time )
  6114. {
  6115. struct map_session_data *sd = NULL;
  6116. struct mob_data *md; // [Valaris]
  6117. struct status_change *sc_data;
  6118. int castrate=100;
  6119. int skill,lv;
  6120. nullpo_retr(0, bl);
  6121. if(bl->type==BL_MOB){ // Crash fix [Valaris]
  6122. nullpo_retr(0, md=(struct mob_data*)bl);
  6123. skill = md->skillid;
  6124. lv = md->skilllv;
  6125. } else {
  6126. nullpo_retr(0, sd=(struct map_session_data*)bl);
  6127. skill = sd->skillid;
  6128. lv = sd->skilllv;
  6129. }
  6130. if(lv <= 0) return 0;
  6131. sc_data = status_get_sc_data(bl);
  6132. if (skill > MAX_SKILL_DB || skill < 0)
  6133. return 0;
  6134. /* サフラギウム */
  6135. if(sc_data && sc_data[SC_SUFFRAGIUM].timer!=-1 )
  6136. time=time*(100-sc_data[SC_SUFFRAGIUM].val1*15)/100;
  6137. status_change_end( bl, SC_SUFFRAGIUM, -1);
  6138. if(time==0)
  6139. return 0;
  6140. if (sd) {
  6141. if(!skill_get_castnodex(skill, lv) > 0) {
  6142. castrate=((struct map_session_data *)bl)->castrate;
  6143. time=time*castrate*(battle_config.castrate_dex_scale - status_get_dex(bl))/(battle_config.castrate_dex_scale * 100);
  6144. time=time*battle_config.cast_rate/100;
  6145. }
  6146. }
  6147. /* ブラギの詩 */
  6148. if(sc_data && sc_data[SC_POEMBRAGI].timer!=-1)
  6149. time=time*(100-(sc_data[SC_POEMBRAGI].val1*3+sc_data[SC_POEMBRAGI].val2
  6150. +(sc_data[SC_POEMBRAGI].val3>>16)))/100;
  6151. return (time>0)?time:0;
  6152. }
  6153. /*==========================================
  6154. * ディレイ計算
  6155. *------------------------------------------
  6156. */
  6157. int skill_delayfix( struct block_list *bl, int time )
  6158. {
  6159. struct status_change *sc_data;
  6160. struct map_session_data *sd = NULL;
  6161. int skill = 0,lv = 0;
  6162. int delayrate = 100;
  6163. nullpo_retr(0, bl);
  6164. if(bl->type == BL_PC){
  6165. nullpo_retr(0, sd = (struct map_session_data*)bl);
  6166. skill = sd->skillid;
  6167. lv = sd->skilllv;
  6168. }
  6169. if(lv <= 0) return 0;
  6170. sc_data = status_get_sc_data(bl);
  6171. if(sd) {
  6172. delayrate=((struct map_session_data *)bl)->delayrate;
  6173. // instant cast attack skills depend on aspd as delay [celest]
  6174. if (time == 0) {
  6175. if (skill_db[skill].skill_type == BF_WEAPON)
  6176. time = status_get_adelay (bl)/2;
  6177. else
  6178. time = 300; // default delay, according to official servers
  6179. } else if (time < 0)
  6180. time = abs(time) + status_get_adelay (bl)/2; // if set to <0, the aspd delay will be added
  6181. if(battle_config.delay_dependon_dex && /* dexの影響を計算する */
  6182. !skill_get_delaynodex(skill, lv)) // if skill casttime is allowed to be reduced by dex
  6183. time = time * (battle_config.castrate_dex_scale - status_get_dex(bl)) / (battle_config.castrate_dex_scale);
  6184. time = time * delayrate * battle_config.delay_rate / 10000;
  6185. if (time < battle_config.min_skill_delay_limit) // check minimum skill delay
  6186. time = battle_config.min_skill_delay_limit;
  6187. }
  6188. /* ブラギの詩 */
  6189. if(sc_data && sc_data[SC_POEMBRAGI].timer != -1 )
  6190. time = time * (100 - (sc_data[SC_POEMBRAGI].val1 * 3 + sc_data[SC_POEMBRAGI].val2
  6191. + (sc_data[SC_POEMBRAGI].val3 & 0xffff))) / 100;
  6192. return (time>0)?time:0;
  6193. }
  6194. /*==========================================
  6195. * スキル使用(ID指定)
  6196. *------------------------------------------
  6197. */
  6198. int skill_use_id( struct map_session_data *sd, int target_id,
  6199. int skill_num, int skill_lv)
  6200. {
  6201. unsigned int tick;
  6202. int casttime=0,delay=0,skill,range;
  6203. struct map_session_data* target_sd=NULL;
  6204. int forcecast=0;
  6205. struct block_list *bl;
  6206. struct status_change *sc_data;
  6207. tick=gettick();
  6208. nullpo_retr(0, sd);
  6209. if( (bl=map_id2bl(target_id)) == NULL ){
  6210. /* if(battle_config.error_log)
  6211. printf("skill target not found %d\n",target_id); */
  6212. return 0;
  6213. }
  6214. if(sd->bl.m != bl->m || pc_isdead(sd))
  6215. return 0;
  6216. if(skillnotok(skill_num, sd)) // [MouseJstr]
  6217. return 0;
  6218. sc_data=sd->sc_data;
  6219. /* 沈?や異常(ただし、グリムなどの判定をする) */
  6220. if( sd->opt1>0 )
  6221. return 0;
  6222. if(sc_data){
  6223. // allow to use only Chasewalk [celest]
  6224. if(sc_data[SC_CHASEWALK].timer != -1 && skill_num != ST_CHASEWALK)
  6225. return 0;
  6226. if(sc_data[SC_VOLCANO].timer != -1){
  6227. if(skill_num==WZ_ICEWALL) return 0;
  6228. }
  6229. if(sc_data[SC_ROKISWEIL].timer!=-1){
  6230. if(skill_num==BD_ADAPTATION) return 0;
  6231. }
  6232. if(sc_data[SC_DIVINA].timer!=-1 ||
  6233. sc_data[SC_ROKISWEIL].timer!=-1 ||
  6234. (sc_data[SC_AUTOCOUNTER].timer != -1 && sd->skillid != KN_AUTOCOUNTER) ||
  6235. sc_data[SC_STEELBODY].timer != -1 ||
  6236. sc_data[SC_BERSERK].timer != -1 ||
  6237. (sc_data[SC_MARIONETTE].timer != -1 && sd->skillid != CG_MARIONETTE)){
  6238. return 0; /* ?態異常や沈?など */
  6239. }
  6240. if(sc_data[SC_BLADESTOP].timer != -1){
  6241. int lv = sc_data[SC_BLADESTOP].val1;
  6242. if(sc_data[SC_BLADESTOP].val2==1) return 0;//白羽された側なのでダメ
  6243. if(lv==1) return 0;
  6244. if(lv==2 && skill_num!=MO_FINGEROFFENSIVE) return 0;
  6245. if(lv==3 && skill_num!=MO_FINGEROFFENSIVE && skill_num!=MO_INVESTIGATE) return 0;
  6246. if(lv==4 && skill_num!=MO_FINGEROFFENSIVE && skill_num!=MO_INVESTIGATE && skill_num!=MO_CHAINCOMBO) return 0;
  6247. if(lv==5 && skill_num!=MO_FINGEROFFENSIVE && skill_num!=MO_INVESTIGATE && skill_num!=MO_CHAINCOMBO && skill_num!=MO_EXTREMITYFIST) return 0;
  6248. }
  6249. if (sc_data[SC_BASILICA].timer != -1) { // Disallow all other skills in Basilica [celest]
  6250. struct skill_unit_group *sg = (struct skill_unit_group *)sc_data[SC_BASILICA].val4;
  6251. // if caster is the owner of basilica
  6252. if (sg && sg->src_id == sd->bl.id &&
  6253. skill_num == HP_BASILICA) ; // do nothing
  6254. // otherwise...
  6255. else return 0;
  6256. }
  6257. /* 演奏/ダンス中 */
  6258. if(sc_data[SC_DANCING].timer!=-1 ){
  6259. // if(battle_config.pc_skill_log)
  6260. // printf("dancing! %d\n",skill_num);
  6261. if( sc_data[SC_DANCING].val4 && skill_num!=BD_ADAPTATION ) //合奏中はアドリブ以外不可
  6262. return 0;
  6263. if(skill_num!=BD_ADAPTATION && skill_num!=BA_MUSICALSTRIKE && skill_num!=DC_THROWARROW){
  6264. return 0;
  6265. }
  6266. }
  6267. }
  6268. if(sd->status.option&4 && skill_num==TF_HIDING)
  6269. return 0;
  6270. if(sd->status.option&2 && skill_num!=TF_HIDING && skill_num!=AS_GRIMTOOTH && skill_num!=RG_BACKSTAP && skill_num!=RG_RAID )
  6271. return 0;
  6272. if(skill_get_inf2(skill_num)&0x200 && sd->bl.id == target_id)
  6273. return 0;
  6274. //直前のスキルが何か?える必要のあるスキル
  6275. switch(skill_num){
  6276. case SA_CASTCANCEL:
  6277. if(sd->skillid != skill_num){ //キャストキャンセル自?は?えない
  6278. sd->skillid_old = sd->skillid;
  6279. sd->skilllv_old = sd->skilllv;
  6280. break;
  6281. }
  6282. case BD_ENCORE: /* アンコ?ル */
  6283. if(!sd->skillid_dance){ //前回使用した踊りがないとだめ
  6284. clif_skill_fail(sd,skill_num,0,0);
  6285. return 0;
  6286. }else{
  6287. sd->skillid_old = skill_num;
  6288. }
  6289. break;
  6290. case GD_BATTLEORDER:
  6291. case GD_REGENERATION:
  6292. case GD_RESTORE:
  6293. case GD_EMERGENCYCALL:
  6294. {
  6295. struct guild *g;
  6296. if (!sd->status.guild_id)
  6297. return 0;
  6298. if ((g = guild_search(sd->status.guild_id)) == NULL)
  6299. return 0;
  6300. if (strcmp(sd->status.name,g->master))
  6301. return 0;
  6302. skill_lv = guild_checkskill(g, skill_num);
  6303. if (skill_lv <= 0) return 0;
  6304. }
  6305. break;
  6306. }
  6307. sd->skillid = skill_num;
  6308. sd->skilllv = skill_lv;
  6309. switch(skill_num){ //事前にレベルが?わったりするスキル
  6310. case BD_LULLABY: /* 子守歌 */
  6311. case BD_RICHMANKIM: /* ニヨルドの宴 */
  6312. case BD_ETERNALCHAOS: /* 永遠の混沌 */
  6313. case BD_DRUMBATTLEFIELD: /* ?太鼓の響き */
  6314. case BD_RINGNIBELUNGEN: /* ニ?ベルングの指輪 */
  6315. case BD_ROKISWEIL: /* ロキの叫び */
  6316. case BD_INTOABYSS: /* 深淵の中に */
  6317. case BD_SIEGFRIED: /* 不死身のジ?クフリ?ド */
  6318. case BD_RAGNAROK: /* 神?の?昏 */
  6319. case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
  6320. {
  6321. int range=1;
  6322. int c=0;
  6323. map_foreachinarea(skill_check_condition_char_sub,sd->bl.m,
  6324. sd->bl.x-range,sd->bl.y-range,
  6325. sd->bl.x+range,sd->bl.y+range,BL_PC,&sd->bl,&c);
  6326. if(c<1){
  6327. clif_skill_fail(sd,skill_num,0,0);
  6328. return 0;
  6329. }else if(c==99){ //相方不要設定だった
  6330. ;
  6331. }else{
  6332. sd->skilllv=(c + skill_lv)/2;
  6333. }
  6334. }
  6335. break;
  6336. }
  6337. if(!skill_check_condition(sd,0)) return 0;
  6338. {
  6339. int check_range_flag = 0;
  6340. /* 射程と障害物チェック */
  6341. range = skill_get_range(skill_num,skill_lv);
  6342. if(range < 0)
  6343. range = status_get_range(&sd->bl) - (range + 1);
  6344. // be lenient if the skill was cast before we have moved to the correct position [Celest]
  6345. if (sd->walktimer != -1)
  6346. range += battle_config.skill_range_leniency;
  6347. else check_range_flag = 1;
  6348. if(!battle_check_range(&sd->bl,bl,range)) {
  6349. if (check_range_flag && battle_check_range(&sd->bl,bl,range + battle_config.skill_range_leniency)) {
  6350. int dir, mask[8][2] = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};
  6351. dir = map_calc_dir(&sd->bl,bl->x,bl->y);
  6352. pc_walktoxy (sd, sd->bl.x + mask[dir][0] * battle_config.skill_range_leniency,
  6353. sd->bl.y + mask[dir][1] * battle_config.skill_range_leniency);
  6354. } else
  6355. return 0;
  6356. }
  6357. }
  6358. if(bl->type==BL_PC) {
  6359. target_sd=(struct map_session_data*)bl;
  6360. if(target_sd && skill_num == ALL_RESURRECTION && !pc_isdead(target_sd))
  6361. return 0;
  6362. }
  6363. if((skill_num != MO_CHAINCOMBO &&
  6364. skill_num != MO_COMBOFINISH &&
  6365. skill_num != MO_EXTREMITYFIST &&
  6366. skill_num != CH_TIGERFIST &&
  6367. skill_num != CH_CHAINCRUSH) ||
  6368. (skill_num == CH_CHAINCRUSH && sd->state.skill_flag) ||
  6369. (skill_num == MO_EXTREMITYFIST && sd->state.skill_flag) )
  6370. pc_stopattack(sd);
  6371. casttime=skill_castfix(&sd->bl, skill_get_cast( skill_num,skill_lv) );
  6372. if(skill_num != SA_MAGICROD)
  6373. delay=skill_delayfix(&sd->bl, skill_get_delay( skill_num,skill_lv) );
  6374. //sd->state.skillcastcancel = skill_db[skill_num].castcancel;
  6375. sd->state.skillcastcancel = skill_get_castcancel(skill_num);
  6376. switch(skill_num){ /* 何か特殊な?理が必要 */
  6377. // case AL_HEAL: /* ヒ?ル */
  6378. // if(battle_check_undead(status_get_race(bl),status_get_elem_type(bl)))
  6379. // forcecast=1; /* ヒ?ルアタックなら詠唱エフェクト有り */
  6380. // break;
  6381. case ALL_RESURRECTION: /* リザレクション */
  6382. if(bl->type != BL_PC && battle_check_undead(status_get_race(bl),status_get_elem_type(bl))){ /* 敵がアンデッドなら */
  6383. forcecast=1; /* タ?ンアンデットと同じ詠唱時間 */
  6384. casttime=skill_castfix(&sd->bl, skill_get_cast(PR_TURNUNDEAD,skill_lv) );
  6385. }
  6386. break;
  6387. case MO_FINGEROFFENSIVE: /* 指? */
  6388. casttime += casttime * ((skill_lv > sd->spiritball)? sd->spiritball:skill_lv);
  6389. break;
  6390. case MO_CHAINCOMBO: /*連打掌*/
  6391. target_id = sd->attacktarget;
  6392. if( sc_data && sc_data[SC_BLADESTOP].timer!=-1 ){
  6393. struct block_list *tbl;
  6394. if((tbl=(struct block_list *)sc_data[SC_BLADESTOP].val4) == NULL) //タ?ゲットがいない?
  6395. return 0;
  6396. target_id = tbl->id;
  6397. }
  6398. break;
  6399. case MO_COMBOFINISH: /*猛龍拳*/
  6400. // case CH_TIGERFIST: /* 伏虎拳 */
  6401. case CH_CHAINCRUSH: /* 連柱崩? */
  6402. target_id = sd->attacktarget;
  6403. break;
  6404. case CH_TIGERFIST: /* 伏虎拳 */
  6405. if(sc_data && sc_data[SC_COMBO].timer != -1 && sc_data[SC_COMBO].val1 == MO_COMBOFINISH)
  6406. target_id = sd->attacktarget;
  6407. break;
  6408. // -- moonsoul (altered to allow proper usage of extremity from new champion combos)
  6409. //
  6410. case MO_EXTREMITYFIST: /*阿修羅覇鳳拳*/
  6411. if(sc_data && sc_data[SC_COMBO].timer != -1 && (sc_data[SC_COMBO].val1 == MO_COMBOFINISH || sc_data[SC_COMBO].val1 == CH_CHAINCRUSH)) {
  6412. casttime = 0;
  6413. target_id = sd->attacktarget;
  6414. }
  6415. forcecast=1;
  6416. break;
  6417. case SA_MAGICROD:
  6418. case SA_SPELLBREAKER:
  6419. forcecast=1;
  6420. break;
  6421. case WE_MALE:
  6422. case WE_FEMALE:
  6423. {
  6424. struct map_session_data *p_sd = pc_get_partner(sd);
  6425. if (p_sd == NULL) // it's possible to get null if we're not married ^^;
  6426. return 0;
  6427. // nullpo_retr (0, p_sd)
  6428. if(skill_num == WE_MALE && sd->status.hp <= ((15*sd->status.max_hp)/100)) // Requires more than 15% of Max HP for WE_MALE
  6429. return 0;
  6430. else if(skill_num == WE_FEMALE && sd->status.sp <= ((15*sd->status.max_sp)/100)) // Requires more than 15% of Max SP for WE_FEMALE
  6431. return 0;
  6432. target_id = p_sd->bl.id;
  6433. //rangeをもう1回?査
  6434. range = skill_get_range(skill_num,skill_lv);
  6435. if(range < 0)
  6436. range = status_get_range(&sd->bl) - (range + 1);
  6437. if(!battle_check_range(&sd->bl,&p_sd->bl,range))
  6438. return 0;
  6439. }
  6440. break;
  6441. case PF_MEMORIZE: /* メモライズ */
  6442. casttime = 12000;
  6443. break;
  6444. case HW_MAGICPOWER:
  6445. casttime = 700;
  6446. break;
  6447. case HP_BASILICA: /* バジリカ */
  6448. {
  6449. if (skill_check_unit_range(sd->bl.m,sd->bl.x,sd->bl.y,sd->skillid,sd->skilllv)) {
  6450. clif_skill_fail(sd,sd->skillid,0,0);
  6451. return 0;
  6452. }
  6453. if (skill_check_unit_range2(sd->bl.m,sd->bl.x,sd->bl.y,sd->skillid,sd->skilllv)) {
  6454. clif_skill_fail(sd,sd->skillid,0,0);
  6455. return 0;
  6456. }
  6457. // cancel Basilica if already in effect
  6458. struct status_change *sc_data = status_get_sc_data(&sd->bl);
  6459. if(sc_data && sc_data[SC_BASILICA].timer != -1) {
  6460. struct skill_unit_group *sg = (struct skill_unit_group *)sc_data[SC_BASILICA].val4;
  6461. if (sg && sg->src_id == sd->bl.id) {
  6462. status_change_end(&sd->bl,SC_BASILICA,-1);
  6463. skill_delunitgroup (sg);
  6464. return 0;
  6465. }
  6466. }
  6467. }
  6468. break;
  6469. case GD_BATTLEORDER:
  6470. case GD_REGENERATION:
  6471. case GD_RESTORE:
  6472. case GD_EMERGENCYCALL:
  6473. casttime = 1000; // temporary [Celest]
  6474. break;
  6475. }
  6476. //メモライズ?態ならキャストタイムが1/3
  6477. if(sc_data && sc_data[SC_MEMORIZE].timer != -1 && casttime > 0){
  6478. casttime = casttime/2;
  6479. if((--sc_data[SC_MEMORIZE].val2)<=0)
  6480. status_change_end(&sd->bl, SC_MEMORIZE, -1);
  6481. }
  6482. if(battle_config.pc_skill_log)
  6483. printf("PC %d skill use target_id=%d skill=%d lv=%d cast=%d\n",sd->bl.id,target_id,skill_num,skill_lv,casttime);
  6484. // if(sd->skillitem == skill_num)
  6485. // casttime = delay = 0;
  6486. if( casttime>0 || forcecast ){ /* 詠唱が必要 */
  6487. struct mob_data *md;
  6488. clif_skillcasting( &sd->bl, sd->bl.id, target_id, 0,0, skill_num,casttime);
  6489. /* 詠唱反?モンスタ? */
  6490. if( bl->type==BL_MOB && (md=(struct mob_data *)bl) && mob_db[md->class_].mode&0x10 &&
  6491. md->state.state!=MS_ATTACK && sd->invincible_timer == -1){
  6492. md->target_id=sd->bl.id;
  6493. md->state.targettype = ATTACKABLE;
  6494. md->min_chase=13;
  6495. }
  6496. }
  6497. if( casttime<=0 ) /* 詠唱の無いものはキャンセルされない */
  6498. sd->state.skillcastcancel=0;
  6499. sd->skilltarget = target_id;
  6500. /* sd->cast_target_bl = bl; */
  6501. sd->skillx = 0;
  6502. sd->skilly = 0;
  6503. sd->canact_tick = tick + casttime + delay;
  6504. sd->canmove_tick = tick;
  6505. if(!(battle_config.pc_cloak_check_type&2) && sc_data && sc_data[SC_CLOAKING].timer != -1 && sd->skillid != AS_CLOAKING)
  6506. status_change_end(&sd->bl,SC_CLOAKING,-1);
  6507. if(casttime > 0) {
  6508. sd->skilltimer = add_timer( tick+casttime, skill_castend_id, sd->bl.id, 0 );
  6509. if((skill = pc_checkskill(sd,SA_FREECAST)) > 0) {
  6510. sd->prev_speed = sd->speed;
  6511. sd->speed = sd->speed*(175 - skill*5)/100;
  6512. clif_updatestatus(sd,SP_SPEED);
  6513. }
  6514. else
  6515. pc_stop_walking(sd,0);
  6516. }
  6517. else {
  6518. if(skill_num != SA_CASTCANCEL)
  6519. sd->skilltimer = -1;
  6520. skill_castend_id(sd->skilltimer,tick,sd->bl.id,0);
  6521. }
  6522. return 0;
  6523. }
  6524. /*==========================================
  6525. * スキル使用(場所指定)
  6526. *------------------------------------------
  6527. */
  6528. int skill_use_pos( struct map_session_data *sd,
  6529. int skill_x, int skill_y, int skill_num, int skill_lv)
  6530. {
  6531. struct block_list bl;
  6532. struct status_change *sc_data;
  6533. unsigned int tick;
  6534. int casttime=0,delay=0,skill,range;
  6535. nullpo_retr(0, sd);
  6536. if(pc_isdead(sd))
  6537. return 0;
  6538. if (skillnotok(skill_num, sd)) // [MoueJstr]
  6539. return 0;
  6540. if(skill_num==WZ_ICEWALL && map[sd->bl.m].flag.noicewall && !map[sd->bl.m].flag.pvp) { // noicewall flag [Valaris]
  6541. clif_skill_fail(sd,sd->skillid,0,0);
  6542. return 0;
  6543. }
  6544. sc_data=sd->sc_data;
  6545. if( sd->opt1>0 )
  6546. return 0;
  6547. if(sc_data){
  6548. if( sc_data[SC_DIVINA].timer!=-1 ||
  6549. sc_data[SC_ROKISWEIL].timer!=-1 ||
  6550. sc_data[SC_AUTOCOUNTER].timer != -1 ||
  6551. sc_data[SC_STEELBODY].timer != -1 ||
  6552. sc_data[SC_DANCING].timer!=-1 ||
  6553. sc_data[SC_BERSERK].timer != -1 ||
  6554. sc_data[SC_MARIONETTE].timer != -1)
  6555. return 0; /* ?態異常や沈?など */
  6556. if (sc_data[SC_BASILICA].timer != -1) {
  6557. struct skill_unit_group *sg = (struct skill_unit_group *)sc_data[SC_BASILICA].val4;
  6558. // if caster is the owner of basilica
  6559. if (sg && sg->src_id == sd->bl.id &&
  6560. skill_num == HP_BASILICA) ; // do nothing
  6561. // otherwise...
  6562. else return 0;
  6563. }
  6564. }
  6565. if(sd->status.option&2)
  6566. return 0;
  6567. sd->skillid = skill_num;
  6568. sd->skilllv = skill_lv;
  6569. if(skill_lv <= 0) return 0;
  6570. sd->skillx = skill_x;
  6571. sd->skilly = skill_y;
  6572. if(!skill_check_condition(sd,0)) return 0;
  6573. /* 射程と障害物チェック */
  6574. bl.type = BL_NUL;
  6575. bl.m = sd->bl.m;
  6576. bl.x = skill_x;
  6577. bl.y = skill_y;
  6578. {
  6579. int check_range_flag = 0;
  6580. /* 射程と障害物チェック */
  6581. range = skill_get_range(skill_num,skill_lv);
  6582. if(range < 0)
  6583. range = status_get_range(&sd->bl) - (range + 1);
  6584. // be lenient if the skill was cast before we have moved to the correct position [Celest]
  6585. if (sd->walktimer != -1)
  6586. range += battle_config.skill_range_leniency;
  6587. else check_range_flag = 1;
  6588. if(!battle_check_range(&sd->bl,&bl,range)) {
  6589. if (check_range_flag && battle_check_range(&sd->bl,&bl,range + battle_config.skill_range_leniency)) {
  6590. int dir, mask[8][2] = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};
  6591. dir = map_calc_dir(&sd->bl,bl.x,bl.y);
  6592. pc_walktoxy (sd, sd->bl.x + mask[dir][0] * battle_config.skill_range_leniency,
  6593. sd->bl.y + mask[dir][1] * battle_config.skill_range_leniency);
  6594. } else
  6595. return 0;
  6596. }
  6597. }
  6598. pc_stopattack(sd);
  6599. casttime=skill_castfix(&sd->bl, skill_get_cast( skill_num,skill_lv) );
  6600. delay=skill_delayfix(&sd->bl, skill_get_delay( skill_num,skill_lv) );
  6601. sd->state.skillcastcancel = skill_db[skill_num].castcancel;
  6602. if(battle_config.pc_skill_log)
  6603. printf("PC %d skill use target_pos=(%d,%d) skill=%d lv=%d cast=%d\n",sd->bl.id,skill_x,skill_y,skill_num,skill_lv,casttime);
  6604. // if(sd->skillitem == skill_num)
  6605. // casttime = delay = 0;
  6606. //メモライズ?態ならキャストタイムが1/3
  6607. if(sc_data && sc_data[SC_MEMORIZE].timer != -1 && casttime > 0){
  6608. casttime = casttime/3;
  6609. if((--sc_data[SC_MEMORIZE].val2)<=0)
  6610. status_change_end(&sd->bl, SC_MEMORIZE, -1);
  6611. }
  6612. if( casttime>0 ) /* 詠唱が必要 */
  6613. clif_skillcasting( &sd->bl,
  6614. sd->bl.id, 0, skill_x,skill_y, skill_num,casttime);
  6615. if( casttime<=0 ) /* 詠唱の無いものはキャンセルされない */
  6616. sd->state.skillcastcancel=0;
  6617. sd->skilltarget = 0;
  6618. /* sd->cast_target_bl = NULL; */
  6619. tick=gettick();
  6620. sd->canact_tick = tick + casttime + delay;
  6621. sd->canmove_tick = tick;
  6622. if(!(battle_config.pc_cloak_check_type&2) && sc_data && sc_data[SC_CLOAKING].timer != -1)
  6623. status_change_end(&sd->bl,SC_CLOAKING,-1);
  6624. if(casttime > 0) {
  6625. sd->skilltimer = add_timer( tick+casttime, skill_castend_pos, sd->bl.id, 0 );
  6626. if((skill = pc_checkskill(sd,SA_FREECAST)) > 0) {
  6627. sd->prev_speed = sd->speed;
  6628. sd->speed = sd->speed*(175 - skill*5)/100;
  6629. clif_updatestatus(sd,SP_SPEED);
  6630. }
  6631. else
  6632. pc_stop_walking(sd,0);
  6633. }
  6634. else {
  6635. sd->skilltimer = -1;
  6636. skill_castend_pos(sd->skilltimer,tick,sd->bl.id,0);
  6637. }
  6638. //マジックパワ?の?果終了
  6639. if(sc_data && sc_data[SC_MAGICPOWER].timer != -1 && skill_num != HW_MAGICPOWER)
  6640. status_change_end(&sd->bl,SC_MAGICPOWER,-1);
  6641. return 0;
  6642. }
  6643. /*==========================================
  6644. * スキル詠唱キャンセル
  6645. *------------------------------------------
  6646. */
  6647. int skill_castcancel(struct block_list *bl,int type)
  6648. {
  6649. int inf;
  6650. int ret=0;
  6651. nullpo_retr(0, bl);
  6652. if(bl->type==BL_PC){
  6653. struct map_session_data *sd=(struct map_session_data *)bl;
  6654. unsigned long tick=gettick();
  6655. nullpo_retr(0, sd);
  6656. sd->canact_tick=tick;
  6657. sd->canmove_tick = tick;
  6658. if( sd->skilltimer!=-1){
  6659. if(pc_checkskill(sd,SA_FREECAST) > 0) {
  6660. sd->speed = sd->prev_speed;
  6661. clif_updatestatus(sd,SP_SPEED);
  6662. }
  6663. if(!type) {
  6664. if((inf = skill_get_inf( sd->skillid )) == 2 || inf == 32)
  6665. ret=delete_timer( sd->skilltimer, skill_castend_pos );
  6666. else
  6667. ret=delete_timer( sd->skilltimer, skill_castend_id );
  6668. if(ret<0)
  6669. printf("delete timer error : skillid : %d\n",sd->skillid);
  6670. }
  6671. else {
  6672. if((inf = skill_get_inf( sd->skillid_old )) == 2 || inf == 32)
  6673. ret=delete_timer( sd->skilltimer, skill_castend_pos );
  6674. else
  6675. ret=delete_timer( sd->skilltimer, skill_castend_id );
  6676. if(ret<0)
  6677. printf("delete timer error : skillid : %d\n",sd->skillid_old);
  6678. }
  6679. sd->skilltimer=-1;
  6680. clif_skillcastcancel(bl);
  6681. }
  6682. return 0;
  6683. }else if(bl->type==BL_MOB){
  6684. struct mob_data *md=(struct mob_data *)bl;
  6685. nullpo_retr(0, md);
  6686. if( md->skilltimer!=-1 ){
  6687. if((inf = skill_get_inf( md->skillid )) == 2 || inf == 32)
  6688. ret=delete_timer( md->skilltimer, mobskill_castend_pos );
  6689. else
  6690. ret=delete_timer( md->skilltimer, mobskill_castend_id );
  6691. md->skilltimer=-1;
  6692. clif_skillcastcancel(bl);
  6693. }
  6694. if(ret<0)
  6695. printf("delete timer error : skillid : %d\n",md->skillid);
  6696. return 0;
  6697. }
  6698. return 1;
  6699. }
  6700. /*=========================================
  6701. * ブランディッシュスピア 初期範?決定
  6702. *----------------------------------------
  6703. */
  6704. void skill_brandishspear_first(struct square *tc,int dir,int x,int y){
  6705. nullpo_retv(tc);
  6706. if(dir == 0){
  6707. tc->val1[0]=x-2;
  6708. tc->val1[1]=x-1;
  6709. tc->val1[2]=x;
  6710. tc->val1[3]=x+1;
  6711. tc->val1[4]=x+2;
  6712. tc->val2[0]=
  6713. tc->val2[1]=
  6714. tc->val2[2]=
  6715. tc->val2[3]=
  6716. tc->val2[4]=y-1;
  6717. }
  6718. else if(dir==2){
  6719. tc->val1[0]=
  6720. tc->val1[1]=
  6721. tc->val1[2]=
  6722. tc->val1[3]=
  6723. tc->val1[4]=x+1;
  6724. tc->val2[0]=y+2;
  6725. tc->val2[1]=y+1;
  6726. tc->val2[2]=y;
  6727. tc->val2[3]=y-1;
  6728. tc->val2[4]=y-2;
  6729. }
  6730. else if(dir==4){
  6731. tc->val1[0]=x-2;
  6732. tc->val1[1]=x-1;
  6733. tc->val1[2]=x;
  6734. tc->val1[3]=x+1;
  6735. tc->val1[4]=x+2;
  6736. tc->val2[0]=
  6737. tc->val2[1]=
  6738. tc->val2[2]=
  6739. tc->val2[3]=
  6740. tc->val2[4]=y+1;
  6741. }
  6742. else if(dir==6){
  6743. tc->val1[0]=
  6744. tc->val1[1]=
  6745. tc->val1[2]=
  6746. tc->val1[3]=
  6747. tc->val1[4]=x-1;
  6748. tc->val2[0]=y+2;
  6749. tc->val2[1]=y+1;
  6750. tc->val2[2]=y;
  6751. tc->val2[3]=y-1;
  6752. tc->val2[4]=y-2;
  6753. }
  6754. else if(dir==1){
  6755. tc->val1[0]=x-1;
  6756. tc->val1[1]=x;
  6757. tc->val1[2]=x+1;
  6758. tc->val1[3]=x+2;
  6759. tc->val1[4]=x+3;
  6760. tc->val2[0]=y-4;
  6761. tc->val2[1]=y-3;
  6762. tc->val2[2]=y-1;
  6763. tc->val2[3]=y;
  6764. tc->val2[4]=y+1;
  6765. }
  6766. else if(dir==3){
  6767. tc->val1[0]=x+3;
  6768. tc->val1[1]=x+2;
  6769. tc->val1[2]=x+1;
  6770. tc->val1[3]=x;
  6771. tc->val1[4]=x-1;
  6772. tc->val2[0]=y-1;
  6773. tc->val2[1]=y;
  6774. tc->val2[2]=y+1;
  6775. tc->val2[3]=y+2;
  6776. tc->val2[4]=y+3;
  6777. }
  6778. else if(dir==5){
  6779. tc->val1[0]=x+1;
  6780. tc->val1[1]=x;
  6781. tc->val1[2]=x-1;
  6782. tc->val1[3]=x-2;
  6783. tc->val1[4]=x-3;
  6784. tc->val2[0]=y+3;
  6785. tc->val2[1]=y+2;
  6786. tc->val2[2]=y+1;
  6787. tc->val2[3]=y;
  6788. tc->val2[4]=y-1;
  6789. }
  6790. else if(dir==7){
  6791. tc->val1[0]=x-3;
  6792. tc->val1[1]=x-2;
  6793. tc->val1[2]=x-1;
  6794. tc->val1[3]=x;
  6795. tc->val1[4]=x+1;
  6796. tc->val2[1]=y;
  6797. tc->val2[0]=y+1;
  6798. tc->val2[2]=y-1;
  6799. tc->val2[3]=y-2;
  6800. tc->val2[4]=y-3;
  6801. }
  6802. }
  6803. /*=========================================
  6804. * ブランディッシュスピア 方向判定 範??張
  6805. *-----------------------------------------
  6806. */
  6807. void skill_brandishspear_dir(struct square *tc,int dir,int are){
  6808. int c;
  6809. nullpo_retv(tc);
  6810. for(c=0;c<5;c++){
  6811. if(dir==0){
  6812. tc->val2[c]+=are;
  6813. }else if(dir==1){
  6814. tc->val1[c]-=are; tc->val2[c]+=are;
  6815. }else if(dir==2){
  6816. tc->val1[c]-=are;
  6817. }else if(dir==3){
  6818. tc->val1[c]-=are; tc->val2[c]-=are;
  6819. }else if(dir==4){
  6820. tc->val2[c]-=are;
  6821. }else if(dir==5){
  6822. tc->val1[c]+=are; tc->val2[c]-=are;
  6823. }else if(dir==6){
  6824. tc->val1[c]+=are;
  6825. }else if(dir==7){
  6826. tc->val1[c]+=are; tc->val2[c]+=are;
  6827. }
  6828. }
  6829. }
  6830. /*==========================================
  6831. * ディボ?ション 有?確認
  6832. *------------------------------------------
  6833. */
  6834. void skill_devotion(struct map_session_data *md,int target)
  6835. {
  6836. // ?確認
  6837. int n;
  6838. nullpo_retv(md);
  6839. for(n=0;n<5;n++){
  6840. if(md->dev.val1[n]){
  6841. struct map_session_data *sd = map_id2sd(md->dev.val1[n]);
  6842. // 相手が見つからない // 相手をディボしてるのが自分じゃない // 距離が離れてる
  6843. if( sd == NULL || (sd->sc_data && (md->bl.id != sd->sc_data[SC_DEVOTION].val1)) || skill_devotion3(&md->bl,md->dev.val1[n])){
  6844. skill_devotion_end(md,sd,n);
  6845. }
  6846. }
  6847. }
  6848. }
  6849. void skill_devotion2(struct block_list *bl,int crusader)
  6850. {
  6851. // 被ディボ?ションが?いた時の距離チェック
  6852. struct map_session_data *sd = map_id2sd(crusader);
  6853. nullpo_retv(bl);
  6854. if(sd) skill_devotion3(&sd->bl,bl->id);
  6855. }
  6856. int skill_devotion3(struct block_list *bl,int target)
  6857. {
  6858. // クルセが?いた時の距離チェック
  6859. struct map_session_data *md;
  6860. struct map_session_data *sd;
  6861. int n,r=0;
  6862. nullpo_retr(1, bl);
  6863. md = (struct map_session_data *)bl;
  6864. if ((sd = map_id2sd(target))==NULL)
  6865. return 1;
  6866. else
  6867. r = distance(bl->x,bl->y,sd->bl.x,sd->bl.y);
  6868. if(pc_checkskill(md,CR_DEVOTION)+6 < r){ // 許容範?を超えてた
  6869. for(n=0;n<5;n++)
  6870. if(md->dev.val1[n]==target)
  6871. md->dev.val2[n]=0; // 離れた時は、?を切るだけ
  6872. clif_devotion(md,sd->bl.id);
  6873. return 1;
  6874. }
  6875. return 0;
  6876. }
  6877. void skill_devotion_end(struct map_session_data *md,struct map_session_data *sd,int target)
  6878. {
  6879. // クルセと被ディボキャラのリセット
  6880. nullpo_retv(md);
  6881. nullpo_retv(sd);
  6882. md->dev.val1[target]=md->dev.val2[target]=0;
  6883. if(sd && sd->sc_data){
  6884. // status_change_end(sd->bl,SC_DEVOTION,-1);
  6885. sd->sc_data[SC_DEVOTION].val1=0;
  6886. sd->sc_data[SC_DEVOTION].val2=0;
  6887. clif_status_change(&sd->bl,SC_DEVOTION,0);
  6888. clif_devotion(md,sd->bl.id);
  6889. }
  6890. }
  6891. /*==========================================
  6892. * オ?トスペル
  6893. *------------------------------------------
  6894. */
  6895. int skill_autospell(struct map_session_data *sd,int skillid)
  6896. {
  6897. int skilllv;
  6898. int maxlv=1,lv;
  6899. nullpo_retr(0, sd);
  6900. skilllv = pc_checkskill(sd,SA_AUTOSPELL);
  6901. if(skilllv <= 0) return 0;
  6902. if(skillid==MG_NAPALMBEAT) maxlv=3;
  6903. else if(skillid==MG_COLDBOLT || skillid==MG_FIREBOLT || skillid==MG_LIGHTNINGBOLT){
  6904. if(skilllv==2) maxlv=1;
  6905. else if(skilllv==3) maxlv=2;
  6906. else if(skilllv>=4) maxlv=3;
  6907. }
  6908. else if(skillid==MG_SOULSTRIKE){
  6909. if(skilllv==5) maxlv=1;
  6910. else if(skilllv==6) maxlv=2;
  6911. else if(skilllv>=7) maxlv=3;
  6912. }
  6913. else if(skillid==MG_FIREBALL){
  6914. if(skilllv==8) maxlv=1;
  6915. else if(skilllv>=9) maxlv=2;
  6916. }
  6917. else if(skillid==MG_FROSTDIVER) maxlv=1;
  6918. else return 0;
  6919. if(maxlv > (lv=pc_checkskill(sd,skillid)))
  6920. maxlv = lv;
  6921. status_change_start(&sd->bl,SC_AUTOSPELL,skilllv,skillid,maxlv,0, // val1:スキルID val2:使用最大Lv
  6922. skill_get_time(SA_AUTOSPELL,skilllv),0);// にしてみたけどbscriptが書き易い????
  6923. return 0;
  6924. }
  6925. /*==========================================
  6926. * ギャングスタ?パラダイス判定?理(foreachinarea)
  6927. *------------------------------------------
  6928. */
  6929. static int skill_gangster_count(struct block_list *bl,va_list ap)
  6930. {
  6931. int *c;
  6932. struct map_session_data *sd;
  6933. nullpo_retr(0, bl);
  6934. nullpo_retr(0, ap);
  6935. sd=(struct map_session_data*)bl;
  6936. c=va_arg(ap,int *);
  6937. if(sd && c && pc_issit(sd) && pc_checkskill(sd,RG_GANGSTER) > 0)
  6938. (*c)++;
  6939. return 0;
  6940. }
  6941. static int skill_gangster_in(struct block_list *bl,va_list ap)
  6942. {
  6943. struct map_session_data *sd;
  6944. nullpo_retr(0, bl);
  6945. nullpo_retr(0, ap);
  6946. sd=(struct map_session_data*)bl;
  6947. if(sd && pc_issit(sd) && pc_checkskill(sd,RG_GANGSTER) > 0)
  6948. sd->state.gangsterparadise=1;
  6949. return 0;
  6950. }
  6951. static int skill_gangster_out(struct block_list *bl,va_list ap)
  6952. {
  6953. struct map_session_data *sd;
  6954. nullpo_retr(0, bl);
  6955. nullpo_retr(0, ap);
  6956. sd=(struct map_session_data*)bl;
  6957. if(sd && sd->state.gangsterparadise)
  6958. sd->state.gangsterparadise=0;
  6959. return 0;
  6960. }
  6961. int skill_gangsterparadise(struct map_session_data *sd ,int type)
  6962. {
  6963. int range=1;
  6964. int c=0;
  6965. nullpo_retr(0, sd);
  6966. if(pc_checkskill(sd,RG_GANGSTER) <= 0)
  6967. return 0;
  6968. if(type==1) {/* 座った時の?理 */
  6969. map_foreachinarea(skill_gangster_count,sd->bl.m,
  6970. sd->bl.x-range,sd->bl.y-range,
  6971. sd->bl.x+range,sd->bl.y+range,BL_PC,&c);
  6972. if(c > 1) {/*ギャングスタ?成功したら自分にもギャングスタ??性付?*/
  6973. map_foreachinarea(skill_gangster_in,sd->bl.m,
  6974. sd->bl.x-range,sd->bl.y-range,
  6975. sd->bl.x+range,sd->bl.y+range,BL_PC);
  6976. sd->state.gangsterparadise = 1;
  6977. }
  6978. return 0;
  6979. }
  6980. else if(type==0) {/* 立ち上がったときの?理 */
  6981. map_foreachinarea(skill_gangster_count,sd->bl.m,
  6982. sd->bl.x-range,sd->bl.y-range,
  6983. sd->bl.x+range,sd->bl.y+range,BL_PC,&c);
  6984. if(c < 2)
  6985. map_foreachinarea(skill_gangster_out,sd->bl.m,
  6986. sd->bl.x-range,sd->bl.y-range,
  6987. sd->bl.x+range,sd->bl.y+range,BL_PC);
  6988. sd->state.gangsterparadise = 0;
  6989. return 0;
  6990. }
  6991. return 0;
  6992. }
  6993. /*==========================================
  6994. * 寒いジョ?ク?スクリ?ム判定?理(foreachinarea)
  6995. *------------------------------------------
  6996. */
  6997. int skill_frostjoke_scream(struct block_list *bl,va_list ap)
  6998. {
  6999. struct block_list *src;
  7000. int skillnum,skilllv;
  7001. unsigned int tick;
  7002. nullpo_retr(0, bl);
  7003. nullpo_retr(0, ap);
  7004. nullpo_retr(0, src=va_arg(ap,struct block_list*));
  7005. skillnum=va_arg(ap,int);
  7006. skilllv=va_arg(ap,int);
  7007. if(skilllv <= 0) return 0;
  7008. tick=va_arg(ap,unsigned int);
  7009. if(src == bl)//自分には?かない
  7010. return 0;
  7011. if(battle_check_target(src,bl,BCT_ENEMY) > 0)
  7012. skill_additional_effect(src,bl,skillnum,skilllv,BF_MISC,tick);
  7013. else if(battle_check_target(src,bl,BCT_PARTY) > 0) {
  7014. if(rand()%100 < 10)//PTメンバにも低確率でかかる(とりあえず10%)
  7015. skill_additional_effect(src,bl,skillnum,skilllv,BF_MISC,tick);
  7016. }
  7017. return 0;
  7018. }
  7019. /*==========================================
  7020. * Moonlit creates a 'safe zone' [celest]
  7021. *------------------------------------------
  7022. */
  7023. static int skill_moonlit_count(struct block_list *bl,va_list ap)
  7024. {
  7025. int *c, id;
  7026. struct map_session_data *sd;
  7027. nullpo_retr(0, bl);
  7028. nullpo_retr(0, ap);
  7029. nullpo_retr(0, (sd=(struct map_session_data *)bl));
  7030. id=va_arg(ap,int);
  7031. c=va_arg(ap,int *);
  7032. if (sd->bl.id != id && sd->sc_count && sd->sc_data[SC_MOONLIT].timer != -1 && c)
  7033. (*c)++;
  7034. return 0;
  7035. }
  7036. int skill_check_moonlit (struct block_list *bl, int dx, int dy)
  7037. {
  7038. int c=0;
  7039. nullpo_retr(0, bl);
  7040. map_foreachinarea(skill_moonlit_count,bl->m,
  7041. dx-1,dy-1,dx+1,dy+1,BL_PC,bl->id,&c);
  7042. return (c>0);
  7043. }
  7044. /*==========================================
  7045. *アブラカダブラの使用スキル決定(決定スキルがダメなら0を返す)
  7046. *------------------------------------------
  7047. */
  7048. int skill_abra_dataset(int skilllv)
  7049. {
  7050. int skill = rand()%331;
  7051. if(skilllv <= 0) return 0;
  7052. //dbに基づくレベル?確率判定
  7053. if(skill_abra_db[skill].req_lv > skilllv || rand()%10000 >= skill_abra_db[skill].per) return 0;
  7054. //NPCスキルはダメ
  7055. if(skill >= NPC_PIERCINGATT && skill <= NPC_SUMMONMONSTER) return 0;
  7056. //演奏スキルはダメ
  7057. if (skill_get_unit_flag(skill)&UF_DANCE) return 0;
  7058. return skill;
  7059. }
  7060. /*==========================================
  7061. * バジリカのセルを設定する
  7062. *------------------------------------------
  7063. */
  7064. void skill_basilica_cell(struct skill_unit *unit,int flag)
  7065. {
  7066. int i,x,y,range = skill_get_unit_range(HP_BASILICA);
  7067. int size = range*2+1;
  7068. for (i=0;i<size*size;i++) {
  7069. x = unit->bl.x+(i%size-range);
  7070. y = unit->bl.y+(i/size-range);
  7071. map_setcell(unit->bl.m,x,y,flag);
  7072. }
  7073. }
  7074. /*==========================================
  7075. *
  7076. *------------------------------------------
  7077. */
  7078. int skill_attack_area(struct block_list *bl,va_list ap)
  7079. {
  7080. struct block_list *src,*dsrc;
  7081. int atk_type,skillid,skilllv,flag,type;
  7082. unsigned int tick;
  7083. nullpo_retr(0, bl);
  7084. nullpo_retr(0, ap);
  7085. atk_type = va_arg(ap,int);
  7086. if((src=va_arg(ap,struct block_list*)) == NULL)
  7087. return 0;
  7088. if((dsrc=va_arg(ap,struct block_list*)) == NULL)
  7089. return 0;
  7090. skillid=va_arg(ap,int);
  7091. skilllv=va_arg(ap,int);
  7092. //if(skilllv <= 0) return 0;
  7093. if(skillid > 0 && skilllv <= 0) return 0; // celest
  7094. tick=va_arg(ap,unsigned int);
  7095. flag=va_arg(ap,int);
  7096. type=va_arg(ap,int);
  7097. if(battle_check_target(dsrc,bl,type) > 0)
  7098. skill_attack(atk_type,src,dsrc,bl,skillid,skilllv,tick,flag);
  7099. return 0;
  7100. }
  7101. /*==========================================
  7102. *
  7103. *------------------------------------------
  7104. */
  7105. int skill_clear_element_field(struct block_list *bl)
  7106. {
  7107. struct mob_data *md=NULL;
  7108. struct map_session_data *sd=NULL;
  7109. int i,max,skillid;
  7110. nullpo_retr(0, bl);
  7111. if (bl->type==BL_MOB) {
  7112. max = MAX_MOBSKILLUNITGROUP;
  7113. md = (struct mob_data *)bl;
  7114. } else if(bl->type==BL_PC) {
  7115. max = MAX_SKILLUNITGROUP;
  7116. sd = (struct map_session_data *)bl;
  7117. } else
  7118. return 0;
  7119. for (i=0;i<max;i++) {
  7120. if(sd){
  7121. skillid=sd->skillunit[i].skill_id;
  7122. if(skillid==SA_DELUGE||skillid==SA_VOLCANO||skillid==SA_VIOLENTGALE||skillid==SA_LANDPROTECTOR)
  7123. skill_delunitgroup(&sd->skillunit[i]);
  7124. }else if(md){
  7125. skillid=md->skillunit[i].skill_id;
  7126. if(skillid==SA_DELUGE||skillid==SA_VOLCANO||skillid==SA_VIOLENTGALE||skillid==SA_LANDPROTECTOR)
  7127. skill_delunitgroup(&md->skillunit[i]);
  7128. }
  7129. }
  7130. return 0;
  7131. }
  7132. /*==========================================
  7133. * ランドプロテクタ?チェック(foreachinarea)
  7134. *------------------------------------------
  7135. */
  7136. int skill_landprotector(struct block_list *bl, va_list ap )
  7137. {
  7138. int skillid;
  7139. int *alive;
  7140. struct skill_unit *unit;
  7141. nullpo_retr(0, bl);
  7142. nullpo_retr(0, ap);
  7143. skillid=va_arg(ap,int);
  7144. alive=va_arg(ap,int *);
  7145. if((unit=(struct skill_unit *)bl) == NULL)
  7146. return 0;
  7147. if(skillid==SA_LANDPROTECTOR){
  7148. skill_delunit(unit);
  7149. }else{
  7150. if(alive && unit->group->skill_id==SA_LANDPROTECTOR)
  7151. (*alive)=0;
  7152. }
  7153. return 0;
  7154. }
  7155. /*==========================================
  7156. * イドゥンの林檎の回復?理(foreachinarea)
  7157. *------------------------------------------
  7158. */
  7159. int skill_idun_heal(struct block_list *bl, va_list ap )
  7160. {
  7161. struct skill_unit *unit;
  7162. struct skill_unit_group *sg;
  7163. int heal;
  7164. nullpo_retr(0, bl);
  7165. nullpo_retr(0, ap);
  7166. nullpo_retr(0, unit = va_arg(ap,struct skill_unit *));
  7167. nullpo_retr(0, sg = unit->group);
  7168. heal=30+sg->skill_lv*5+((sg->val1)>>16)*5+((sg->val1)&0xfff)/2;
  7169. if(bl->type == BL_SKILL || bl->id == sg->src_id)
  7170. return 0;
  7171. if(bl->type == BL_PC || bl->type == BL_MOB){
  7172. clif_skill_nodamage(&unit->bl,bl,AL_HEAL,heal,1);
  7173. battle_heal(NULL,bl,heal,0,0);
  7174. }
  7175. return 0;
  7176. }
  7177. /*==========================================
  7178. * 指定範??でsrcに?して有?なタ?ゲットのblの?を?える(foreachinarea)
  7179. *------------------------------------------
  7180. */
  7181. int skill_count_target(struct block_list *bl, va_list ap)
  7182. {
  7183. struct block_list *src;
  7184. int *c;
  7185. nullpo_retr(0, bl);
  7186. nullpo_retr(0, ap);
  7187. if((src = va_arg(ap,struct block_list *)) == NULL)
  7188. return 0;
  7189. if((c = va_arg(ap,int *)) == NULL)
  7190. return 0;
  7191. if(battle_check_target(src,bl,BCT_ENEMY) > 0)
  7192. (*c)++;
  7193. return 0;
  7194. }
  7195. /*==========================================
  7196. * トラップ範??理(foreachinarea)
  7197. *------------------------------------------
  7198. */
  7199. int skill_trap_splash(struct block_list *bl, va_list ap )
  7200. {
  7201. struct block_list *src;
  7202. int tick;
  7203. int splash_count;
  7204. struct skill_unit *unit;
  7205. struct skill_unit_group *sg;
  7206. struct block_list *ss;
  7207. int i;
  7208. nullpo_retr(0, bl);
  7209. nullpo_retr(0, ap);
  7210. nullpo_retr(0, src = va_arg(ap,struct block_list *));
  7211. nullpo_retr(0, unit = (struct skill_unit *)src);
  7212. nullpo_retr(0, sg = unit->group);
  7213. nullpo_retr(0, ss = map_id2bl(sg->src_id));
  7214. tick = va_arg(ap,int);
  7215. splash_count = va_arg(ap,int);
  7216. if(battle_check_target(src,bl,BCT_ENEMY) > 0){
  7217. switch(sg->unit_id){
  7218. case 0x95: /* サンドマン */
  7219. case 0x96: /* フラッシャ? */
  7220. case 0x94: /* ショックウェ?ブトラップ */
  7221. skill_additional_effect(ss,bl,sg->skill_id,sg->skill_lv,BF_MISC,tick);
  7222. break;
  7223. case 0x8f: /* ブラストマイン */
  7224. case 0x98: /* クレイモア?トラップ */
  7225. for(i=0;i<splash_count;i++){
  7226. skill_attack(BF_MISC,ss,src,bl,sg->skill_id,sg->skill_lv,tick,(sg->val2)?0x0500:0);
  7227. }
  7228. case 0x97: /* フリ?ジングトラップ */
  7229. skill_attack(BF_WEAPON, ss,src,bl,sg->skill_id,sg->skill_lv,tick,(sg->val2)?0x0500:0);
  7230. break;
  7231. default:
  7232. break;
  7233. }
  7234. }
  7235. return 0;
  7236. }
  7237. /*==========================================
  7238. * ステ?タス異常終了
  7239. *------------------------------------------
  7240. */
  7241. int skill_encchant_eremental_end(struct block_list *bl,int type)
  7242. {
  7243. struct status_change *sc_data;
  7244. nullpo_retr(0, bl);
  7245. nullpo_retr(0, sc_data=status_get_sc_data(bl));
  7246. if( type!=SC_ENCPOISON && sc_data[SC_ENCPOISON].timer!=-1 ) /* エンチャントポイズン解除 */
  7247. status_change_end(bl,SC_ENCPOISON,-1);
  7248. if( type!=SC_ASPERSIO && sc_data[SC_ASPERSIO].timer!=-1 ) /* アスペルシオ解除 */
  7249. status_change_end(bl,SC_ASPERSIO,-1);
  7250. if( type!=SC_FLAMELAUNCHER && sc_data[SC_FLAMELAUNCHER].timer!=-1 ) /* フレイムランチャ解除 */
  7251. status_change_end(bl,SC_FLAMELAUNCHER,-1);
  7252. if( type!=SC_FROSTWEAPON && sc_data[SC_FROSTWEAPON].timer!=-1 ) /* フロストウェポン解除 */
  7253. status_change_end(bl,SC_FROSTWEAPON,-1);
  7254. if( type!=SC_LIGHTNINGLOADER && sc_data[SC_LIGHTNINGLOADER].timer!=-1 ) /* ライトニングロ?ダ?解除 */
  7255. status_change_end(bl,SC_LIGHTNINGLOADER,-1);
  7256. if( type!=SC_SEISMICWEAPON && sc_data[SC_SEISMICWEAPON].timer!=-1 ) /* サイスミックウェポン解除 */
  7257. status_change_end(bl,SC_SEISMICWEAPON,-1);
  7258. return 0;
  7259. }
  7260. /* クロ?キング?査(周りに移動不可能地?があるか) */
  7261. int skill_check_cloaking(struct block_list *bl)
  7262. {
  7263. struct map_session_data *sd = NULL;
  7264. static int dx[]={ 0, 1, 0, -1, -1, 1, 1, -1}; //optimized by Lupus
  7265. static int dy[]={-1, 0, 1, 0, -1, -1, 1, 1};
  7266. int end=1,i;
  7267. nullpo_retr(0, bl);
  7268. if(bl->type == BL_PC && !battle_config.pc_cloak_check_type) // If it's No it shouldn't be checked
  7269. return 0;
  7270. else if(bl->type == BL_MOB && !battle_config.monster_cloak_check_type)
  7271. return 0;
  7272. //missing sd [Found by Celest, commited by Aria]
  7273. if (bl->type == BL_PC)
  7274. sd=(struct map_session_data *)bl;
  7275. for(i=0;i<sizeof(dx)/sizeof(dx[0]);i++){
  7276. if(map_getcell(bl->m,bl->x+dx[i],bl->y+dy[i],CELL_CHKNOPASS)) {
  7277. end=0;
  7278. break;
  7279. }
  7280. }
  7281. if(end){
  7282. if ((sd && pc_checkskill(sd,AS_CLOAKING)<3) || bl->type == BL_MOB) {
  7283. status_change_end(bl, SC_CLOAKING, -1);
  7284. }
  7285. else if (sd && sd->sc_data[SC_CLOAKING].val3 != 130) {
  7286. sd->sc_data[SC_CLOAKING].val3 = 130;
  7287. status_calc_speed (sd);
  7288. }
  7289. }
  7290. else {
  7291. if (sd && sd->sc_data[SC_CLOAKING].val3 != 103) {
  7292. sd->sc_data[SC_CLOAKING].val3 = 103;
  7293. status_calc_speed (sd);
  7294. }
  7295. }
  7296. return end;
  7297. }
  7298. /*
  7299. *----------------------------------------------------------------------------
  7300. * スキルユニット
  7301. *----------------------------------------------------------------------------
  7302. */
  7303. /*==========================================
  7304. * 演奏/ダンスをやめる
  7305. * flag 1で合奏中なら相方にユニットを任せる
  7306. *
  7307. *------------------------------------------
  7308. */
  7309. void skill_stop_dancing(struct block_list *src, int flag)
  7310. {
  7311. struct status_change* sc_data;
  7312. struct skill_unit_group* group;
  7313. short* sc_count;
  7314. nullpo_retv(src);
  7315. nullpo_retv(sc_data = status_get_sc_data(src));
  7316. nullpo_retv(sc_count = status_get_sc_count(src));
  7317. if((*sc_count)>0 && sc_data[SC_DANCING].timer != -1) {
  7318. group=(struct skill_unit_group *)sc_data[SC_DANCING].val2; //ダンスのスキルユニットIDはval2に入ってる
  7319. if(group && src->type==BL_PC && sc_data && sc_data[SC_DANCING].val4){ //合奏中?
  7320. struct map_session_data* dsd=map_id2sd(sc_data[SC_DANCING].val4); //相方のsd取得
  7321. if(flag){ //ログアウトなど片方が落ちても演奏が??される
  7322. if(dsd && src->id == group->src_id){ //グル?プを持ってるPCが落ちる
  7323. group->src_id=sc_data[SC_DANCING].val4; //相方にグル?プを任せる
  7324. if(flag&1) //ログアウト
  7325. dsd->sc_data[SC_DANCING].val4=0; //相方の相方を0にして合奏終了→通常のダンス?態
  7326. if(flag&2) //ハエ飛びなど
  7327. return; //合奏もダンス?態も終了させない&スキルユニットは置いてけぼり
  7328. }else if(dsd && dsd->bl.id == group->src_id){ //相方がグル?プを持っているPCが落ちる(自分はグル?プを持っていない)
  7329. if(flag&1) //ログアウト
  7330. dsd->sc_data[SC_DANCING].val4=0; //相方の相方を0にして合奏終了→通常のダンス?態
  7331. if(flag&2) //ハエ飛びなど
  7332. return; //合奏もダンス?態も終了させない&スキルユニットは置いてけぼり
  7333. }
  7334. status_change_end(src,SC_DANCING,-1);//自分のステ?タスを終了させる
  7335. //そしてグル?プは消さない&消さないのでステ?タス計算もいらない?
  7336. return;
  7337. }else{
  7338. if(dsd && src->id == group->src_id){ //グル?プを持ってるPCが止める
  7339. status_change_end((struct block_list *)dsd,SC_DANCING,-1);//相手のステ?タスを終了させる
  7340. }
  7341. if(dsd && dsd->bl.id == group->src_id){ //相方がグル?プを持っているPCが止める(自分はグル?プを持っていない)
  7342. status_change_end(src,SC_DANCING,-1);//自分のステ?タスを終了させる
  7343. }
  7344. }
  7345. }
  7346. if(flag&2 && group && src->type==BL_PC){ //ハエで飛んだときとかはユニットも飛ぶ
  7347. struct map_session_data *sd = (struct map_session_data *)src;
  7348. skill_unit_move_unit_group(group, sd->bl.m,(sd->to_x - sd->bl.x),(sd->to_y - sd->bl.y));
  7349. return;
  7350. }
  7351. skill_delunitgroup(group);
  7352. if(src->type==BL_PC)
  7353. status_calc_pc((struct map_session_data *)src,0);
  7354. }
  7355. }
  7356. /*==========================================
  7357. * スキルユニット初期化
  7358. *------------------------------------------
  7359. */
  7360. struct skill_unit *skill_initunit(struct skill_unit_group *group,int idx,int x,int y)
  7361. {
  7362. struct skill_unit *unit;
  7363. nullpo_retr(NULL, group);
  7364. nullpo_retr(NULL, unit=&group->unit[idx]);
  7365. if(!unit->alive)
  7366. group->alive_count++;
  7367. unit->bl.id=map_addobject(&unit->bl);
  7368. unit->bl.type=BL_SKILL;
  7369. unit->bl.m=group->map;
  7370. unit->bl.x=x;
  7371. unit->bl.y=y;
  7372. unit->group=group;
  7373. unit->val1=unit->val2=0;
  7374. unit->alive=1;
  7375. map_addblock(&unit->bl);
  7376. clif_skill_setunit(unit);
  7377. if (group->skill_id==HP_BASILICA)
  7378. skill_basilica_cell(unit,CELL_SETBASILICA);
  7379. return unit;
  7380. }
  7381. /*==========================================
  7382. * スキルユニット削除
  7383. *------------------------------------------
  7384. */
  7385. int skill_delunit(struct skill_unit *unit)
  7386. {
  7387. struct skill_unit_group *group;
  7388. nullpo_retr(0, unit);
  7389. if(!unit->alive)
  7390. return 0;
  7391. nullpo_retr(0, group=unit->group);
  7392. /* onlimitイベント呼び出し */
  7393. skill_unit_onlimit( unit,gettick() );
  7394. /* onoutイベント呼び出し */
  7395. if (!unit->range) {
  7396. map_foreachinarea(skill_unit_effect,unit->bl.m,
  7397. unit->bl.x,unit->bl.y,unit->bl.x,unit->bl.y,0,
  7398. &unit->bl,gettick(),0);
  7399. }
  7400. if (group->skill_id==HP_BASILICA)
  7401. skill_basilica_cell(unit,CELL_CLRBASILICA);
  7402. clif_skill_delunit(unit);
  7403. unit->group=NULL;
  7404. unit->alive=0;
  7405. map_delobjectnofree(unit->bl.id);
  7406. if(group->alive_count>0 && (--group->alive_count)<=0)
  7407. skill_delunitgroup(group);
  7408. return 0;
  7409. }
  7410. /*==========================================
  7411. * スキルユニットグル?プ初期化
  7412. *------------------------------------------
  7413. */
  7414. static int skill_unit_group_newid = MAX_SKILL_DB;
  7415. struct skill_unit_group *skill_initunitgroup(struct block_list *src,
  7416. int count,int skillid,int skilllv,int unit_id)
  7417. {
  7418. int i;
  7419. struct skill_unit_group *group=NULL, *list=NULL;
  7420. int maxsug=0;
  7421. if(skilllv <= 0) return 0;
  7422. nullpo_retr(NULL, src);
  7423. if(src->type==BL_PC){
  7424. list=((struct map_session_data *)src)->skillunit;
  7425. maxsug=MAX_SKILLUNITGROUP;
  7426. }else if(src->type==BL_MOB){
  7427. list=((struct mob_data *)src)->skillunit;
  7428. maxsug=MAX_MOBSKILLUNITGROUP;
  7429. }else if(src->type==BL_PET){
  7430. list=((struct pet_data *)src)->skillunit;
  7431. maxsug=MAX_MOBSKILLUNITGROUP;
  7432. }
  7433. if(list){
  7434. for(i=0;i<maxsug;i++) /* 空いているもの?索 */
  7435. if(list[i].group_id==0){
  7436. group=&list[i];
  7437. break;
  7438. }
  7439. if(group==NULL){ /* 空いてないので古いもの?索 */
  7440. int j=0;
  7441. unsigned maxdiff=0,x,tick=gettick();
  7442. for(i=0;i<maxsug;i++)
  7443. if((x=DIFF_TICK(tick,list[i].tick))>maxdiff){
  7444. maxdiff=x;
  7445. j=i;
  7446. }
  7447. skill_delunitgroup(&list[j]);
  7448. group=&list[j];
  7449. }
  7450. }
  7451. if(group==NULL){
  7452. printf("skill_initunitgroup: error unit group !\n");
  7453. exit(1);
  7454. }
  7455. group->src_id=src->id;
  7456. group->party_id=status_get_party_id(src);
  7457. group->guild_id=status_get_guild_id(src);
  7458. group->group_id=skill_unit_group_newid++;
  7459. if(skill_unit_group_newid<=0)
  7460. skill_unit_group_newid = MAX_SKILL_DB;
  7461. group->unit=(struct skill_unit *)aCalloc(count,sizeof(struct skill_unit));
  7462. group->unit_count=count;
  7463. group->val1=group->val2=0;
  7464. group->skill_id=skillid;
  7465. group->skill_lv=skilllv;
  7466. group->unit_id=unit_id;
  7467. group->map=src->m;
  7468. group->limit=10000;
  7469. group->interval=1000;
  7470. group->tick=gettick();
  7471. group->valstr=NULL;
  7472. if (skill_get_unit_flag(skillid)&UF_DANCE) {
  7473. struct map_session_data *sd = NULL;
  7474. if(src->type==BL_PC && (sd=(struct map_session_data *)src) ){
  7475. sd->skillid_dance=skillid;
  7476. sd->skilllv_dance=skilllv;
  7477. }
  7478. status_change_start(src,SC_DANCING,skillid,(int)group,0,0,skill_get_time(skillid,skilllv)+1000,0);
  7479. //合奏スキルは相方をダンス状態にする
  7480. if (sd && skill_get_unit_flag(skillid)&UF_ENSEMBLE) {
  7481. int c=0;
  7482. map_foreachinarea(skill_check_condition_use_sub,sd->bl.m,
  7483. sd->bl.x-1,sd->bl.y-1,sd->bl.x+1,sd->bl.y+1,BL_PC,&sd->bl,&c);
  7484. }
  7485. }
  7486. return group;
  7487. }
  7488. /*==========================================
  7489. * スキルユニットグル?プ削除
  7490. *------------------------------------------
  7491. */
  7492. int skill_delunitgroup(struct skill_unit_group *group)
  7493. {
  7494. struct block_list *src;
  7495. int i;
  7496. nullpo_retr(0, group);
  7497. if(group->unit_count<=0)
  7498. return 0;
  7499. src=map_id2bl(group->src_id);
  7500. //ダンススキルはダンス状態を解除する
  7501. if (skill_get_unit_flag(group->skill_id)&UF_DANCE) {
  7502. if(src)
  7503. status_change_end(src,SC_DANCING,-1);
  7504. }
  7505. group->alive_count=0;
  7506. if(group->unit!=NULL){
  7507. for(i=0;i<group->unit_count;i++)
  7508. if(group->unit[i].alive)
  7509. skill_delunit(&group->unit[i]);
  7510. }
  7511. if(group->valstr!=NULL){
  7512. map_freeblock(group->valstr);
  7513. group->valstr=NULL;
  7514. }
  7515. map_freeblock(group->unit); /* aFree()の替わり */
  7516. group->unit=NULL;
  7517. group->src_id=0;
  7518. group->group_id=0;
  7519. group->unit_count=0;
  7520. return 0;
  7521. }
  7522. /*==========================================
  7523. * スキルユニットグル?プ全削除
  7524. *------------------------------------------
  7525. */
  7526. int skill_clear_unitgroup(struct block_list *src)
  7527. {
  7528. struct skill_unit_group *group=NULL;
  7529. int maxsug=0;
  7530. nullpo_retr(0, src);
  7531. if(src->type==BL_PC){
  7532. group=((struct map_session_data *)src)->skillunit;
  7533. maxsug=MAX_SKILLUNITGROUP;
  7534. } else if(src->type==BL_MOB){
  7535. group=((struct mob_data *)src)->skillunit;
  7536. maxsug=MAX_MOBSKILLUNITGROUP;
  7537. } else if(src->type==BL_PET){ // [Valaris]
  7538. group=((struct pet_data *)src)->skillunit;
  7539. maxsug=MAX_MOBSKILLUNITGROUP;
  7540. } else
  7541. return 0;
  7542. if(group){
  7543. int i;
  7544. for(i=0;i<maxsug;i++)
  7545. if(group[i].group_id>0 && group[i].src_id == src->id)
  7546. skill_delunitgroup(&group[i]);
  7547. }
  7548. return 0;
  7549. }
  7550. /*==========================================
  7551. * スキルユニットグル?プの被影響tick?索
  7552. *------------------------------------------
  7553. */
  7554. struct skill_unit_group_tickset *skill_unitgrouptickset_search(
  7555. struct block_list *bl,struct skill_unit_group *group,int tick)
  7556. {
  7557. int i,j=-1,k,s,id;
  7558. struct skill_unit_group_tickset *set;
  7559. nullpo_retr(0, bl);
  7560. if (group->interval==-1)
  7561. return NULL;
  7562. if (bl->type == BL_PC)
  7563. set = ((struct map_session_data *)bl)->skillunittick;
  7564. else if (bl->type == BL_MOB)
  7565. set = ((struct mob_data *)bl)->skillunittick;
  7566. else
  7567. return 0;
  7568. if (skill_get_unit_flag(group->skill_id)&UF_NOOVERLAP)
  7569. id = s = group->skill_id;
  7570. else
  7571. id = s = group->group_id;
  7572. for (i=0; i<MAX_SKILLUNITGROUPTICKSET; i++) {
  7573. k = (i+s) % MAX_SKILLUNITGROUPTICKSET;
  7574. if (set[k].id == id)
  7575. return &set[k];
  7576. else if (j==-1 && (DIFF_TICK(tick,set[k].tick)>0 || set[k].id==0))
  7577. j=k;
  7578. }
  7579. if (j == -1) {
  7580. if(battle_config.error_log) {
  7581. sprintf (tmp_output, "skill_unitgrouptickset_search: tickset is full\n");
  7582. ShowWarning (tmp_output);
  7583. }
  7584. j = id % MAX_SKILLUNITGROUPTICKSET;
  7585. }
  7586. set[j].id = id;
  7587. set[j].tick = tick;
  7588. return &set[j];
  7589. }
  7590. /*==========================================
  7591. * スキルユニットタイマ??動?理用(foreachinarea)
  7592. *------------------------------------------
  7593. */
  7594. int skill_unit_timer_sub_onplace( struct block_list *bl, va_list ap )
  7595. {
  7596. struct skill_unit *unit;
  7597. struct skill_unit_group *group;
  7598. unsigned int tick;
  7599. nullpo_retr(0, bl);
  7600. nullpo_retr(0, ap);
  7601. unit = va_arg(ap,struct skill_unit *);
  7602. tick = va_arg(ap,unsigned int);
  7603. if (bl->type!=BL_PC && bl->type!=BL_MOB)
  7604. return 0;
  7605. if (!unit->alive || bl->prev==NULL)
  7606. return 0;
  7607. nullpo_retr(0, group=unit->group);
  7608. if (battle_check_target(&unit->bl,bl,group->target_flag)<=0)
  7609. return 0;
  7610. skill_unit_onplace_timer(unit,bl,tick);
  7611. return 0;
  7612. }
  7613. /*==========================================
  7614. * スキルユニットタイマ??理用(foreachobject)
  7615. *------------------------------------------
  7616. */
  7617. int skill_unit_timer_sub( struct block_list *bl, va_list ap )
  7618. {
  7619. struct skill_unit *unit;
  7620. struct skill_unit_group *group;
  7621. int range;
  7622. unsigned int tick;
  7623. nullpo_retr(0, bl);
  7624. nullpo_retr(0, ap);
  7625. nullpo_retr(0, unit=(struct skill_unit *)bl);
  7626. tick=va_arg(ap,unsigned int);
  7627. if(!unit->alive)
  7628. return 0;
  7629. nullpo_retr(0, group=unit->group);
  7630. range = unit->range;
  7631. /* onplace_timerイベント呼び出し */
  7632. if (range>=0 && group->interval!=-1) {
  7633. map_foreachinarea(skill_unit_timer_sub_onplace, bl->m,
  7634. bl->x-range,bl->y-range,bl->x+range,bl->y+range,0,bl,tick);
  7635. if (!unit->alive)
  7636. return 0;
  7637. // マグヌスは発動したユニットは削除する
  7638. if (group->skill_id==PR_MAGNUS && unit->val2) {
  7639. skill_delunit(unit);
  7640. return 0;
  7641. }
  7642. }
  7643. // イドゥンの林檎による回復
  7644. if (group->unit_id==0xaa && DIFF_TICK(tick,group->tick)>=6000*group->val3) {
  7645. struct block_list *src = map_id2bl(group->src_id);
  7646. int range = skill_get_unit_layout_type(group->skill_id,group->skill_lv);
  7647. nullpo_retr(0, src);
  7648. map_foreachinarea(skill_idun_heal,src->m,
  7649. src->x-range,src->y-range,src->x+range,src->y+range,0,unit);
  7650. group->val3++;
  7651. }
  7652. /* 時間切れ削除 */
  7653. if((DIFF_TICK(tick,group->tick)>=group->limit || DIFF_TICK(tick,group->tick)>=unit->limit)){
  7654. switch(group->unit_id){
  7655. case 0x8f: /* ブラストマイン */
  7656. group->unit_id = 0x8c;
  7657. clif_changelook(bl,LOOK_BASE,group->unit_id);
  7658. group->limit=DIFF_TICK(tick+1500,group->tick);
  7659. unit->limit=DIFF_TICK(tick+1500,group->tick);
  7660. break;
  7661. case 0x90: /* スキッドトラップ */
  7662. case 0x91: /* アンクルスネア */
  7663. case 0x93: /* ランドマイン */
  7664. case 0x94: /* ショックウェ?ブトラップ */
  7665. case 0x95: /* サンドマン */
  7666. case 0x96: /* フラッシャ? */
  7667. case 0x97: /* フリ?ジングトラップ */
  7668. case 0x98: /* クレイモア?トラップ */
  7669. case 0x99: /* ト?キ?ボックス */
  7670. {
  7671. struct block_list *src=map_id2bl(group->src_id);
  7672. if(group->unit_id == 0x91 && group->val2);
  7673. else{
  7674. if(src && src->type==BL_PC){
  7675. struct item item_tmp;
  7676. memset(&item_tmp,0,sizeof(item_tmp));
  7677. item_tmp.nameid=1065;
  7678. item_tmp.identify=1;
  7679. map_addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,NULL,NULL,NULL,0); // ?返還
  7680. }
  7681. }
  7682. skill_delunit(unit);
  7683. }
  7684. break;
  7685. case 0xc1:
  7686. case 0xc2:
  7687. case 0xc3:
  7688. case 0xc4:
  7689. {
  7690. struct block_list *src=map_id2bl(group->src_id);
  7691. if (src)
  7692. group->tick = tick;
  7693. }
  7694. break;
  7695. default:
  7696. skill_delunit(unit);
  7697. }
  7698. }
  7699. if(group->unit_id == 0x8d) {
  7700. unit->val1 -= 5;
  7701. if(unit->val1 <= 0 && unit->limit + group->tick > tick + 700)
  7702. unit->limit = DIFF_TICK(tick+700,group->tick);
  7703. }
  7704. return 0;
  7705. }
  7706. /*==========================================
  7707. * スキルユニットタイマ??理
  7708. *------------------------------------------
  7709. */
  7710. int skill_unit_timer( int tid,unsigned int tick,int id,int data)
  7711. {
  7712. map_freeblock_lock();
  7713. map_foreachobject( skill_unit_timer_sub, BL_SKILL, tick );
  7714. map_freeblock_unlock();
  7715. return 0;
  7716. }
  7717. /*==========================================
  7718. * スキルユニット移動時?理用(foreachinarea)
  7719. *------------------------------------------
  7720. */
  7721. int skill_unit_move_sub( struct block_list *bl, va_list ap )
  7722. {
  7723. struct skill_unit *unit = (struct skill_unit *)bl;
  7724. struct skill_unit_group *group;
  7725. struct block_list *target;
  7726. unsigned int tick,flag;
  7727. nullpo_retr(0, bl);
  7728. nullpo_retr(0, ap);
  7729. nullpo_retr(0, target=va_arg(ap,struct block_list*));
  7730. tick = va_arg(ap,unsigned int);
  7731. flag = va_arg(ap,int);
  7732. if (target->type!=BL_PC && target->type!=BL_MOB)
  7733. return 0;
  7734. nullpo_retr(0, group=unit->group);
  7735. if (group->interval!=-1)
  7736. return 0;
  7737. if (!unit->alive || target->prev==NULL)
  7738. return 0;
  7739. if (flag)
  7740. skill_unit_onplace(unit,target,tick);
  7741. else
  7742. skill_unit_onout(unit,target,tick);
  7743. return 0;
  7744. }
  7745. /*==========================================
  7746. * スキルユニット移動時?理
  7747. *------------------------------------------
  7748. */
  7749. int skill_unit_move(struct block_list *bl,unsigned int tick,int flag)
  7750. {
  7751. nullpo_retr(0, bl);
  7752. if(bl->prev==NULL )
  7753. return 0;
  7754. map_foreachinarea(skill_unit_move_sub,
  7755. bl->m,bl->x,bl->y,bl->x,bl->y,BL_SKILL,bl,tick,flag);
  7756. return 0;
  7757. }
  7758. /*==========================================
  7759. * スキルユニット自?の移動時?理
  7760. * 引?はグル?プと移動量
  7761. *------------------------------------------
  7762. */
  7763. int skill_unit_move_unit_group( struct skill_unit_group *group, int m,int dx,int dy)
  7764. {
  7765. int i,j;
  7766. int tick = gettick();
  7767. int *m_flag;
  7768. struct skill_unit *unit1;
  7769. struct skill_unit *unit2;
  7770. nullpo_retr(0, group);
  7771. if (group->unit_count<=0)
  7772. return 0;
  7773. if (group->unit==NULL)
  7774. return 0;
  7775. // 移動可能なスキルはダンス系と、ブラストマイン、クレイモアートラップのみ
  7776. if (!(skill_get_unit_flag(group->skill_id)&UF_DANCE) &&
  7777. group->skill_id!=HT_CLAYMORETRAP && group->skill_id!=HT_BLASTMINE)
  7778. return 0;
  7779. m_flag = malloc(sizeof(int)*group->unit_count);
  7780. memset(m_flag,0,sizeof(int)*group->unit_count);// 移動フラグ
  7781. // 先にフラグを全部決める
  7782. // m_flag
  7783. // 0: 単純移動
  7784. // 1: ユニットを移動する(現位置からユニットがなくなる)
  7785. // 2: 残留&新位置が移動先となる(移動先にユニットが存在しない)
  7786. // 3: 残留
  7787. for(i=0;i<group->unit_count;i++){
  7788. unit1=&group->unit[i];
  7789. if (!unit1->alive || unit1->bl.m!=m)
  7790. continue;
  7791. for(j=0;j<group->unit_count;j++){
  7792. unit2=&group->unit[j];
  7793. if (!unit2->alive)
  7794. continue;
  7795. if (unit1->bl.x+dx==unit2->bl.x && unit1->bl.y+dy==unit2->bl.y){
  7796. // 移動先にユニットがかぶっている
  7797. m_flag[i] |= 0x1;
  7798. }
  7799. if (unit1->bl.x-dx==unit2->bl.x && unit1->bl.y-dy==unit2->bl.y){
  7800. // ユニットがこの場所にやってくる
  7801. m_flag[i] |= 0x2;
  7802. }
  7803. }
  7804. }
  7805. // フラグに基づいてユニット移動
  7806. // フラグが1のunitを探し、フラグが2のunitの移動先に移す
  7807. j = 0;
  7808. for (i=0;i<group->unit_count;i++) {
  7809. unit1=&group->unit[i];
  7810. if (!unit1->alive)
  7811. continue;
  7812. if (!(m_flag[i]&0x2)) {
  7813. // ユニットがなくなる場所でスキルユニット影響を消す
  7814. map_foreachinarea(skill_unit_effect,unit1->bl.m,
  7815. unit1->bl.x,unit1->bl.y,unit1->bl.x,unit1->bl.y,0,
  7816. &unit1->bl,tick,0);
  7817. }
  7818. if (m_flag[i]==0) {
  7819. // 単純移動
  7820. map_delblock(&unit1->bl);
  7821. unit1->bl.m = m;
  7822. unit1->bl.x += dx;
  7823. unit1->bl.y += dy;
  7824. map_addblock(&unit1->bl);
  7825. clif_skill_setunit(unit1);
  7826. } else if (m_flag[i]==1) {
  7827. // フラグが2のものを探してそのユニットの移動先に移動
  7828. for(;j<group->unit_count;j++) {
  7829. if (m_flag[j]==2) {
  7830. // 継承移動
  7831. unit2 = &group->unit[j];
  7832. if (!unit2->alive)
  7833. continue;
  7834. map_delblock(&unit1->bl);
  7835. unit1->bl.m = m;
  7836. unit1->bl.x = unit2->bl.x+dx;
  7837. unit1->bl.y = unit2->bl.y+dy;
  7838. map_addblock(&unit1->bl);
  7839. clif_skill_setunit(unit1);
  7840. j++;
  7841. break;
  7842. }
  7843. }
  7844. }
  7845. if (!(m_flag[i]&0x2)) {
  7846. // 移動後の場所でスキルユニットを発動
  7847. map_foreachinarea(skill_unit_effect,unit1->bl.m,
  7848. unit1->bl.x,unit1->bl.y,unit1->bl.x,unit1->bl.y,0,
  7849. &unit1->bl,tick,1);
  7850. }
  7851. }
  7852. free(m_flag);
  7853. return 0;
  7854. }
  7855. /*----------------------------------------------------------------------------
  7856. * アイテム合成
  7857. *----------------------------------------------------------------------------
  7858. */
  7859. /*==========================================
  7860. * アイテム合成可能判定
  7861. *------------------------------------------
  7862. */
  7863. int skill_can_produce_mix( struct map_session_data *sd, int nameid, int trigger )
  7864. {
  7865. int i,j;
  7866. nullpo_retr(0, sd);
  7867. if(nameid<=0)
  7868. return 0;
  7869. for(i=0;i<MAX_SKILL_PRODUCE_DB;i++){
  7870. if(skill_produce_db[i].nameid == nameid )
  7871. break;
  7872. }
  7873. if( i >= MAX_SKILL_PRODUCE_DB ) /* デ?タベ?スにない */
  7874. return 0;
  7875. if(trigger>=0){
  7876. if(trigger == 32 || trigger == 16 || trigger==64 || trigger == 256) {
  7877. if(skill_produce_db[i].itemlv!=trigger) /* ファ?マシ?*ポ?ション類と溶??*?石以外はだめ */
  7878. return 0;
  7879. }else{
  7880. if(skill_produce_db[i].itemlv>=16) /* 武器以外はだめ */
  7881. return 0;
  7882. if( itemdb_wlv(nameid)>trigger ) /* 武器Lv判定 */
  7883. return 0;
  7884. }
  7885. }
  7886. if( (j=skill_produce_db[i].req_skill)>0 && pc_checkskill(sd,j)<=0 )
  7887. return 0; /* スキルが足りない */
  7888. for(j=0;j<MAX_PRODUCE_RESOURCE;j++){
  7889. int id,x,y;
  7890. if( (id=skill_produce_db[i].mat_id[j]) <= 0 ) /* これ以上は材料要らない */
  7891. continue;
  7892. if(skill_produce_db[i].mat_amount[j] <= 0) {
  7893. if(pc_search_inventory(sd,id) < 0)
  7894. return 0;
  7895. }
  7896. else {
  7897. for(y=0,x=0;y<MAX_INVENTORY;y++)
  7898. if( sd->status.inventory[y].nameid == id )
  7899. x+=sd->status.inventory[y].amount;
  7900. if(x<skill_produce_db[i].mat_amount[j]) /* アイテムが足りない */
  7901. return 0;
  7902. }
  7903. }
  7904. return i+1;
  7905. }
  7906. /*==========================================
  7907. * アイテム合成可能判定
  7908. *------------------------------------------
  7909. */
  7910. int skill_produce_mix( struct map_session_data *sd,
  7911. int nameid, int slot1, int slot2, int slot3 )
  7912. {
  7913. int slot[3];
  7914. int i,sc,ele,idx,equip,wlv,make_per,flag;
  7915. nullpo_retr(0, sd);
  7916. if( !(idx=skill_can_produce_mix(sd,nameid,-1)) ) /* ?件不足 */
  7917. return 0;
  7918. idx--;
  7919. slot[0]=slot1;
  7920. slot[1]=slot2;
  7921. slot[2]=slot3;
  7922. /* 埋め?み?理 */
  7923. for(i=0,sc=0,ele=0;i<3;i++){
  7924. int j;
  7925. if( slot[i]<=0 )
  7926. continue;
  7927. j = pc_search_inventory(sd,slot[i]);
  7928. if(j < 0) /* 不正パケット(アイテム存在)チェック */
  7929. continue;
  7930. if(slot[i]==1000){ /* 星のかけら */
  7931. pc_delitem(sd,j,1,1);
  7932. sc++;
  7933. }
  7934. if(slot[i]>=994 && slot[i]<=997 && ele==0){ /* ?性石 */
  7935. static const int ele_table[4]={3,1,4,2};
  7936. pc_delitem(sd,j,1,1);
  7937. ele=ele_table[slot[i]-994];
  7938. }
  7939. }
  7940. /* 材料消費 */
  7941. for(i=0;i<MAX_PRODUCE_RESOURCE;i++){
  7942. int j,id,x;
  7943. if( (id=skill_produce_db[idx].mat_id[i]) <= 0 )
  7944. continue;
  7945. x=skill_produce_db[idx].mat_amount[i]; /* 必要な個? */
  7946. do{ /* 2つ以上のインデックスにまたがっているかもしれない */
  7947. int y=0;
  7948. j = pc_search_inventory(sd,id);
  7949. if(j >= 0){
  7950. y = sd->status.inventory[j].amount;
  7951. if(y>x)y=x; /* 足りている */
  7952. pc_delitem(sd,j,y,0);
  7953. }else {
  7954. if(battle_config.error_log)
  7955. printf("skill_produce_mix: material item error\n");
  7956. }
  7957. x-=y; /* まだ足りない個?を計算 */
  7958. }while( j>=0 && x>0 ); /* 材料を消費するか、エラ?になるまで繰り返す */
  7959. }
  7960. /* 確率判定 */
  7961. equip = itemdb_isequip(nameid);
  7962. if(!equip) {
  7963. // Corrected rates [DracoRPG] --------------------------//
  7964. if(skill_produce_db[idx].req_skill==AM_PHARMACY) {
  7965. make_per = pc_checkskill(sd,AM_LEARNINGPOTION)*100
  7966. + pc_checkskill(sd,AM_PHARMACY)*300 + sd->status.job_level*20
  7967. + sd->status.dex*10+sd->status.int_*5;
  7968. if(nameid >= 501 && nameid <= 505) // Normal potions
  7969. make_per += 2000 + pc_checkskill(sd,AM_POTIONPITCHER)*100;
  7970. else if(nameid >= 605 && nameid <= 606) // Anodyne & Aloevera (not sure of the formula, I put the same base value as normal pots but without the Aid Potion bonus since they are not throwable pots ^^)
  7971. make_per += 2000;
  7972. else if(nameid >= 545 && nameid <= 547) // Concentrated potions
  7973. ;
  7974. else if(nameid == 970) // Alcohol
  7975. make_per += 1000;
  7976. else if(nameid == 7135) // Bottle Grenade
  7977. make_per += 500 + pc_checkskill(sd,AM_DEMONSTRATION)*100;
  7978. else if(nameid == 7136) // Acid Bottle
  7979. make_per += 500 + pc_checkskill(sd,AM_ACIDTERROR)*100;
  7980. else if(nameid == 7137) // Plant Bottle
  7981. make_per += 500 + pc_checkskill(sd,AM_CANNIBALIZE)*100;
  7982. else if(nameid == 7138) // Marine Sphere Bottle
  7983. make_per += 500 + pc_checkskill(sd,AM_SPHEREMINE)*100;
  7984. else if(nameid == 7139) // Glistening Coat
  7985. make_per += 500 + pc_checkskill(sd,AM_CP_WEAPON)*100 + pc_checkskill(sd,AM_CP_SHIELD)*100 +
  7986. pc_checkskill(sd,AM_CP_ARMOR)*100 + pc_checkskill(sd,AM_CP_HELM)*100;
  7987. else
  7988. make_per = 1000 + sd->status.base_level*30 + sd->paramc[3]*20 + sd->paramc[4]*15 + pc_checkskill(sd,AM_LEARNINGPOTION)*100 + pc_checkskill(sd,AM_PHARMACY)*300;
  7989. } else if (skill_produce_db[idx].req_skill == ASC_CDP) {
  7990. make_per = 2000 + 40*sd->paramc[4] + 20*sd->paramc[5];
  7991. //make_per = 20 + (20*sd->paramc[4])/50 + (20*sd->paramc[5])/100;
  7992. } else {
  7993. if(nameid == 998)
  7994. make_per = 1500 + sd->status.job_level*35 + sd->paramc[4]*10 + sd->paramc[5]*10 + pc_checkskill(sd,skill_produce_db[idx].req_skill)*600;
  7995. else
  7996. make_per = 1000 + sd->status.job_level*35 + sd->paramc[4]*10 + sd->paramc[5]*10 + pc_checkskill(sd,skill_produce_db[idx].req_skill)*500;
  7997. }
  7998. }
  7999. else { // Corrected rates [DracoRPG]
  8000. int add_per=0;
  8001. if(pc_search_inventory(sd,989) >= 0) add_per = 400;
  8002. else if(pc_search_inventory(sd,988) >= 0) add_per = 300;
  8003. else if(pc_search_inventory(sd,987) >= 0) add_per = 200;
  8004. else if(pc_search_inventory(sd,986) >= 0) add_per = 100;
  8005. wlv = itemdb_wlv(nameid);
  8006. make_per = 1500 + sd->status.job_level*35 + sd->paramc[4]*10 + sd->paramc[5]*10 + pc_checkskill(sd,skill_produce_db[idx].req_skill)*1000 + pc_checkskill(sd,BS_WEAPONRESEARCH)*100 +
  8007. ((wlv >= 3)? pc_checkskill(sd,BS_ORIDEOCON)*100 : 0) + add_per - (ele? 2500:0) - sc*((4-wlv)*500) - wlv*1000;
  8008. }
  8009. // -----------------------------------------------------//
  8010. if(make_per < 1) make_per = 1;
  8011. if(skill_produce_db[idx].req_skill==AM_PHARMACY ||
  8012. skill_produce_db[idx].req_skill==ASC_CDP) {
  8013. if( battle_config.pp_rate!=100 )
  8014. make_per=make_per*battle_config.pp_rate/100;
  8015. }
  8016. else {
  8017. if( battle_config.wp_rate!=100 ) /* 確率補正 */
  8018. make_per=make_per*battle_config.wp_rate/100;
  8019. }
  8020. // if(battle_config.etc_log)
  8021. // printf("make rate = %d\n",make_per);
  8022. if(rand()%10000 < make_per){
  8023. /* 成功 */
  8024. struct item tmp_item;
  8025. memset(&tmp_item,0,sizeof(tmp_item));
  8026. tmp_item.nameid=nameid;
  8027. tmp_item.amount=1;
  8028. tmp_item.identify=1;
  8029. if(equip){ /* 武器の場合 */
  8030. tmp_item.card[0]=0x00ff; /* 製造武器フラグ */
  8031. tmp_item.card[1]=((sc*5)<<8)+ele; /* ?性とつよさ */
  8032. *((unsigned long *)(&tmp_item.card[2]))=sd->char_id; /* キャラID */
  8033. }
  8034. else if((battle_config.produce_item_name_input && skill_produce_db[idx].req_skill!=AM_PHARMACY) ||
  8035. (battle_config.produce_potion_name_input && skill_produce_db[idx].req_skill==AM_PHARMACY)) {
  8036. tmp_item.card[0]=0x00fe;
  8037. tmp_item.card[1]=0;
  8038. *((unsigned long *)(&tmp_item.card[2]))=sd->char_id; /* キャラID */
  8039. }
  8040. if(log_config.produce > 0)
  8041. log_produce(sd,nameid,slot1,slot2,slot3,1);
  8042. switch (skill_produce_db[idx].req_skill) {
  8043. case AM_PHARMACY:
  8044. clif_produceeffect(sd,2,nameid);/* 製?エフェクト */
  8045. clif_misceffect(&sd->bl,5); /* 他人にも成功を通知 */
  8046. break;
  8047. case ASC_CDP:
  8048. clif_produceeffect(sd,2,nameid);/* 暫定で製?エフェクト */
  8049. clif_misceffect(&sd->bl,5);
  8050. break;
  8051. default: /* 武器製造、コイン製造 */
  8052. clif_produceeffect(sd,0,nameid); /* 武器製造エフェクト */
  8053. clif_misceffect(&sd->bl,3);
  8054. break;
  8055. }
  8056. if((flag = pc_additem(sd,&tmp_item,1))) {
  8057. clif_additem(sd,0,0,flag);
  8058. map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
  8059. }
  8060. } else {
  8061. if(log_config.produce > 0)
  8062. log_produce(sd,nameid,slot1,slot2,slot3,0);
  8063. switch (skill_produce_db[idx].req_skill) {
  8064. case AM_PHARMACY:
  8065. clif_produceeffect(sd,3,nameid);/* 製?失敗エフェクト */
  8066. clif_misceffect(&sd->bl,6); /* 他人にも失敗を通知 */
  8067. break;
  8068. case ASC_CDP:
  8069. {
  8070. clif_produceeffect(sd,3,nameid); /* 暫定で製?エフェクト */
  8071. clif_misceffect(&sd->bl,6); /* 他人にも失敗を通知 */
  8072. pc_heal(sd, -(sd->status.max_hp>>2), 0);
  8073. }
  8074. break;
  8075. default:
  8076. clif_produceeffect(sd,1,nameid);/* 武器製造失敗エフェクト */
  8077. clif_misceffect(&sd->bl,2); /* 他人にも失敗を通知 */
  8078. break;
  8079. }
  8080. }
  8081. return 0;
  8082. }
  8083. int skill_arrow_create( struct map_session_data *sd,int nameid)
  8084. {
  8085. int i,j,flag,index=-1;
  8086. struct item tmp_item;
  8087. nullpo_retr(0, sd);
  8088. if(nameid <= 0)
  8089. return 1;
  8090. for(i=0;i<MAX_SKILL_ARROW_DB;i++)
  8091. if(nameid == skill_arrow_db[i].nameid) {
  8092. index = i;
  8093. break;
  8094. }
  8095. if(index < 0 || (j = pc_search_inventory(sd,nameid)) < 0)
  8096. return 1;
  8097. pc_delitem(sd,j,1,0);
  8098. for(i=0;i<5;i++) {
  8099. memset(&tmp_item,0,sizeof(tmp_item));
  8100. tmp_item.identify = 1;
  8101. tmp_item.nameid = skill_arrow_db[index].cre_id[i];
  8102. tmp_item.amount = skill_arrow_db[index].cre_amount[i];
  8103. if(battle_config.making_arrow_name_input) {
  8104. tmp_item.card[0]=0x00fe;
  8105. tmp_item.card[1]=0;
  8106. *((unsigned long *)(&tmp_item.card[2]))=sd->char_id; /* キャラID */
  8107. }
  8108. if(tmp_item.nameid <= 0 || tmp_item.amount <= 0)
  8109. continue;
  8110. if((flag = pc_additem(sd,&tmp_item,tmp_item.amount))) {
  8111. clif_additem(sd,0,0,flag);
  8112. map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
  8113. }
  8114. }
  8115. return 0;
  8116. }
  8117. /*----------------------------------------------------------------------------
  8118. * 初期化系
  8119. */
  8120. /*----------------------------------------------------------------------------
  8121. * 初期化系
  8122. */
  8123. /*
  8124. * 文字列処理
  8125. * ',' で区切って val に戻す
  8126. */
  8127. int skill_split_str(char *str,char **val,int num)
  8128. {
  8129. int i;
  8130. for (i=0; i<num && str; i++){
  8131. val[i] = str;
  8132. str = strchr(str,',');
  8133. if (str)
  8134. *str++=0;
  8135. }
  8136. return i;
  8137. }
  8138. /*
  8139. * 文字列処理
  8140. * ':' で区切ってatoiしてvalに戻す
  8141. */
  8142. int skill_split_atoi(char *str,int *val)
  8143. {
  8144. int i, max = 0;
  8145. for (i=0; i<MAX_SKILL_LEVEL; i++) {
  8146. if (str) {
  8147. val[i] = max = atoi(str);
  8148. str = strchr(str,':');
  8149. if (str)
  8150. *str++=0;
  8151. } else {
  8152. val[i] = max;
  8153. }
  8154. }
  8155. return i;
  8156. }
  8157. /*
  8158. * スキルユニットの配置情報作成
  8159. */
  8160. void skill_init_unit_layout()
  8161. {
  8162. int i,j,size,pos = 0;
  8163. memset(skill_unit_layout,0,sizeof(skill_unit_layout));
  8164. // 矩形のユニット配置を作成する
  8165. for (i=0; i<=MAX_SQUARE_LAYOUT; i++) {
  8166. size = i*2+1;
  8167. skill_unit_layout[i].count = size*size;
  8168. for (j=0; j<size*size; j++) {
  8169. skill_unit_layout[i].dx[j] = (j%size-i);
  8170. skill_unit_layout[i].dy[j] = (j/size-i);
  8171. }
  8172. }
  8173. pos = i;
  8174. // 矩形以外のユニット配置を作成する
  8175. for (i=0;i<MAX_SKILL_DB;i++) {
  8176. if (!skill_db[i].unit_id[0] || skill_db[i].unit_layout_type[0] != -1)
  8177. continue;
  8178. switch (i) {
  8179. case MG_FIREWALL:
  8180. case WZ_ICEWALL:
  8181. // ファイアーウォール、アイスウォールは方向で変わるので別処理
  8182. break;
  8183. case PR_SANCTUARY:
  8184. {
  8185. static const int dx[] = {
  8186. -1, 0, 1,-2,-1, 0, 1, 2,-2,-1,
  8187. 0, 1, 2,-2,-1, 0, 1, 2,-1, 0, 1};
  8188. static const int dy[]={
  8189. -2,-2,-2,-1,-1,-1,-1,-1, 0, 0,
  8190. 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2};
  8191. skill_unit_layout[pos].count = 21;
  8192. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8193. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8194. break;
  8195. }
  8196. case PR_MAGNUS:
  8197. {
  8198. static const int dx[] = {
  8199. -1, 0, 1,-1, 0, 1,-3,-2,-1, 0,
  8200. 1, 2, 3,-3,-2,-1, 0, 1, 2, 3,
  8201. -3,-2,-1, 0, 1, 2, 3,-1, 0, 1,-1, 0, 1};
  8202. static const int dy[] = {
  8203. -3,-3,-3,-2,-2,-2,-1,-1,-1,-1,
  8204. -1,-1,-1, 0, 0, 0, 0, 0, 0, 0,
  8205. 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3};
  8206. skill_unit_layout[pos].count = 33;
  8207. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8208. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8209. break;
  8210. }
  8211. case AS_VENOMDUST:
  8212. {
  8213. static const int dx[] = {-1, 0, 0, 0, 1};
  8214. static const int dy[] = { 0,-1, 0, 1, 0};
  8215. skill_unit_layout[pos].count = 5;
  8216. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8217. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8218. break;
  8219. }
  8220. case CR_GRANDCROSS:
  8221. case NPC_DARKGRANDCROSS:
  8222. {
  8223. static const int dx[] = {
  8224. 0, 0,-1, 0, 1,-2,-1, 0, 1, 2,
  8225. -4,-3,-2,-1, 0, 1, 2, 3, 4,-2,
  8226. -1, 0, 1, 2,-1, 0, 1, 0, 0};
  8227. static const int dy[] = {
  8228. -4,-3,-2,-2,-2,-1,-1,-1,-1,-1,
  8229. 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
  8230. 1, 1, 1, 1, 2, 2, 2, 3, 4};
  8231. skill_unit_layout[pos].count = 29;
  8232. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8233. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8234. break;
  8235. }
  8236. case PF_FOGWALL:
  8237. {
  8238. static const int dx[] = {
  8239. -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2};
  8240. static const int dy[] = {
  8241. -1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
  8242. skill_unit_layout[pos].count = 15;
  8243. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8244. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8245. break;
  8246. }
  8247. default:
  8248. printf("unknown unit layout at skill %d\n",i);
  8249. break;
  8250. }
  8251. if (!skill_unit_layout[pos].count)
  8252. continue;
  8253. for (j=0;j<MAX_SKILL_LEVEL;j++)
  8254. skill_db[i].unit_layout_type[j] = pos;
  8255. pos++;
  8256. }
  8257. // ファイヤーウォール
  8258. firewall_unit_pos = pos;
  8259. for (i=0;i<8;i++) {
  8260. if (i&1) { /* 斜め配置 */
  8261. skill_unit_layout[pos].count = 5;
  8262. if (i&0x2) {
  8263. int dx[] = {-1,-1, 0, 0, 1};
  8264. int dy[] = { 1, 0, 0,-1,-1};
  8265. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8266. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8267. } else {
  8268. int dx[] = { 1, 1 ,0, 0,-1};
  8269. int dy[] = { 1, 0, 0,-1,-1};
  8270. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8271. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8272. }
  8273. } else { /* 縦横配置 */
  8274. skill_unit_layout[pos].count = 3;
  8275. if (i%4==0) { /* 上下 */
  8276. int dx[] = {-1, 0, 1};
  8277. int dy[] = { 0, 0, 0};
  8278. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8279. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8280. } else { /* 左右 */
  8281. int dx[] = { 0, 0, 0};
  8282. int dy[] = {-1, 0, 1};
  8283. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8284. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8285. }
  8286. }
  8287. pos++;
  8288. }
  8289. // アイスウォール
  8290. icewall_unit_pos = pos;
  8291. for (i=0;i<8;i++) {
  8292. skill_unit_layout[pos].count = 5;
  8293. if (i&1) { /* 斜め配置 */
  8294. if (i&0x2) {
  8295. int dx[] = {-2,-1, 0, 1, 2};
  8296. int dy[] = { 2,-1, 0,-1,-2};
  8297. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8298. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8299. } else {
  8300. int dx[] = { 2, 1 ,0,-1,-2};
  8301. int dy[] = { 2, 1, 0,-1,-2};
  8302. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8303. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8304. }
  8305. } else { /* 縦横配置 */
  8306. if (i%4==0) { /* 上下 */
  8307. int dx[] = {-2,-1, 0, 1, 2};
  8308. int dy[] = { 0, 0, 0, 0, 0};
  8309. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8310. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8311. } else { /* 左右 */
  8312. int dx[] = { 0, 0, 0, 0, 0};
  8313. int dy[] = {-2,-1, 0, 1, 2};
  8314. memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
  8315. memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
  8316. }
  8317. }
  8318. pos++;
  8319. }
  8320. }
  8321. /*==========================================
  8322. * スキル?係ファイル?み?み
  8323. * skill_db.txt スキルデ?タ
  8324. * skill_cast_db.txt スキルの詠唱時間とディレイデ?タ
  8325. * produce_db.txt アイテム作成スキル用デ?タ
  8326. * create_arrow_db.txt 矢作成スキル用デ?タ
  8327. * abra_db.txt アブラカダブラ?動スキルデ?タ
  8328. *------------------------------------------
  8329. */
  8330. int skill_readdb(void)
  8331. {
  8332. int i,j,k,l,m;
  8333. FILE *fp;
  8334. char line[1024],*p;
  8335. char *filename[]={"db/produce_db.txt","db/produce_db2.txt"};
  8336. /* スキルデ?タベ?ス */
  8337. memset(skill_db,0,sizeof(skill_db));
  8338. fp=fopen("db/skill_db.txt","r");
  8339. if(fp==NULL){
  8340. printf("can't read db/skill_db.txt\n");
  8341. return 1;
  8342. }
  8343. while(fgets(line,1020,fp)){
  8344. char *split[50];
  8345. if(line[0]=='/' && line[1]=='/')
  8346. continue;
  8347. j = skill_split_str(line,split,14);
  8348. if(split[13]==NULL || j<14)
  8349. continue;
  8350. i=atoi(split[0]);
  8351. if (i>=10000 && i<10015) // for guild skills [Celest]
  8352. i -= 9500;
  8353. else if(i<=0 || i>MAX_SKILL_DB)
  8354. continue;
  8355. /* printf("skill id=%d\n",i); */
  8356. skill_split_atoi(split[1],skill_db[i].range);
  8357. skill_db[i].hit=atoi(split[2]);
  8358. skill_db[i].inf=atoi(split[3]);
  8359. skill_db[i].pl=atoi(split[4]);
  8360. skill_db[i].nk=atoi(split[5]);
  8361. skill_db[i].max=atoi(split[6]);
  8362. skill_split_atoi(split[7],skill_db[i].num);
  8363. if(strcmpi(split[8],"yes") == 0)
  8364. skill_db[i].castcancel=1;
  8365. else
  8366. skill_db[i].castcancel=0;
  8367. skill_db[i].cast_def_rate=atoi(split[9]);
  8368. skill_db[i].inf2=atoi(split[10]);
  8369. skill_db[i].maxcount=atoi(split[11]);
  8370. if(strcmpi(split[12],"weapon") == 0)
  8371. skill_db[i].skill_type=BF_WEAPON;
  8372. else if(strcmpi(split[12],"magic") == 0)
  8373. skill_db[i].skill_type=BF_MAGIC;
  8374. else if(strcmpi(split[12],"misc") == 0)
  8375. skill_db[i].skill_type=BF_MISC;
  8376. else
  8377. skill_db[i].skill_type=0;
  8378. skill_split_atoi(split[13],skill_db[i].blewcount);
  8379. }
  8380. fclose(fp);
  8381. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n","db/skill_db.txt");
  8382. ShowStatus(tmp_output);
  8383. fp=fopen("db/skill_require_db.txt","r");
  8384. if(fp==NULL){
  8385. printf("can't read db/skill_require_db.txt\n");
  8386. return 1;
  8387. }
  8388. while(fgets(line,1020,fp)){
  8389. char *split[50];
  8390. if(line[0]=='/' && line[1]=='/')
  8391. continue;
  8392. j = skill_split_str(line,split,30);
  8393. if(split[29]==NULL || j<30)
  8394. continue;
  8395. i=atoi(split[0]);
  8396. if (i>=10000 && i<10015) // for guild skills [Celest]
  8397. i -= 9500;
  8398. else if(i<=0 || i>MAX_SKILL_DB)
  8399. continue;
  8400. skill_split_atoi(split[1],skill_db[i].hp);
  8401. skill_split_atoi(split[2],skill_db[i].mhp);
  8402. skill_split_atoi(split[3],skill_db[i].sp);
  8403. skill_split_atoi(split[4],skill_db[i].hp_rate);
  8404. skill_split_atoi(split[5],skill_db[i].sp_rate);
  8405. skill_split_atoi(split[6],skill_db[i].zeny);
  8406. p = split[7];
  8407. for(j=0;j<32;j++){
  8408. l = atoi(p);
  8409. if (l==99) {
  8410. skill_db[i].weapon = 0xffffffff;
  8411. break;
  8412. }
  8413. else
  8414. skill_db[i].weapon |= 1<<l;
  8415. p=strchr(p,':');
  8416. if(!p)
  8417. break;
  8418. p++;
  8419. }
  8420. if( strcmpi(split[8],"hiding")==0 ) skill_db[i].state=ST_HIDING;
  8421. else if( strcmpi(split[8],"cloaking")==0 ) skill_db[i].state=ST_CLOAKING;
  8422. else if( strcmpi(split[8],"hidden")==0 ) skill_db[i].state=ST_HIDDEN;
  8423. else if( strcmpi(split[8],"riding")==0 ) skill_db[i].state=ST_RIDING;
  8424. else if( strcmpi(split[8],"falcon")==0 ) skill_db[i].state=ST_FALCON;
  8425. else if( strcmpi(split[8],"cart")==0 ) skill_db[i].state=ST_CART;
  8426. else if( strcmpi(split[8],"shield")==0 ) skill_db[i].state=ST_SHIELD;
  8427. else if( strcmpi(split[8],"sight")==0 ) skill_db[i].state=ST_SIGHT;
  8428. else if( strcmpi(split[8],"explosionspirits")==0 ) skill_db[i].state=ST_EXPLOSIONSPIRITS;
  8429. else if( strcmpi(split[8],"recover_weight_rate")==0 ) skill_db[i].state=ST_RECOV_WEIGHT_RATE;
  8430. else if( strcmpi(split[8],"move_enable")==0 ) skill_db[i].state=ST_MOVE_ENABLE;
  8431. else if( strcmpi(split[8],"water")==0 ) skill_db[i].state=ST_WATER;
  8432. else skill_db[i].state=ST_NONE;
  8433. skill_split_atoi(split[9],skill_db[i].spiritball);
  8434. skill_db[i].itemid[0]=atoi(split[10]);
  8435. skill_db[i].amount[0]=atoi(split[11]);
  8436. skill_db[i].itemid[1]=atoi(split[12]);
  8437. skill_db[i].amount[1]=atoi(split[13]);
  8438. skill_db[i].itemid[2]=atoi(split[14]);
  8439. skill_db[i].amount[2]=atoi(split[15]);
  8440. skill_db[i].itemid[3]=atoi(split[16]);
  8441. skill_db[i].amount[3]=atoi(split[17]);
  8442. skill_db[i].itemid[4]=atoi(split[18]);
  8443. skill_db[i].amount[4]=atoi(split[19]);
  8444. skill_db[i].itemid[5]=atoi(split[20]);
  8445. skill_db[i].amount[5]=atoi(split[21]);
  8446. skill_db[i].itemid[6]=atoi(split[22]);
  8447. skill_db[i].amount[6]=atoi(split[23]);
  8448. skill_db[i].itemid[7]=atoi(split[24]);
  8449. skill_db[i].amount[7]=atoi(split[25]);
  8450. skill_db[i].itemid[8]=atoi(split[26]);
  8451. skill_db[i].amount[8]=atoi(split[27]);
  8452. skill_db[i].itemid[9]=atoi(split[28]);
  8453. skill_db[i].amount[9]=atoi(split[29]);
  8454. }
  8455. fclose(fp);
  8456. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n","db/skill_require_db.txt");
  8457. ShowStatus(tmp_output);
  8458. /* キャスティングデ?タベ?ス */
  8459. fp=fopen("db/skill_cast_db.txt","r");
  8460. if(fp==NULL){
  8461. printf("can't read db/skill_cast_db.txt\n");
  8462. return 1;
  8463. }
  8464. while(fgets(line,1020,fp)){
  8465. char *split[50];
  8466. memset(split,0,sizeof(split)); // [Valaris] thanks to fov
  8467. if(line[0]=='/' && line[1]=='/')
  8468. continue;
  8469. j = skill_split_str(line,split,5);
  8470. if(split[4]==NULL || j<5)
  8471. continue;
  8472. i=atoi(split[0]);
  8473. if (i>=10000 && i<10015) // for guild skills [Celest]
  8474. i -= 9500;
  8475. else if(i<=0 || i>MAX_SKILL_DB)
  8476. continue;
  8477. skill_split_atoi(split[1],skill_db[i].cast);
  8478. skill_split_atoi(split[2],skill_db[i].delay);
  8479. skill_split_atoi(split[3],skill_db[i].upkeep_time);
  8480. skill_split_atoi(split[4],skill_db[i].upkeep_time2);
  8481. }
  8482. fclose(fp);
  8483. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n","db/skill_cast_db.txt");
  8484. ShowStatus(tmp_output);
  8485. /* スキルユニットデータベース */
  8486. fp = fopen("db/skill_unit_db.txt","r");
  8487. if (fp==NULL) {
  8488. printf("can't read db/skill_unit_db.txt\n");
  8489. return 1;
  8490. }
  8491. while (fgets(line,1020,fp)) {
  8492. char *split[50];
  8493. if (line[0]=='/' && line[1]=='/')
  8494. continue;
  8495. j = skill_split_str(line,split,8);
  8496. if (split[7]==NULL || j<8)
  8497. continue;
  8498. i=atoi(split[0]);
  8499. if (i>=10000 && i<10015) // for guild skills [Celest]
  8500. i -= 9500;
  8501. else if(i<=0 || i>MAX_SKILL_DB)
  8502. continue;
  8503. skill_db[i].unit_id[0] = strtol(split[1],NULL,16);
  8504. skill_db[i].unit_id[1] = strtol(split[2],NULL,16);
  8505. skill_split_atoi(split[3],skill_db[i].unit_layout_type);
  8506. skill_db[i].unit_range = atoi(split[4]);
  8507. skill_db[i].unit_interval = atoi(split[5]);
  8508. if( strcmpi(split[6],"noenemy")==0 ) skill_db[i].unit_target=BCT_NOENEMY;
  8509. else if( strcmpi(split[6],"friend")==0 ) skill_db[i].unit_target=BCT_NOENEMY;
  8510. else if( strcmpi(split[6],"party")==0 ) skill_db[i].unit_target=BCT_PARTY;
  8511. else if( strcmpi(split[6],"all")==0 ) skill_db[i].unit_target=BCT_ALL;
  8512. else if( strcmpi(split[6],"enemy")==0 ) skill_db[i].unit_target=BCT_ENEMY;
  8513. else if( strcmpi(split[6],"self")==0 ) skill_db[i].unit_target=BCT_SELF;
  8514. else skill_db[i].unit_target = strtol(split[6],NULL,16);
  8515. skill_db[i].unit_flag = strtol(split[7],NULL,16);
  8516. k++;
  8517. }
  8518. fclose(fp);
  8519. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n","db/skill_unit_db.txt");
  8520. ShowStatus(tmp_output);
  8521. skill_init_unit_layout();
  8522. /* 製造系スキルデ?タベ?ス */
  8523. memset(skill_produce_db,0,sizeof(skill_produce_db));
  8524. for(m=0;m<2;m++){
  8525. fp=fopen(filename[m],"r");
  8526. if(fp==NULL){
  8527. if(m>0)
  8528. continue;
  8529. printf("can't read %s\n",filename[m]);
  8530. return 1;
  8531. }
  8532. k=0;
  8533. while(fgets(line,1020,fp)){
  8534. char *split[6 + MAX_PRODUCE_RESOURCE * 2];
  8535. int x,y;
  8536. if(line[0]=='/' && line[1]=='/')
  8537. continue;
  8538. memset(split,0,sizeof(split));
  8539. j = skill_split_str(line,split,(3 + MAX_PRODUCE_RESOURCE * 2));
  8540. if(split[0]==0) //fixed by Lupus
  8541. continue;
  8542. i=atoi(split[0]);
  8543. if(i<=0) continue;
  8544. skill_produce_db[k].nameid=i;
  8545. skill_produce_db[k].itemlv=atoi(split[1]);
  8546. skill_produce_db[k].req_skill=atoi(split[2]);
  8547. for(x=3,y=0; split[x] && split[x+1] && y<MAX_PRODUCE_RESOURCE; x+=2,y++){
  8548. skill_produce_db[k].mat_id[y]=atoi(split[x]);
  8549. skill_produce_db[k].mat_amount[y]=atoi(split[x+1]);
  8550. }
  8551. k++;
  8552. if(k >= MAX_SKILL_PRODUCE_DB)
  8553. break;
  8554. }
  8555. fclose(fp);
  8556. sprintf(tmp_output,"Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",k,filename[m]);
  8557. ShowStatus(tmp_output);
  8558. }
  8559. memset(skill_arrow_db,0,sizeof(skill_arrow_db));
  8560. fp=fopen("db/create_arrow_db.txt","r");
  8561. if(fp==NULL){
  8562. printf("can't read db/create_arrow_db.txt\n");
  8563. return 1;
  8564. }
  8565. k=0;
  8566. while(fgets(line,1020,fp)){
  8567. char *split[16];
  8568. int x,y;
  8569. if(line[0]=='/' && line[1]=='/')
  8570. continue;
  8571. memset(split,0,sizeof(split));
  8572. j = skill_split_str(line,split,13);
  8573. if(split[0]==0) //fixed by Lupus
  8574. continue;
  8575. i=atoi(split[0]);
  8576. if(i<=0)
  8577. continue;
  8578. skill_arrow_db[k].nameid=i;
  8579. for(x=1,y=0;split[x] && split[x+1] && y<5;x+=2,y++){
  8580. skill_arrow_db[k].cre_id[y]=atoi(split[x]);
  8581. skill_arrow_db[k].cre_amount[y]=atoi(split[x+1]);
  8582. }
  8583. k++;
  8584. if(k >= MAX_SKILL_ARROW_DB)
  8585. break;
  8586. }
  8587. fclose(fp);
  8588. sprintf(tmp_output,"Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",k,"db/create_arrow_db.txt");
  8589. ShowStatus(tmp_output);
  8590. memset(skill_abra_db,0,sizeof(skill_abra_db));
  8591. fp=fopen("db/abra_db.txt","r");
  8592. if(fp==NULL){
  8593. printf("can't read db/abra_db.txt\n");
  8594. return 1;
  8595. }
  8596. k=0;
  8597. while(fgets(line,1020,fp)){
  8598. char *split[16];
  8599. if(line[0]=='/' && line[1]=='/')
  8600. continue;
  8601. memset(split,0,sizeof(split));
  8602. j = skill_split_str(line,split,13);
  8603. if(split[0]==0) //fixed by Lupus
  8604. continue;
  8605. i=atoi(split[0]);
  8606. if(i<=0)
  8607. continue;
  8608. skill_abra_db[i].req_lv=atoi(split[2]);
  8609. skill_abra_db[i].per=atoi(split[3]);
  8610. k++;
  8611. if(k >= MAX_SKILL_ABRA_DB)
  8612. break;
  8613. }
  8614. fclose(fp);
  8615. sprintf(tmp_output,"Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",k,"db/abra_db.txt");
  8616. ShowStatus(tmp_output);
  8617. fp=fopen("db/skill_castnodex_db.txt","r");
  8618. if(fp==NULL){
  8619. printf("can't read db/skill_castnodex_db.txt\n");
  8620. return 1;
  8621. }
  8622. while(fgets(line,1020,fp)){
  8623. char *split[50];
  8624. if(line[0]=='/' && line[1]=='/')
  8625. continue;
  8626. memset(split,0,sizeof(split));
  8627. j = skill_split_str(line,split,3);
  8628. if(split[0]==0) //fixed by Lupus
  8629. continue;
  8630. i=atoi(split[0]);
  8631. if (i>=10000 && i<10015) // for guild skills [Celest]
  8632. i -= 9500;
  8633. else if(i<=0 || i>MAX_SKILL_DB)
  8634. continue;
  8635. skill_split_atoi(split[1],skill_db[i].castnodex);
  8636. if (!split[2])
  8637. continue;
  8638. skill_split_atoi(split[2],skill_db[i].delaynodex);
  8639. }
  8640. fclose(fp);
  8641. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n","db/skill_castnodex_db.txt");
  8642. ShowStatus(tmp_output);
  8643. fp=fopen("db/skill_nocast_db.txt","r");
  8644. if(fp==NULL){
  8645. printf("can't read db/skill_nocast_db.txt\n");
  8646. return 1;
  8647. }
  8648. k=0;
  8649. while(fgets(line,1020,fp)){
  8650. char *split[16];
  8651. if(line[0]=='/' && line[1]=='/')
  8652. continue;
  8653. memset(split,0,sizeof(split));
  8654. j = skill_split_str(line,split,2);
  8655. if(split[0]==0) //fixed by Lupus
  8656. continue;
  8657. i=atoi(split[0]);
  8658. if (i>=10000 && i<10015) // for guild skills [Celest]
  8659. i -= 9500;
  8660. else if(i<=0 || i>MAX_SKILL_DB)
  8661. continue;
  8662. skill_db[i].nocast=atoi(split[1]);
  8663. k++;
  8664. }
  8665. fclose(fp);
  8666. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n","db/skill_nocast_db");
  8667. ShowStatus(tmp_output);
  8668. return 0;
  8669. }
  8670. /*===============================================
  8671. * For reading leveluseskillspamount.txt [Celest]
  8672. *-----------------------------------------------
  8673. */
  8674. static int skill_read_skillspamount(void)
  8675. {
  8676. char *buf,*p;
  8677. struct skill_db *skill = NULL;
  8678. int s, idx, new_flag=1, level=1, sp=0;
  8679. buf=grfio_reads("data\\leveluseskillspamount.txt",&s);
  8680. if(buf==NULL)
  8681. return -1;
  8682. buf[s]=0;
  8683. for(p=buf;p-buf<s;){
  8684. char buf2[64];
  8685. if (sscanf(p,"%[@]",buf2) == 1) {
  8686. level = 1;
  8687. new_flag = 1;
  8688. } else if (new_flag && sscanf(p,"%[^#]#",buf2) == 1) {
  8689. for (idx=0; skill_names[idx].id != 0; idx++) {
  8690. if (strstr(buf2, skill_names[idx].name) != NULL) {
  8691. skill = &skill_db[ skill_names[idx].id ];
  8692. new_flag = 0;
  8693. break;
  8694. }
  8695. }
  8696. } else if (!new_flag && sscanf(p,"%d#",&sp) == 1) {
  8697. skill->sp[level-1]=sp;
  8698. level++;
  8699. }
  8700. p=strchr(p,10);
  8701. if(!p) break;
  8702. p++;
  8703. }
  8704. aFree(buf);
  8705. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n","data\\leveluseskillspamount.txt");
  8706. ShowStatus(tmp_output);
  8707. return 0;
  8708. }
  8709. void skill_reload(void)
  8710. {
  8711. /*
  8712. <empty skill database>
  8713. <?>
  8714. */
  8715. do_init_skill();
  8716. }
  8717. /*==========================================
  8718. * スキル?係初期化?理
  8719. *------------------------------------------
  8720. */
  8721. int do_init_skill(void)
  8722. {
  8723. skill_readdb();
  8724. if (battle_config.skill_sp_override_grffile)
  8725. skill_read_skillspamount();
  8726. add_timer_func_list(skill_unit_timer,"skill_unit_timer");
  8727. add_timer_func_list(skill_castend_id,"skill_castend_id");
  8728. add_timer_func_list(skill_castend_pos,"skill_castend_pos");
  8729. add_timer_func_list(skill_timerskill,"skill_timerskill");
  8730. add_timer_interval(gettick()+SKILLUNITTIMER_INVERVAL,skill_unit_timer,0,0,SKILLUNITTIMER_INVERVAL);
  8731. return 0;
  8732. }