mob.c 119 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419
  1. // $Id: mob.c,v 1.7 2004/09/25 05:32:18 MouseJstr Exp $
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdarg.h>
  5. #include <string.h>
  6. #include "timer.h"
  7. #include "socket.h"
  8. #include "db.h"
  9. #include "nullpo.h"
  10. #include "malloc.h"
  11. #include "map.h"
  12. #include "clif.h"
  13. #include "intif.h"
  14. #include "pc.h"
  15. #include "mob.h"
  16. #include "guild.h"
  17. #include "itemdb.h"
  18. #include "skill.h"
  19. #include "battle.h"
  20. #include "party.h"
  21. #include "npc.h"
  22. #include "log.h"
  23. #include "showmsg.h"
  24. #ifdef MEMWATCH
  25. #include "memwatch.h"
  26. #endif
  27. #define MIN_MOBTHINKTIME 100
  28. #define MOB_LAZYMOVEPERC 50 // Move probability in the negligent mode MOB (rate of 1000 minute)
  29. #define MOB_LAZYWARPPERC 20 // Warp probability in the negligent mode MOB (rate of 1000 minute)
  30. #define MAX_MOB_DB 2000 /* Change this to increase the table size in your mob_db to accomodate
  31. numbers more than 2000 for mobs if you want to (and know what you're doing).
  32. Be sure to note that 4001 to 4047 are for advanced classes. */
  33. struct mob_db mob_db[2001];
  34. #define CLASSCHANGE_BOSS_NUM 21
  35. /*==========================================
  36. * Local prototype declaration (only required thing)
  37. *------------------------------------------
  38. */
  39. static int distance(int,int,int,int);
  40. static int mob_makedummymobdb(int);
  41. static int mob_timer(int,unsigned int,int,int);
  42. int mobskill_use(struct mob_data *md,unsigned int tick,int event);
  43. int mobskill_deltimer(struct mob_data *md );
  44. int mob_skillid2skillidx(int class,int skillid);
  45. int mobskill_use_id(struct mob_data *md,struct block_list *target,int skill_idx);
  46. static int mob_unlocktarget(struct mob_data *md,int tick);
  47. /*==========================================
  48. * Mob is searched with a name.
  49. *------------------------------------------
  50. */
  51. int mobdb_searchname(const char *str)
  52. {
  53. int i;
  54. for(i=0;i<sizeof(mob_db)/sizeof(mob_db[0]);i++){
  55. if( strcmpi(mob_db[i].name,str)==0 || strcmp(mob_db[i].jname,str)==0 ||
  56. memcmp(mob_db[i].name,str,24)==0 || memcmp(mob_db[i].jname,str,24)==0)
  57. return i;
  58. }
  59. return 0;
  60. }
  61. /*==========================================
  62. * Id Mob is checked.
  63. *------------------------------------------
  64. */
  65. int mobdb_checkid(const int id)
  66. {
  67. if (id <= 0 || id >= (sizeof(mob_db) / sizeof(mob_db[0])) || mob_db[id].name[0] == '\0')
  68. return 0;
  69. return id;
  70. }
  71. /*==========================================
  72. * The minimum data set for MOB spawning
  73. *------------------------------------------
  74. */
  75. int mob_spawn_dataset(struct mob_data *md,const char *mobname,int class)
  76. {
  77. nullpo_retr(0, md);
  78. md->bl.prev=NULL;
  79. md->bl.next=NULL;
  80. if(strcmp(mobname,"--en--")==0)
  81. memcpy(md->name,mob_db[class].name,24);
  82. else if(strcmp(mobname,"--ja--")==0)
  83. memcpy(md->name,mob_db[class].jname,24);
  84. else
  85. memcpy(md->name,mobname,24);
  86. md->n = 0;
  87. md->base_class = md->class = class;
  88. md->bl.id= npc_get_new_npc_id();
  89. memset(&md->state,0,sizeof(md->state));
  90. md->timer = -1;
  91. md->target_id=0;
  92. md->attacked_id=0;
  93. md->speed=mob_db[class].speed;
  94. return 0;
  95. }
  96. /*==========================================
  97. * The MOB appearance for one time (for scripts)
  98. *------------------------------------------
  99. */
  100. int mob_once_spawn(struct map_session_data *sd,char *mapname,
  101. int x,int y,const char *mobname,int class,int amount,const char *event)
  102. {
  103. struct mob_data *md=NULL;
  104. int m,count,lv=255,r=class;
  105. if( sd )
  106. lv=sd->status.base_level;
  107. if( sd && strcmp(mapname,"this")==0)
  108. m=sd->bl.m;
  109. else
  110. m=map_mapname2mapid(mapname);
  111. if(m<0 || amount<=0 || (class>=0 && class<=1000) || class>6000) // 値が異常なら召喚を止める
  112. return 0;
  113. if(class<0){ // ランダムに召喚
  114. int i=0;
  115. int j=-class-1;
  116. int k;
  117. if(j>=0 && j<MAX_RANDOMMONSTER){
  118. do{
  119. class=rand()%1000+1001;
  120. k=rand()%1000000;
  121. }while((mob_db[class].max_hp <= 0 || mob_db[class].summonper[j] <= k ||
  122. (lv<mob_db[class].lv && battle_config.random_monster_checklv)) && (i++) < 2000);
  123. if(i>=2000){
  124. class=mob_db[0].summonper[j];
  125. }
  126. }else{
  127. return 0;
  128. }
  129. // if(battle_config.etc_log)
  130. // printf("mobclass=%d try=%d\n",class,i);
  131. }
  132. if(sd){
  133. if(x<=0) x=sd->bl.x;
  134. if(y<=0) y=sd->bl.y;
  135. }else if(x<=0 || y<=0){
  136. printf("mob_once_spawn: ??\n");
  137. }
  138. for(count=0;count<amount;count++){
  139. md=(struct mob_data *)aCalloc(1,sizeof(struct mob_data));
  140. memset(md, '\0', sizeof *md);
  141. if(class>4000) { // large/tiny mobs [Valaris]
  142. md->size=2;
  143. class-=4000;
  144. }
  145. else if(class>MAX_MOB_DB) {
  146. md->size=1;
  147. class-=MAX_MOB_DB;
  148. }
  149. if(mob_db[class].mode&0x02)
  150. md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
  151. else
  152. md->lootitem=NULL;
  153. mob_spawn_dataset(md,mobname,class);
  154. md->bl.m=m;
  155. md->bl.x=x;
  156. md->bl.y=y;
  157. if(r<0&&battle_config.dead_branch_active) md->mode=0x1+0x4+0x80; //移動してアクティブで反撃する
  158. md->m =m;
  159. md->x0=x;
  160. md->y0=y;
  161. md->xs=0;
  162. md->ys=0;
  163. md->spawndelay1=-1; // 一度のみフラグ
  164. md->spawndelay2=-1; // 一度のみフラグ
  165. memcpy(md->npc_event,event,strlen(event));
  166. md->bl.type=BL_MOB;
  167. map_addiddb(&md->bl);
  168. mob_spawn(md->bl.id);
  169. if(class==1288) { // emperium hp based on defense level [Valaris]
  170. struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
  171. if(gc) {
  172. mob_db[class].max_hp+=2000*gc->defense;
  173. md->hp=mob_db[class].max_hp;
  174. }
  175. } // end addition [Valaris]
  176. }
  177. return (amount>0)?md->bl.id:0;
  178. }
  179. /*==========================================
  180. * The MOB appearance for one time (& area specification for scripts)
  181. *------------------------------------------
  182. */
  183. int mob_once_spawn_area(struct map_session_data *sd,char *mapname,
  184. int x0,int y0,int x1,int y1,
  185. const char *mobname,int class,int amount,const char *event)
  186. {
  187. int x,y,i,max,lx=-1,ly=-1,id=0;
  188. int m;
  189. if(strcmp(mapname,"this")==0)
  190. m=sd->bl.m;
  191. else
  192. m=map_mapname2mapid(mapname);
  193. max=(y1-y0+1)*(x1-x0+1)*3;
  194. if(max>1000)max=1000;
  195. if(m<0 || amount<=0 || (class>=0 && class<=1000) || class>6000) // A summon is stopped if a value is unusual
  196. return 0;
  197. for(i=0;i<amount;i++){
  198. int j=0;
  199. do{
  200. x=rand()%(x1-x0+1)+x0;
  201. y=rand()%(y1-y0+1)+y0;
  202. } while (map_getcell(m,x,y,CELL_CHKNOPASS) && (++j)<max);
  203. if(j>=max){
  204. if(lx>=0){ // 検索に失敗したので以前に沸いた場所を使う
  205. x=lx;
  206. y=ly;
  207. }else
  208. return 0; // 最初に沸く場所の検索を失敗したのでやめる
  209. }
  210. if(x==0||y==0) printf("xory=0, x=%d,y=%d,x0=%d,y0=%d\n",x,y,x0,y0);
  211. id=mob_once_spawn(sd,mapname,x,y,mobname,class,1,event);
  212. lx=x;
  213. ly=y;
  214. }
  215. return id;
  216. }
  217. /*==========================================
  218. * Summoning Guardians [Valaris]
  219. *------------------------------------------
  220. */
  221. int mob_spawn_guardian(struct map_session_data *sd,char *mapname,
  222. int x,int y,const char *mobname,int class,int amount,const char *event,int guardian)
  223. {
  224. struct mob_data *md=NULL;
  225. int m,count=1,lv=255;
  226. if( sd )
  227. lv=sd->status.base_level;
  228. if( sd && strcmp(mapname,"this")==0)
  229. m=sd->bl.m;
  230. else
  231. m=map_mapname2mapid(mapname);
  232. if(m<0 || amount<=0 || (class>=0 && class<=1000) || class>MAX_MOB_DB) // Invalid monster classes
  233. return 0;
  234. if(class<0)
  235. return 0;
  236. if(sd){
  237. if(x<=0) x=sd->bl.x;
  238. if(y<=0) y=sd->bl.y;
  239. }
  240. else if(x<=0 || y<=0)
  241. printf("mob_spawn_guardian: ??\n");
  242. for(count=0;count<amount;count++){
  243. struct guild_castle *gc;
  244. md=calloc(sizeof(struct mob_data), 1);
  245. if(md==NULL){
  246. printf("mob_spawn_guardian: out of memory !\n");
  247. exit(1);
  248. }
  249. memset(md, '\0', sizeof *md);
  250. mob_spawn_dataset(md,mobname,class);
  251. md->bl.m=m;
  252. md->bl.x=x;
  253. md->bl.y=y;
  254. md->m =m;
  255. md->x0=x;
  256. md->y0=y;
  257. md->xs=0;
  258. md->ys=0;
  259. md->spawndelay1=-1; // Only once is a flag.
  260. md->spawndelay2=-1; // Only once is a flag.
  261. memcpy(md->npc_event,event,sizeof(md->npc_event));
  262. md->bl.type=BL_MOB;
  263. map_addiddb(&md->bl);
  264. mob_spawn(md->bl.id);
  265. gc=guild_mapname2gc(map[md->bl.m].name);
  266. if(gc) {
  267. mob_db[class].max_hp+=2000*gc->defense;
  268. if(guardian==0) { md->hp=gc->Ghp0; gc->GID0=md->bl.id; }
  269. if(guardian==1) { md->hp=gc->Ghp1; gc->GID1=md->bl.id; }
  270. if(guardian==2) { md->hp=gc->Ghp2; gc->GID2=md->bl.id; }
  271. if(guardian==3) { md->hp=gc->Ghp3; gc->GID3=md->bl.id; }
  272. if(guardian==4) { md->hp=gc->Ghp4; gc->GID4=md->bl.id; }
  273. if(guardian==5) { md->hp=gc->Ghp5; gc->GID5=md->bl.id; }
  274. if(guardian==6) { md->hp=gc->Ghp6; gc->GID6=md->bl.id; }
  275. if(guardian==7) { md->hp=gc->Ghp7; gc->GID7=md->bl.id; }
  276. }
  277. }
  278. return (amount>0)?md->bl.id:0;
  279. }
  280. /*==========================================
  281. * The disregard ID is added to mob.
  282. *------------------------------------------
  283. */
  284. int mob_exclusion_add(struct mob_data *md,int type,int id)
  285. {
  286. nullpo_retr(0, md);
  287. if(type==1)
  288. md->exclusion_src=id;
  289. if(type==2)
  290. md->exclusion_party=id;
  291. if(type==3)
  292. md->exclusion_guild=id;
  293. return 0;
  294. }
  295. /*==========================================
  296. * The disregard ID of mob is checked. (TAGE?)
  297. *------------------------------------------
  298. */
  299. int mob_exclusion_check(struct mob_data *md,struct map_session_data *sd)
  300. {
  301. nullpo_retr(0, sd);
  302. nullpo_retr(0, md);
  303. if(sd->bl.type==BL_PC){
  304. if(md->exclusion_src && md->exclusion_src==sd->bl.id)
  305. return 1;
  306. if(md->exclusion_party && md->exclusion_party==sd->status.party_id)
  307. return 2;
  308. if(md->exclusion_guild && md->exclusion_guild==sd->status.guild_id)
  309. return 3;
  310. }
  311. return 0;
  312. }
  313. /*==========================================
  314. * Appearance income of mob
  315. *------------------------------------------
  316. */
  317. int mob_get_viewclass(int class)
  318. {
  319. return mob_db[class].view_class;
  320. }
  321. int mob_get_sex(int class)
  322. {
  323. return mob_db[class].sex;
  324. }
  325. short mob_get_hair(int class)
  326. {
  327. return mob_db[class].hair;
  328. }
  329. short mob_get_hair_color(int class)
  330. {
  331. return mob_db[class].hair_color;
  332. }
  333. short mob_get_weapon(int class)
  334. {
  335. return mob_db[class].weapon;
  336. }
  337. short mob_get_shield(int class)
  338. {
  339. return mob_db[class].shield;
  340. }
  341. short mob_get_head_top(int class)
  342. {
  343. return mob_db[class].head_top;
  344. }
  345. short mob_get_head_mid(int class)
  346. {
  347. return mob_db[class].head_mid;
  348. }
  349. short mob_get_head_buttom(int class)
  350. {
  351. return mob_db[class].head_buttom;
  352. }
  353. short mob_get_clothes_color(int class) // Add for player monster dye - Valaris
  354. {
  355. return mob_db[class].clothes_color; // End
  356. }
  357. int mob_get_equip(int class) // mob equip [Valaris]
  358. {
  359. return mob_db[class].equip;
  360. }
  361. /*==========================================
  362. * Is MOB in the state in which the present movement is possible or not?
  363. *------------------------------------------
  364. */
  365. int mob_can_move(struct mob_data *md)
  366. {
  367. nullpo_retr(0, md);
  368. if(md->canmove_tick > gettick() || (md->opt1 > 0 && md->opt1 != 6) || md->option&2)
  369. return 0;
  370. // アンクル中で動けないとか
  371. if( md->sc_data[SC_ANKLE].timer != -1 || //アンクルスネア
  372. md->sc_data[SC_AUTOCOUNTER].timer != -1 || //オートカウンター
  373. md->sc_data[SC_BLADESTOP].timer != -1 || //白刃取り
  374. md->sc_data[SC_SPIDERWEB].timer != -1 //スパイダーウェッブ
  375. )
  376. return 0;
  377. return 1;
  378. }
  379. /*==========================================
  380. * Time calculation concerning one step next to mob
  381. *------------------------------------------
  382. */
  383. static int calc_next_walk_step(struct mob_data *md)
  384. {
  385. nullpo_retr(0, md);
  386. if(md->walkpath.path_pos>=md->walkpath.path_len)
  387. return -1;
  388. if(md->walkpath.path[md->walkpath.path_pos]&1)
  389. return battle_get_speed(&md->bl)*14/10;
  390. return battle_get_speed(&md->bl);
  391. }
  392. static int mob_walktoxy_sub(struct mob_data *md);
  393. /*==========================================
  394. * Mob Walk processing
  395. *------------------------------------------
  396. */
  397. static int mob_walk(struct mob_data *md,unsigned int tick,int data)
  398. {
  399. int moveblock;
  400. int i;
  401. static int dirx[8]={0,-1,-1,-1,0,1,1,1};
  402. static int diry[8]={1,1,0,-1,-1,-1,0,1};
  403. int x,y,dx,dy;
  404. nullpo_retr(0, md);
  405. md->state.state=MS_IDLE;
  406. if(md->walkpath.path_pos>=md->walkpath.path_len || md->walkpath.path_pos!=data)
  407. return 0;
  408. md->walkpath.path_half ^= 1;
  409. if(md->walkpath.path_half==0){
  410. md->walkpath.path_pos++;
  411. if(md->state.change_walk_target){
  412. mob_walktoxy_sub(md);
  413. return 0;
  414. }
  415. }
  416. else {
  417. if(md->walkpath.path[md->walkpath.path_pos]>=8)
  418. return 1;
  419. x = md->bl.x;
  420. y = md->bl.y;
  421. if(map_getcell(md->bl.m,x,y,CELL_CHKNOPASS)) {
  422. mob_stop_walking(md,1);
  423. return 0;
  424. }
  425. md->dir=md->walkpath.path[md->walkpath.path_pos];
  426. dx = dirx[md->dir];
  427. dy = diry[md->dir];
  428. if(map_getcell(md->bl.m,x+dx,y+dy,CELL_CHKNOPASS)) {
  429. mob_walktoxy_sub(md);
  430. return 0;
  431. }
  432. if (skill_check_basilica (&md->bl,x+dx,y+dy) ||
  433. skill_check_moonlit (&md->bl,x+dx,y+dy)) {
  434. mob_walktoxy_sub(md);
  435. return 0;
  436. }
  437. moveblock = ( x/BLOCK_SIZE != (x+dx)/BLOCK_SIZE || y/BLOCK_SIZE != (y+dy)/BLOCK_SIZE);
  438. md->state.state=MS_WALK;
  439. map_foreachinmovearea(clif_moboutsight,md->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,md);
  440. x += dx;
  441. y += dy;
  442. if(md->min_chase>13)
  443. md->min_chase--;
  444. if(moveblock) map_delblock(&md->bl);
  445. md->bl.x = x;
  446. md->bl.y = y;
  447. if(moveblock) map_addblock(&md->bl);
  448. map_foreachinmovearea(clif_mobinsight,md->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,md);
  449. md->state.state=MS_IDLE;
  450. if(md->option&4)
  451. skill_check_cloaking(&md->bl);
  452. skill_unit_move(&md->bl,tick,1); // スキルユニットの検査
  453. }
  454. if((i=calc_next_walk_step(md))>0){
  455. i = i>>1;
  456. if(i < 1 && md->walkpath.path_half == 0)
  457. i = 1;
  458. md->timer=add_timer(tick+i,mob_timer,md->bl.id,md->walkpath.path_pos);
  459. md->state.state=MS_WALK;
  460. if(md->walkpath.path_pos>=md->walkpath.path_len)
  461. clif_fixmobpos(md); // とまったときに位置の再送信
  462. }
  463. return 0;
  464. }
  465. /*==========================================
  466. * Attack processing of mob
  467. *------------------------------------------
  468. */
  469. static int mob_attack(struct mob_data *md,unsigned int tick,int data)
  470. {
  471. struct block_list *tbl=NULL;
  472. struct map_session_data *tsd=NULL;
  473. struct mob_data *tmd=NULL;
  474. int mode,race,range;
  475. nullpo_retr(0, md);
  476. md->min_chase=13;
  477. md->state.state=MS_IDLE;
  478. md->state.skillstate=MSS_IDLE;
  479. if( md->skilltimer!=-1 ) // スキル使用中
  480. return 0;
  481. if(md->opt1>0 || md->option&2)
  482. return 0;
  483. if(md->sc_data[SC_AUTOCOUNTER].timer != -1)
  484. return 0;
  485. if(md->sc_data[SC_BLADESTOP].timer != -1)
  486. return 0;
  487. if((tbl=map_id2bl(md->target_id))==NULL){
  488. md->target_id=0;
  489. md->state.targettype = NONE_ATTACKABLE;
  490. return 0;
  491. }
  492. if(tbl->type==BL_PC)
  493. tsd=(struct map_session_data *)tbl;
  494. else if(tbl->type==BL_MOB)
  495. tmd=(struct mob_data *)tbl;
  496. else
  497. return 0;
  498. if(tsd){
  499. if( pc_isdead(tsd) || tsd->invincible_timer != -1 || pc_isinvisible(tsd) || md->bl.m != tbl->m || tbl->prev == NULL || distance(md->bl.x,md->bl.y,tbl->x,tbl->y)>=13 ){
  500. md->target_id=0;
  501. md->state.targettype = NONE_ATTACKABLE;
  502. return 0;
  503. }
  504. }
  505. if(tmd){
  506. if(md->bl.m != tbl->m || tbl->prev == NULL || distance(md->bl.x,md->bl.y,tbl->x,tbl->y)>=13){
  507. md->target_id=0;
  508. md->state.targettype = NONE_ATTACKABLE;
  509. return 0;
  510. }
  511. }
  512. if(!md->mode)
  513. mode=mob_db[md->class].mode;
  514. else
  515. mode=md->mode;
  516. race=mob_db[md->class].race;
  517. if(!(mode&0x80)){
  518. md->target_id=0;
  519. md->state.targettype = NONE_ATTACKABLE;
  520. return 0;
  521. }
  522. if(tsd && !(mode&0x20) && (tsd->sc_data[SC_TRICKDEAD].timer != -1 || tsd->sc_data[SC_BASILICA].timer != -1 ||
  523. ((pc_ishiding(tsd) || tsd->state.gangsterparadise) && !((race == 4 || race == 6) && !tsd->perfect_hiding) ) ) ) {
  524. md->target_id=0;
  525. md->state.targettype = NONE_ATTACKABLE;
  526. return 0;
  527. }
  528. range = mob_db[md->class].range;
  529. if(mode&1)
  530. range++;
  531. if(distance(md->bl.x,md->bl.y,tbl->x,tbl->y) > range)
  532. return 0;
  533. if(battle_config.monster_attack_direction_change)
  534. md->dir=map_calc_dir(&md->bl, tbl->x,tbl->y ); // 向き設定
  535. //clif_fixmobpos(md);
  536. md->state.skillstate=MSS_ATTACK;
  537. if( mobskill_use(md,tick,-2) ) // スキル使用
  538. return 0;
  539. md->target_lv = battle_weapon_attack(&md->bl,tbl,tick,0);
  540. if(!(battle_config.monster_cloak_check_type&2) && md->sc_data[SC_CLOAKING].timer != -1)
  541. skill_status_change_end(&md->bl,SC_CLOAKING,-1);
  542. md->attackabletime = tick + battle_get_adelay(&md->bl);
  543. md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
  544. md->state.state=MS_ATTACK;
  545. return 0;
  546. }
  547. /*==========================================
  548. * The attack of PC which is attacking id is stopped.
  549. * The callback function of clif_foreachclient
  550. *------------------------------------------
  551. */
  552. int mob_stopattacked(struct map_session_data *sd,va_list ap)
  553. {
  554. int id;
  555. nullpo_retr(0, sd);
  556. nullpo_retr(0, ap);
  557. id=va_arg(ap,int);
  558. if(sd->attacktarget==id)
  559. pc_stopattack(sd);
  560. return 0;
  561. }
  562. /*==========================================
  563. * The timer in which the mob's states changes
  564. *------------------------------------------
  565. */
  566. int mob_changestate(struct mob_data *md,int state,int type)
  567. {
  568. unsigned int tick;
  569. int i;
  570. nullpo_retr(0, md);
  571. if(md->timer != -1)
  572. delete_timer(md->timer,mob_timer);
  573. md->timer=-1;
  574. md->state.state=state;
  575. switch(state){
  576. case MS_WALK:
  577. if((i=calc_next_walk_step(md))>0){
  578. i = i>>2;
  579. md->timer=add_timer(gettick()+i,mob_timer,md->bl.id,0);
  580. }
  581. else
  582. md->state.state=MS_IDLE;
  583. break;
  584. case MS_ATTACK:
  585. tick = gettick();
  586. i=DIFF_TICK(md->attackabletime,tick);
  587. if(i>0 && i<2000)
  588. md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
  589. else if(type) {
  590. md->attackabletime = tick + battle_get_amotion(&md->bl);
  591. md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
  592. }
  593. else {
  594. md->attackabletime = tick + 1;
  595. md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
  596. }
  597. break;
  598. case MS_DELAY:
  599. md->timer=add_timer(gettick()+type,mob_timer,md->bl.id,0);
  600. break;
  601. case MS_DEAD:
  602. skill_castcancel(&md->bl,0);
  603. // mobskill_deltimer(md);
  604. md->state.skillstate=MSS_DEAD;
  605. md->last_deadtime=gettick();
  606. // Since it died, all aggressors' attack to this mob is stopped.
  607. clif_foreachclient(mob_stopattacked,md->bl.id);
  608. skill_unit_out_all(&md->bl,gettick(),1);
  609. skill_status_change_clear(&md->bl,2); // ステータス異常を解除する
  610. skill_clear_unitgroup(&md->bl); // 全てのスキルユニットグループを削除する
  611. skill_cleartimerskill(&md->bl);
  612. if(md->deletetimer!=-1)
  613. delete_timer(md->deletetimer,mob_timer_delete);
  614. md->deletetimer=-1;
  615. md->hp=md->target_id=md->attacked_id=0;
  616. md->state.targettype = NONE_ATTACKABLE;
  617. break;
  618. }
  619. return 0;
  620. }
  621. /*==========================================
  622. * timer processing of mob (timer function)
  623. * It branches to a walk and an attack.
  624. *------------------------------------------
  625. */
  626. static int mob_timer(int tid,unsigned int tick,int id,int data)
  627. {
  628. struct mob_data *md;
  629. struct block_list *bl;
  630. if( (bl=map_id2bl(id)) == NULL ){ //攻撃してきた敵がもういないのは正常のようだ
  631. return 1;
  632. }
  633. if(!bl || !bl->type || bl->type!=BL_MOB)
  634. return 1;
  635. nullpo_retr(1, md=(struct mob_data*)bl);
  636. if(!md->bl.type || md->bl.type!=BL_MOB)
  637. return 1;
  638. if(md->timer != tid){
  639. if(battle_config.error_log)
  640. printf("mob_timer %d != %d\n",md->timer,tid);
  641. return 0;
  642. }
  643. md->timer=-1;
  644. if(md->bl.prev == NULL || md->state.state == MS_DEAD)
  645. return 1;
  646. map_freeblock_lock();
  647. switch(md->state.state){
  648. case MS_WALK:
  649. mob_walk(md,tick,data);
  650. break;
  651. case MS_ATTACK:
  652. mob_attack(md,tick,data);
  653. break;
  654. case MS_DELAY:
  655. mob_changestate(md,MS_IDLE,0);
  656. break;
  657. default:
  658. if(battle_config.error_log)
  659. printf("mob_timer : %d ?\n",md->state.state);
  660. break;
  661. }
  662. if (md->timer == -1)
  663. mob_changestate(md,MS_WALK,0);
  664. map_freeblock_unlock();
  665. return 0;
  666. }
  667. /*==========================================
  668. *
  669. *------------------------------------------
  670. */
  671. static int mob_walktoxy_sub(struct mob_data *md)
  672. {
  673. struct walkpath_data wpd;
  674. nullpo_retr(0, md);
  675. if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,md->to_x,md->to_y,md->state.walk_easy))
  676. return 1;
  677. memcpy(&md->walkpath,&wpd,sizeof(wpd));
  678. md->state.change_walk_target=0;
  679. mob_changestate(md,MS_WALK,0);
  680. clif_movemob(md);
  681. return 0;
  682. }
  683. /*==========================================
  684. * mob move start
  685. *------------------------------------------
  686. */
  687. int mob_walktoxy(struct mob_data *md,int x,int y,int easy)
  688. {
  689. struct walkpath_data wpd;
  690. nullpo_retr(0, md);
  691. if(md->state.state == MS_WALK && path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,x,y,easy) )
  692. return 1;
  693. md->state.walk_easy = easy;
  694. md->to_x=x;
  695. md->to_y=y;
  696. if(md->state.state == MS_WALK)
  697. md->state.change_walk_target=1;
  698. else
  699. return mob_walktoxy_sub(md);
  700. return 0;
  701. }
  702. /*==========================================
  703. * mob spawn with delay (timer function)
  704. *------------------------------------------
  705. */
  706. static int mob_delayspawn(int tid,unsigned int tick,int m,int n)
  707. {
  708. mob_spawn(m);
  709. return 0;
  710. }
  711. /*==========================================
  712. * spawn timing calculation
  713. *------------------------------------------
  714. */
  715. int mob_setdelayspawn(int id)
  716. {
  717. unsigned int spawntime,spawntime1,spawntime2,spawntime3;
  718. struct mob_data *md;
  719. struct block_list *bl;
  720. if((bl=map_id2bl(id)) == NULL)
  721. return -1;
  722. if(!bl || !bl->type || bl->type!=BL_MOB)
  723. return -1;
  724. nullpo_retr(-1, md=(struct mob_data*)bl);
  725. if(!md || md->bl.type!=BL_MOB)
  726. return -1;
  727. // Processing of MOB which is not revitalized
  728. if(md->spawndelay1==-1 && md->spawndelay2==-1 && md->n==0){
  729. map_deliddb(&md->bl);
  730. if(md->lootitem) {
  731. map_freeblock(md->lootitem);
  732. md->lootitem=NULL;
  733. }
  734. map_freeblock(md); // Instead of [ of free ]
  735. return 0;
  736. }
  737. spawntime1=md->last_spawntime+md->spawndelay1;
  738. spawntime2=md->last_deadtime+md->spawndelay2;
  739. spawntime3=gettick()+5000;
  740. // spawntime = max(spawntime1,spawntime2,spawntime3);
  741. if(DIFF_TICK(spawntime1,spawntime2)>0)
  742. spawntime=spawntime1;
  743. else
  744. spawntime=spawntime2;
  745. if(DIFF_TICK(spawntime3,spawntime)>0)
  746. spawntime=spawntime3;
  747. add_timer(spawntime,mob_delayspawn,id,0);
  748. return 0;
  749. }
  750. /*==========================================
  751. * Mob spawning. Initialization is also variously here.
  752. *------------------------------------------
  753. */
  754. int mob_spawn(int id)
  755. {
  756. int x=0,y=0,i=0,c;
  757. unsigned int tick = gettick();
  758. struct mob_data *md;
  759. struct block_list *bl;
  760. nullpo_retr(-1, bl=map_id2bl(id));
  761. if(!bl || !bl->type || bl->type!=BL_MOB)
  762. return -1;
  763. nullpo_retr(-1, md=(struct mob_data*)bl);
  764. if(!md || !md->bl.type || md->bl.type!=BL_MOB)
  765. return -1;
  766. md->last_spawntime=tick;
  767. if( md->bl.prev!=NULL ){
  768. // clif_clearchar_area(&md->bl,3);
  769. skill_unit_out_all(&md->bl,gettick(),1);
  770. map_delblock(&md->bl);
  771. }
  772. else
  773. md->class = md->base_class;
  774. md->bl.m =md->m;
  775. do {
  776. if(md->x0==0 && md->y0==0){
  777. x=rand()%(map[md->bl.m].xs-2)+1;
  778. y=rand()%(map[md->bl.m].ys-2)+1;
  779. } else {
  780. x=md->x0+rand()%(md->xs+1)-md->xs/2;
  781. y=md->y0+rand()%(md->ys+1)-md->ys/2;
  782. }
  783. i++;
  784. } while(map_getcell(md->bl.m,x,y,CELL_CHKNOPASS) && i<50);
  785. if(i>=50){
  786. // if(battle_config.error_log==1)
  787. // printf("MOB spawn error %d @ %s\n",id,map[md->bl.m].name);
  788. add_timer(tick+5000,mob_delayspawn,id,0);
  789. return 1;
  790. }
  791. md->to_x=md->bl.x=x;
  792. md->to_y=md->bl.y=y;
  793. md->dir=0;
  794. md->target_dir=0;
  795. map_addblock(&md->bl);
  796. memset(&md->state,0,sizeof(md->state));
  797. md->attacked_id = 0;
  798. md->target_id = 0;
  799. md->move_fail_count = 0;
  800. if(!md->speed)
  801. md->speed = mob_db[md->class].speed;
  802. md->def_ele = mob_db[md->class].element;
  803. if(!md->level) // [Valaris]
  804. md->level=mob_db[md->class].lv;
  805. md->master_id=0;
  806. md->master_dist=0;
  807. md->state.state = MS_IDLE;
  808. md->state.skillstate = MSS_IDLE;
  809. md->timer = -1;
  810. md->last_thinktime = tick;
  811. md->next_walktime = tick+rand()%50+5000;
  812. md->attackabletime = tick;
  813. md->canmove_tick = tick;
  814. md->guild_id = 0;
  815. if (md->class >= 1285 && md->class <= 1288) {
  816. struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
  817. if(gc)
  818. md->guild_id = gc->guild_id;
  819. }
  820. md->deletetimer=-1;
  821. md->skilltimer=-1;
  822. for(i=0,c=tick-1000*3600*10;i<MAX_MOBSKILL;i++)
  823. md->skilldelay[i] = c;
  824. md->skillid=0;
  825. md->skilllv=0;
  826. memset(md->dmglog,0,sizeof(md->dmglog));
  827. if(md->lootitem)
  828. memset(md->lootitem,0,sizeof(md->lootitem));
  829. md->lootitem_count = 0;
  830. for(i=0;i<MAX_MOBSKILLTIMERSKILL;i++)
  831. md->skilltimerskill[i].timer = -1;
  832. for(i=0;i<MAX_STATUSCHANGE;i++) {
  833. md->sc_data[i].timer=-1;
  834. md->sc_data[i].val1 = md->sc_data[i].val2 = md->sc_data[i].val3 = md->sc_data[i].val4 =0;
  835. }
  836. md->sc_count=0;
  837. md->opt1=md->opt2=md->opt3=md->option=0;
  838. memset(md->skillunit,0,sizeof(md->skillunit));
  839. memset(md->skillunittick,0,sizeof(md->skillunittick));
  840. md->hp = battle_get_max_hp(&md->bl);
  841. if(md->hp<=0){
  842. mob_makedummymobdb(md->class);
  843. md->hp = battle_get_max_hp(&md->bl);
  844. }
  845. clif_spawnmob(md);
  846. return 0;
  847. }
  848. /*==========================================
  849. * Distance calculation between two points
  850. *------------------------------------------
  851. */
  852. static int distance(int x0,int y0,int x1,int y1)
  853. {
  854. int dx,dy;
  855. dx=abs(x0-x1);
  856. dy=abs(y0-y1);
  857. return dx>dy ? dx : dy;
  858. }
  859. /*==========================================
  860. * The stop of MOB's attack
  861. *------------------------------------------
  862. */
  863. int mob_stopattack(struct mob_data *md)
  864. {
  865. md->target_id=0;
  866. md->state.targettype = NONE_ATTACKABLE;
  867. md->attacked_id=0;
  868. return 0;
  869. }
  870. /*==========================================
  871. * The stop of MOB's walking
  872. *------------------------------------------
  873. */
  874. int mob_stop_walking(struct mob_data *md,int type)
  875. {
  876. nullpo_retr(0, md);
  877. if(md->state.state == MS_WALK || md->state.state == MS_IDLE) {
  878. int dx=0,dy=0;
  879. md->walkpath.path_len=0;
  880. if(type&4){
  881. dx=md->to_x-md->bl.x;
  882. if(dx<0)
  883. dx=-1;
  884. else if(dx>0)
  885. dx=1;
  886. dy=md->to_y-md->bl.y;
  887. if(dy<0)
  888. dy=-1;
  889. else if(dy>0)
  890. dy=1;
  891. }
  892. md->to_x=md->bl.x+dx;
  893. md->to_y=md->bl.y+dy;
  894. if(dx!=0 || dy!=0){
  895. mob_walktoxy_sub(md);
  896. return 0;
  897. }
  898. mob_changestate(md,MS_IDLE,0);
  899. }
  900. if(type&0x01)
  901. clif_fixmobpos(md);
  902. if(type&0x02) {
  903. int delay=battle_get_dmotion(&md->bl);
  904. unsigned int tick = gettick();
  905. if(md->canmove_tick < tick)
  906. md->canmove_tick = tick + delay;
  907. }
  908. return 0;
  909. }
  910. /*==========================================
  911. * Reachability to a Specification ID existence place
  912. *------------------------------------------
  913. */
  914. int mob_can_reach(struct mob_data *md,struct block_list *bl,int range)
  915. {
  916. int dx,dy;
  917. struct walkpath_data wpd;
  918. int i;
  919. nullpo_retr(0, md);
  920. nullpo_retr(0, bl);
  921. dx=abs(bl->x - md->bl.x);
  922. dy=abs(bl->y - md->bl.y);
  923. //=========== guildcastle guardian no search start===========
  924. //when players are the guild castle member not attack them !
  925. if(md->class >= 1285 && md->class <= 1287){
  926. struct map_session_data *sd;
  927. struct guild *g=NULL;
  928. struct guild_castle *gc=guild_mapname2gc(map[bl->m].name);
  929. if(gc && agit_flag==0) // Guardians will not attack during non-woe time [Valaris]
  930. return 0; // end addition [Valaris]
  931. if(bl && bl->type == BL_PC){
  932. nullpo_retr(0, sd=(struct map_session_data *)bl);
  933. if(!gc)
  934. return 0;
  935. if(gc && sd && sd->status.guild_id) {
  936. g=guild_search(sd->status.guild_id); // don't attack guild members [Valaris]
  937. if(g && g->guild_id == gc->guild_id)
  938. return 0;
  939. if(g && gc && guild_isallied(g,gc))
  940. return 0;
  941. }
  942. }
  943. }
  944. //========== guildcastle guardian no search eof==============
  945. if(bl && bl->type == BL_PC && battle_config.monsters_ignore_gm) { // option to have monsters ignore GMs [Valaris]
  946. struct map_session_data *sd;
  947. if((sd=(struct map_session_data *)bl) != NULL && pc_isGM(sd) >= battle_config.monsters_ignore_gm)
  948. return 0;
  949. }
  950. if( md->bl.m != bl->m) // 違うャbプ
  951. return 0;
  952. if( range>0 && range < ((dx>dy)?dx:dy) ) // 遠すぎる
  953. return 0;
  954. if( md->bl.x==bl->x && md->bl.y==bl->y ) // 同じマス
  955. return 1;
  956. // Obstacle judging
  957. wpd.path_len=0;
  958. wpd.path_pos=0;
  959. wpd.path_half=0;
  960. if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x,bl->y,0)!=-1)
  961. return 1;
  962. if(bl->type!=BL_PC && bl->type!=BL_MOB)
  963. return 0;
  964. // It judges whether it can adjoin or not.
  965. dx=(dx>0)?1:((dx<0)?-1:0);
  966. dy=(dy>0)?1:((dy<0)?-1:0);
  967. if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x-dx,bl->y-dy,0)!=-1)
  968. return 1;
  969. for(i=0;i<9;i++){
  970. if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x-1+i/3,bl->y-1+i%3,0)!=-1)
  971. return 1;
  972. }
  973. return 0;
  974. }
  975. /*==========================================
  976. * Determination for an attack of a monster
  977. *------------------------------------------
  978. */
  979. int mob_target(struct mob_data *md,struct block_list *bl,int dist)
  980. {
  981. struct map_session_data *sd;
  982. struct status_change *sc_data;
  983. short *option;
  984. int mode,race;
  985. nullpo_retr(0, md);
  986. nullpo_retr(0, bl);
  987. sc_data = battle_get_sc_data(bl);
  988. option = battle_get_option(bl);
  989. race=mob_db[md->class].race;
  990. if(!md->mode)
  991. mode=mob_db[md->class].mode;
  992. else
  993. mode=md->mode;
  994. if(!(mode&0x80)) {
  995. md->target_id = 0;
  996. return 0;
  997. }
  998. // Nothing will be carried out if there is no mind of changing TAGE by TAGE ending.
  999. if( (md->target_id > 0 && md->state.targettype == ATTACKABLE) && ( !(mode&0x04) || rand()%100>25) )
  1000. return 0;
  1001. if(mode&0x20 || // Coercion is exerted if it is MVPMOB.
  1002. (sc_data && sc_data[SC_TRICKDEAD].timer == -1 && sc_data[SC_BASILICA].timer == -1 &&
  1003. ( (option && !(*option&0x06) ) || race==4 || race==6) ) ) {
  1004. if(bl->type == BL_PC) {
  1005. nullpo_retr(0, sd = (struct map_session_data *)bl);
  1006. if(sd->invincible_timer != -1 || pc_isinvisible(sd))
  1007. return 0;
  1008. if(!(mode&0x20) && race!=4 && race!=6 && sd->state.gangsterparadise)
  1009. return 0;
  1010. }
  1011. md->target_id=bl->id; // Since there was no disturbance, it locks on to target.
  1012. if(bl->type == BL_PC || bl->type == BL_MOB)
  1013. md->state.targettype = ATTACKABLE;
  1014. else
  1015. md->state.targettype = NONE_ATTACKABLE;
  1016. md->min_chase=dist+13;
  1017. if(md->min_chase>26)
  1018. md->min_chase=26;
  1019. }
  1020. return 0;
  1021. }
  1022. /*==========================================
  1023. * The ?? routine of an active monster
  1024. *------------------------------------------
  1025. */
  1026. static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
  1027. {
  1028. struct map_session_data *tsd=NULL;
  1029. struct mob_data *smd,*tmd=NULL;
  1030. int mode,race,dist,*pcc;
  1031. nullpo_retr(0, bl);
  1032. nullpo_retr(0, ap);
  1033. nullpo_retr(0, smd=va_arg(ap,struct mob_data *));
  1034. nullpo_retr(0, pcc=va_arg(ap,int *));
  1035. if(bl->type==BL_PC)
  1036. tsd=(struct map_session_data *)bl;
  1037. else if(bl->type==BL_MOB)
  1038. tmd=(struct mob_data *)bl;
  1039. else
  1040. return 0;
  1041. //敵味方判定
  1042. if(battle_check_target(&smd->bl,bl,BCT_ENEMY)==0)
  1043. return 0;
  1044. if(!smd->mode)
  1045. mode=mob_db[smd->class].mode;
  1046. else
  1047. mode=smd->mode;
  1048. // アクティブでターゲット射程内にいるなら、ロックする
  1049. if( mode&0x04 ){
  1050. race=mob_db[smd->class].race;
  1051. //対象がPCの場合
  1052. if(tsd &&
  1053. !pc_isdead(tsd) &&
  1054. tsd->bl.m == smd->bl.m &&
  1055. tsd->invincible_timer == -1 &&
  1056. !pc_isinvisible(tsd) &&
  1057. (dist=distance(smd->bl.x,smd->bl.y,tsd->bl.x,tsd->bl.y))<9
  1058. )
  1059. {
  1060. if(mode&0x20 ||
  1061. (tsd->sc_data[SC_TRICKDEAD].timer == -1 && tsd->sc_data[SC_BASILICA].timer == -1 &&
  1062. ((!pc_ishiding(tsd) && !tsd->state.gangsterparadise) || ((race == 4 || race == 6) && !tsd->perfect_hiding) ))){ // 妨害がないか判定
  1063. if( mob_can_reach(smd,bl,12) && // 到達可能性判定
  1064. rand()%1000<1000/(++(*pcc)) ){ // 範囲内PCで等確率にする
  1065. smd->target_id=tsd->bl.id;
  1066. smd->state.targettype = ATTACKABLE;
  1067. smd->min_chase=13;
  1068. }
  1069. }
  1070. }
  1071. //対象がMobの場合
  1072. else if(tmd &&
  1073. tmd->bl.m == smd->bl.m &&
  1074. (dist=distance(smd->bl.x,smd->bl.y,tmd->bl.x,tmd->bl.y))<9
  1075. )
  1076. {
  1077. if( mob_can_reach(smd,bl,12) && // 到達可能性判定
  1078. rand()%1000<1000/(++(*pcc)) ){ // 範囲内で等確率にする
  1079. smd->target_id=bl->id;
  1080. smd->state.targettype = ATTACKABLE;
  1081. smd->min_chase=13;
  1082. }
  1083. }
  1084. }
  1085. return 0;
  1086. }
  1087. /*==========================================
  1088. * loot monster item search
  1089. *------------------------------------------
  1090. */
  1091. static int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
  1092. {
  1093. struct mob_data* md;
  1094. int mode,dist,*itc;
  1095. nullpo_retr(0, bl);
  1096. nullpo_retr(0, ap);
  1097. nullpo_retr(0, md=va_arg(ap,struct mob_data *));
  1098. nullpo_retr(0, itc=va_arg(ap,int *));
  1099. if(!md->mode)
  1100. mode=mob_db[md->class].mode;
  1101. else
  1102. mode=md->mode;
  1103. if( !md->target_id && mode&0x02){
  1104. if(!md->lootitem || (battle_config.monster_loot_type == 1 && md->lootitem_count >= LOOTITEM_SIZE) )
  1105. return 0;
  1106. if(bl->m == md->bl.m && (dist=distance(md->bl.x,md->bl.y,bl->x,bl->y))<9){
  1107. if( mob_can_reach(md,bl,12) && // Reachability judging
  1108. rand()%1000<1000/(++(*itc)) ){ // It is made a probability, such as within the limits PC.
  1109. md->target_id=bl->id;
  1110. md->state.targettype = NONE_ATTACKABLE;
  1111. md->min_chase=13;
  1112. }
  1113. }
  1114. }
  1115. return 0;
  1116. }
  1117. /*==========================================
  1118. * The ?? routine of a link monster
  1119. *------------------------------------------
  1120. */
  1121. static int mob_ai_sub_hard_linksearch(struct block_list *bl,va_list ap)
  1122. {
  1123. struct mob_data *tmd;
  1124. struct mob_data* md;
  1125. struct block_list *target;
  1126. nullpo_retr(0, bl);
  1127. nullpo_retr(0, ap);
  1128. nullpo_retr(0, tmd=(struct mob_data *)bl);
  1129. nullpo_retr(0, md=va_arg(ap,struct mob_data *));
  1130. nullpo_retr(0, target=va_arg(ap,struct block_list *));
  1131. // same family free in a range at a link monster -- it will be made to lock if MOB is
  1132. /* if( (md->target_id > 0 && md->state.targettype == ATTACKABLE) && mob_db[md->class].mode&0x08){
  1133. if( tmd->class==md->class && (!tmd->target_id || md->state.targettype == NONE_ATTACKABLE) && tmd->bl.m == md->bl.m){
  1134. if( mob_can_reach(tmd,target,12) ){ // Reachability judging
  1135. tmd->target_id=md->target_id;
  1136. tmd->state.targettype = ATTACKABLE;
  1137. tmd->min_chase=13;
  1138. }
  1139. }
  1140. }*/
  1141. if( md->attacked_id > 0 && mob_db[md->class].mode&0x08){
  1142. if( tmd->class==md->class && tmd->bl.m == md->bl.m && (!tmd->target_id || md->state.targettype == NONE_ATTACKABLE)){
  1143. if( mob_can_reach(tmd,target,12) ){ // Reachability judging
  1144. tmd->target_id=md->attacked_id;
  1145. tmd->state.targettype = ATTACKABLE;
  1146. tmd->min_chase=13;
  1147. }
  1148. }
  1149. }
  1150. return 0;
  1151. }
  1152. /*==========================================
  1153. * Processing of slave monsters
  1154. *------------------------------------------
  1155. */
  1156. static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
  1157. {
  1158. struct mob_data *mmd=NULL;
  1159. struct block_list *bl;
  1160. int mode,race,old_dist;
  1161. nullpo_retr(0, md);
  1162. if((bl=map_id2bl(md->master_id)) != NULL )
  1163. mmd=(struct mob_data *)bl;
  1164. mode=mob_db[md->class].mode;
  1165. // It is not main monster/leader.
  1166. if(!mmd || mmd->bl.type!=BL_MOB || mmd->bl.id!=md->master_id)
  1167. return 0;
  1168. // Since it is in the map on which the master is not, teleport is carried out and it pursues.
  1169. if( mmd->bl.m != md->bl.m ){
  1170. mob_warp(md,mmd->bl.m,mmd->bl.x,mmd->bl.y,3);
  1171. md->state.master_check = 1;
  1172. return 0;
  1173. }
  1174. // Distance with between slave and master is measured.
  1175. old_dist=md->master_dist;
  1176. md->master_dist=distance(md->bl.x,md->bl.y,mmd->bl.x,mmd->bl.y);
  1177. // Since the master was in near immediately before, teleport is carried out and it pursues.
  1178. if( old_dist<10 && md->master_dist>18){
  1179. mob_warp(md,-1,mmd->bl.x,mmd->bl.y,3);
  1180. md->state.master_check = 1;
  1181. return 0;
  1182. }
  1183. // Although there is the master, since it is somewhat far, it approaches.
  1184. if((!md->target_id || md->state.targettype == NONE_ATTACKABLE) && mob_can_move(md) &&
  1185. (md->walkpath.path_pos>=md->walkpath.path_len || md->walkpath.path_len==0) && md->master_dist<15){
  1186. int i=0,dx,dy,ret;
  1187. if(md->master_dist>4) {
  1188. do {
  1189. if(i<=5){
  1190. dx=mmd->bl.x - md->bl.x;
  1191. dy=mmd->bl.y - md->bl.y;
  1192. if(dx<0) dx+=(rand()%( (dx<-3)?3:-dx )+1);
  1193. else if(dx>0) dx-=(rand()%( (dx>3)?3:dx )+1);
  1194. if(dy<0) dy+=(rand()%( (dy<-3)?3:-dy )+1);
  1195. else if(dy>0) dy-=(rand()%( (dy>3)?3:dy )+1);
  1196. }else{
  1197. dx=mmd->bl.x - md->bl.x + rand()%7 - 3;
  1198. dy=mmd->bl.y - md->bl.y + rand()%7 - 3;
  1199. }
  1200. ret=mob_walktoxy(md,md->bl.x+dx,md->bl.y+dy,0);
  1201. i++;
  1202. } while(ret && i<10);
  1203. }
  1204. else {
  1205. do {
  1206. dx = rand()%9 - 5;
  1207. dy = rand()%9 - 5;
  1208. if( dx == 0 && dy == 0) {
  1209. dx = (rand()%1)? 1:-1;
  1210. dy = (rand()%1)? 1:-1;
  1211. }
  1212. dx += mmd->bl.x;
  1213. dy += mmd->bl.y;
  1214. ret=mob_walktoxy(md,mmd->bl.x+dx,mmd->bl.y+dy,0);
  1215. i++;
  1216. } while(ret && i<10);
  1217. }
  1218. md->next_walktime=tick+500;
  1219. md->state.master_check = 1;
  1220. }
  1221. // There is the master, the master locks a target and he does not lock.
  1222. if( (mmd->target_id>0 && mmd->state.targettype == ATTACKABLE) && (!md->target_id || md->state.targettype == NONE_ATTACKABLE) ){
  1223. struct map_session_data *sd=map_id2sd(mmd->target_id);
  1224. if(sd!=NULL && !pc_isdead(sd) && sd->invincible_timer == -1 && !pc_isinvisible(sd)){
  1225. race=mob_db[md->class].race;
  1226. if(mode&0x20 ||
  1227. (sd->sc_data[SC_TRICKDEAD].timer == -1 && sd->sc_data[SC_BASILICA].timer == -1 &&
  1228. ( (!pc_ishiding(sd) && !sd->state.gangsterparadise) || ((race == 4 || race == 6) && !sd->perfect_hiding) ) ) ){ // 妨害がないか判定
  1229. md->target_id=sd->bl.id;
  1230. md->state.targettype = ATTACKABLE;
  1231. md->min_chase=5+distance(md->bl.x,md->bl.y,sd->bl.x,sd->bl.y);
  1232. md->state.master_check = 1;
  1233. }
  1234. }
  1235. }
  1236. // There is the master, the master locks a target and he does not lock.
  1237. /* if( (md->target_id>0 && mmd->state.targettype == ATTACKABLE) && (!mmd->target_id || mmd->state.targettype == NONE_ATTACKABLE) ){
  1238. struct map_session_data *sd=map_id2sd(md->target_id);
  1239. if(sd!=NULL && !pc_isdead(sd) && sd->invincible_timer == -1 && !pc_isinvisible(sd)){
  1240. race=mob_db[mmd->class].race;
  1241. if(mode&0x20 ||
  1242. (sd->sc_data[SC_TRICKDEAD].timer == -1 &&
  1243. (!(sd->status.option&0x06) || race==4 || race==6)
  1244. ) ){ // It judges whether there is any disturbance.
  1245. mmd->target_id=sd->bl.id;
  1246. mmd->state.targettype = ATTACKABLE;
  1247. mmd->min_chase=5+distance(mmd->bl.x,mmd->bl.y,sd->bl.x,sd->bl.y);
  1248. }
  1249. }
  1250. }*/
  1251. return 0;
  1252. }
  1253. /*==========================================
  1254. * A lock of target is stopped and mob moves to a standby state.
  1255. *------------------------------------------
  1256. */
  1257. static int mob_unlocktarget(struct mob_data *md,int tick)
  1258. {
  1259. nullpo_retr(0, md);
  1260. md->target_id=0;
  1261. md->state.targettype = NONE_ATTACKABLE;
  1262. md->state.skillstate=MSS_IDLE;
  1263. md->next_walktime=tick+rand()%3000+3000;
  1264. return 0;
  1265. }
  1266. /*==========================================
  1267. * Random walk
  1268. *------------------------------------------
  1269. */
  1270. static int mob_randomwalk(struct mob_data *md,int tick)
  1271. {
  1272. const int retrycount=20;
  1273. int speed;
  1274. nullpo_retr(0, md);
  1275. speed=battle_get_speed(&md->bl);
  1276. if(DIFF_TICK(md->next_walktime,tick)<0){
  1277. int i,x,y,c,d=12-md->move_fail_count;
  1278. int mask[8][2] = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};
  1279. if(d<5) d=5;
  1280. for(i=0;i<retrycount;i++){ // Search of a movable place
  1281. int r=rand();
  1282. x=r%(d*2+1)-d;
  1283. y=r/(d*2+1)%(d*2+1)-d;
  1284. if (md->target_dir){
  1285. if (x<0) x=0-x;
  1286. if (y<0) y=0-y;
  1287. x *= mask[md->target_dir-1][0];
  1288. y *= mask[md->target_dir-1][1];
  1289. }
  1290. x+=md->bl.x;
  1291. y+=md->bl.y;
  1292. if((map_getcell(md->bl.m,x,y,CELL_CHKPASS)) && mob_walktoxy(md,x,y,1)==0){
  1293. md->move_fail_count=0;
  1294. break;
  1295. }
  1296. if(i+1>=retrycount){
  1297. md->move_fail_count++;
  1298. md->target_dir = 0;
  1299. if(md->move_fail_count>1000){
  1300. if(battle_config.error_log)
  1301. printf("MOB cant move. random spawn %d, class = %d\n",md->bl.id,md->class);
  1302. md->move_fail_count=0;
  1303. mob_spawn(md->bl.id);
  1304. }
  1305. }
  1306. }
  1307. for(i=c=0;i<md->walkpath.path_len;i++){ // The next walk start time is calculated.
  1308. if(md->walkpath.path[i]&1)
  1309. c+=speed*14/10;
  1310. else
  1311. c+=speed;
  1312. }
  1313. md->next_walktime = tick+rand()%3000+3000+c;
  1314. md->state.skillstate=MSS_WALK;
  1315. return 1;
  1316. }
  1317. return 0;
  1318. }
  1319. /*==========================================
  1320. * AI of MOB whose is near a Player
  1321. *------------------------------------------
  1322. */
  1323. static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
  1324. {
  1325. struct mob_data *md,*tmd=NULL;
  1326. struct map_session_data *tsd=NULL;
  1327. struct block_list *tbl=NULL;
  1328. struct flooritem_data *fitem;
  1329. unsigned int tick;
  1330. int i,dx,dy,ret,dist;
  1331. int attack_type=0;
  1332. int mode,race;
  1333. nullpo_retr(0, bl);
  1334. nullpo_retr(0, ap);
  1335. nullpo_retr(0, md=(struct mob_data*)bl);
  1336. tick=va_arg(ap,unsigned int);
  1337. if(DIFF_TICK(tick,md->last_thinktime)<MIN_MOBTHINKTIME)
  1338. return 0;
  1339. md->last_thinktime=tick;
  1340. if( md->skilltimer!=-1 || md->bl.prev==NULL ){ // Under a skill aria and death
  1341. if(DIFF_TICK(tick,md->next_walktime)>MIN_MOBTHINKTIME)
  1342. md->next_walktime=tick;
  1343. return 0;
  1344. }
  1345. if(!md->mode)
  1346. mode=mob_db[md->class].mode;
  1347. else
  1348. mode=md->mode;
  1349. race=mob_db[md->class].race;
  1350. // Abnormalities
  1351. if((md->opt1 > 0 && md->opt1 != 6) || md->state.state==MS_DELAY || md->sc_data[SC_BLADESTOP].timer != -1)
  1352. return 0;
  1353. if(!(mode&0x80) && md->target_id > 0)
  1354. md->target_id = 0;
  1355. if(md->attacked_id > 0 && mode&0x08){ // Link monster
  1356. struct map_session_data *asd=map_id2sd(md->attacked_id);
  1357. if(asd){
  1358. if(asd->invincible_timer == -1 && !pc_isinvisible(asd)){
  1359. map_foreachinarea(mob_ai_sub_hard_linksearch,md->bl.m,
  1360. md->bl.x-13,md->bl.y-13,
  1361. md->bl.x+13,md->bl.y+13,
  1362. BL_MOB,md,&asd->bl);
  1363. }
  1364. }
  1365. }
  1366. // It checks to see it was attacked first (if active, it is target change at 25% of probability).
  1367. if( mode>0 && md->attacked_id>0 && (!md->target_id || md->state.targettype == NONE_ATTACKABLE
  1368. || (mode&0x04 && rand()%100<25 ) ) ){
  1369. struct block_list *abl=map_id2bl(md->attacked_id);
  1370. struct map_session_data *asd=NULL;
  1371. if(abl){
  1372. if(abl->type==BL_PC)
  1373. asd=(struct map_session_data *)abl;
  1374. if(asd==NULL || md->bl.m != abl->m || abl->prev == NULL || asd->invincible_timer != -1 || pc_isinvisible(asd) ||
  1375. (dist=distance(md->bl.x,md->bl.y,abl->x,abl->y))>=32 || battle_check_target(bl,abl,BCT_ENEMY)==0)
  1376. md->attacked_id=0;
  1377. else {
  1378. //距離が遠い場合はタゲを変更しない
  1379. if (!md->target_id || (distance(md->bl.x,md->bl.y,abl->x,abl->y)<3)) {
  1380. md->target_id=md->attacked_id; // set target
  1381. md->state.targettype = ATTACKABLE;
  1382. attack_type = 1;
  1383. md->attacked_id=0;
  1384. md->min_chase=dist+13;
  1385. if(md->min_chase>26)
  1386. md->min_chase=26;
  1387. }
  1388. }
  1389. }
  1390. }
  1391. md->state.master_check = 0;
  1392. // Processing of slave monster
  1393. if( md->master_id > 0 && md->state.special_mob_ai==0)
  1394. mob_ai_sub_hard_slavemob(md,tick);
  1395. // アクティヴモンスターの策敵 (?? of a bitter taste TIVU monster)
  1396. if( (!md->target_id || md->state.targettype == NONE_ATTACKABLE) && mode&0x04 && !md->state.master_check &&
  1397. battle_config.monster_active_enable){
  1398. i=0;
  1399. if(md->state.special_mob_ai){
  1400. map_foreachinarea(mob_ai_sub_hard_activesearch,md->bl.m,
  1401. md->bl.x-AREA_SIZE*2,md->bl.y-AREA_SIZE*2,
  1402. md->bl.x+AREA_SIZE*2,md->bl.y+AREA_SIZE*2,
  1403. 0,md,&i);
  1404. }else{
  1405. map_foreachinarea(mob_ai_sub_hard_activesearch,md->bl.m,
  1406. md->bl.x-AREA_SIZE*2,md->bl.y-AREA_SIZE*2,
  1407. md->bl.x+AREA_SIZE*2,md->bl.y+AREA_SIZE*2,
  1408. BL_PC,md,&i);
  1409. }
  1410. }
  1411. // The item search of a route monster
  1412. if( !md->target_id && mode&0x02 && !md->state.master_check){
  1413. i=0;
  1414. map_foreachinarea(mob_ai_sub_hard_lootsearch,md->bl.m,
  1415. md->bl.x-AREA_SIZE*2,md->bl.y-AREA_SIZE*2,
  1416. md->bl.x+AREA_SIZE*2,md->bl.y+AREA_SIZE*2,
  1417. BL_ITEM,md,&i);
  1418. }
  1419. // It will attack, if the candidate for an attack is.
  1420. if(md->target_id > 0){
  1421. if((tbl=map_id2bl(md->target_id))){
  1422. if(tbl->type==BL_PC)
  1423. tsd=(struct map_session_data *)tbl;
  1424. else if(tbl->type==BL_MOB)
  1425. tmd=(struct mob_data *)tbl;
  1426. if(tsd || tmd) {
  1427. if(tbl->m != md->bl.m || tbl->prev == NULL || (dist=distance(md->bl.x,md->bl.y,tbl->x,tbl->y))>=md->min_chase)
  1428. mob_unlocktarget(md,tick); // 別マップか、視界外
  1429. else if( tsd && !(mode&0x20) && (tsd->sc_data[SC_TRICKDEAD].timer != -1 || tsd->sc_data[SC_BASILICA].timer != -1 ||
  1430. ((pc_ishiding(tsd) || tsd->state.gangsterparadise) &&
  1431. !((race == 4 || race == 6) && !tsd->perfect_hiding) )) )
  1432. mob_unlocktarget(md,tick); // スキルなどによる策敵妨害
  1433. else if(!battle_check_range(&md->bl,tbl,mob_db[md->class].range)){
  1434. // 攻撃範囲外なので移動
  1435. if(!(mode&1)){ // 移動しないモード
  1436. mob_unlocktarget(md,tick);
  1437. return 0;
  1438. }
  1439. if( !mob_can_move(md) ) // 動けない状態にある
  1440. return 0;
  1441. md->state.skillstate=MSS_CHASE; // 突撃時スキル
  1442. mobskill_use(md,tick,-1);
  1443. // if(md->timer != -1 && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tsd->bl.x,tsd->bl.y)<2) )
  1444. if(md->timer != -1 && md->state.state!=MS_ATTACK && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tbl->x,tbl->y)<2) )
  1445. return 0; // 既に移動中
  1446. if( !mob_can_reach(md,tbl,(md->min_chase>13)?md->min_chase:13) )
  1447. mob_unlocktarget(md,tick); // 移動できないのでタゲ解除(IWとか?)
  1448. else{
  1449. // 追跡
  1450. md->next_walktime=tick+500;
  1451. i=0;
  1452. do {
  1453. if(i==0){ // 最初はAEGISと同じ方法で検索
  1454. dx=tbl->x - md->bl.x;
  1455. dy=tbl->y - md->bl.y;
  1456. if(dx<0) dx++;
  1457. else if(dx>0) dx--;
  1458. if(dy<0) dy++;
  1459. else if(dy>0) dy--;
  1460. }else{ // だめならAthena式(ランダム)
  1461. dx=tbl->x - md->bl.x + rand()%3 - 1;
  1462. dy=tbl->y - md->bl.y + rand()%3 - 1;
  1463. }
  1464. /* if(path_search(&md->walkpath,md->bl.m,md->bl.x,md->bl.y,md->bl.x+dx,md->bl.y+dy,0)){
  1465. dx=tsd->bl.x - md->bl.x;
  1466. dy=tsd->bl.y - md->bl.y;
  1467. if(dx<0) dx--;
  1468. else if(dx>0) dx++;
  1469. if(dy<0) dy--;
  1470. else if(dy>0) dy++;
  1471. }*/
  1472. ret=mob_walktoxy(md,md->bl.x+dx,md->bl.y+dy,0);
  1473. i++;
  1474. } while(ret && i<5);
  1475. if(ret){ // 移動不可能な所からの攻撃なら2歩下る
  1476. if(dx<0) dx=2;
  1477. else if(dx>0) dx=-2;
  1478. if(dy<0) dy=2;
  1479. else if(dy>0) dy=-2;
  1480. mob_walktoxy(md,md->bl.x+dx,md->bl.y+dy,0);
  1481. }
  1482. }
  1483. } else { // 攻撃射程範囲内
  1484. md->state.skillstate=MSS_ATTACK;
  1485. if(md->state.state==MS_WALK)
  1486. mob_stop_walking(md,1); // 歩行中なら停止
  1487. if(md->state.state==MS_ATTACK)
  1488. return 0; // 既に攻撃中
  1489. mob_changestate(md,MS_ATTACK,attack_type);
  1490. /* if(mode&0x08){ // リンクモンスター
  1491. map_foreachinarea(mob_ai_sub_hard_linksearch,md->bl.m,
  1492. md->bl.x-13,md->bl.y-13,
  1493. md->bl.x+13,md->bl.y+13,
  1494. BL_MOB,md,&tsd->bl);
  1495. }*/
  1496. }
  1497. return 0;
  1498. }else{ // ルートモンスター処理
  1499. if(tbl == NULL || tbl->type != BL_ITEM ||tbl->m != md->bl.m ||
  1500. (dist=distance(md->bl.x,md->bl.y,tbl->x,tbl->y))>=md->min_chase || !md->lootitem){
  1501. // 遠すぎるかアイテムがなくなった
  1502. mob_unlocktarget(md,tick);
  1503. if(md->state.state==MS_WALK)
  1504. mob_stop_walking(md,1); // 歩行中なら停止
  1505. }else if(dist){
  1506. if(!(mode&1)){ // 移動しないモード
  1507. mob_unlocktarget(md,tick);
  1508. return 0;
  1509. }
  1510. if( !mob_can_move(md) ) // 動けない状態にある
  1511. return 0;
  1512. md->state.skillstate=MSS_LOOT; // ルート時スキル使用
  1513. mobskill_use(md,tick,-1);
  1514. // if(md->timer != -1 && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tbl->x,tbl->y)<2) )
  1515. if(md->timer != -1 && md->state.state!=MS_ATTACK && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tbl->x,tbl->y) <= 0))
  1516. return 0; // 既に移動中
  1517. md->next_walktime=tick+500;
  1518. dx=tbl->x - md->bl.x;
  1519. dy=tbl->y - md->bl.y;
  1520. /* if(path_search(&md->walkpath,md->bl.m,md->bl.x,md->bl.y,md->bl.x+dx,md->bl.y+dy,0)){
  1521. dx=tbl->x - md->bl.x;
  1522. dy=tbl->y - md->bl.y;
  1523. }*/
  1524. ret=mob_walktoxy(md,md->bl.x+dx,md->bl.y+dy,0);
  1525. if(ret)
  1526. mob_unlocktarget(md,tick);// 移動できないのでタゲ解除(IWとか?)
  1527. }else{ // アイテムまでたどり着いた
  1528. if(md->state.state==MS_ATTACK)
  1529. return 0; // 攻撃中
  1530. if(md->state.state==MS_WALK)
  1531. mob_stop_walking(md,1); // 歩行中なら停止
  1532. fitem = (struct flooritem_data *)tbl;
  1533. if(md->lootitem_count < LOOTITEM_SIZE)
  1534. memcpy(&md->lootitem[md->lootitem_count++],&fitem->item_data,sizeof(md->lootitem[0]));
  1535. else if(battle_config.monster_loot_type == 1 && md->lootitem_count >= LOOTITEM_SIZE) {
  1536. mob_unlocktarget(md,tick);
  1537. return 0;
  1538. }
  1539. else {
  1540. if(md->lootitem[0].card[0] == (short)0xff00)
  1541. intif_delete_petdata(*((long *)(&md->lootitem[0].card[1])));
  1542. for(i=0;i<LOOTITEM_SIZE-1;i++)
  1543. memcpy(&md->lootitem[i],&md->lootitem[i+1],sizeof(md->lootitem[0]));
  1544. memcpy(&md->lootitem[LOOTITEM_SIZE-1],&fitem->item_data,sizeof(md->lootitem[0]));
  1545. }
  1546. map_clearflooritem(tbl->id);
  1547. mob_unlocktarget(md,tick);
  1548. }
  1549. return 0;
  1550. }
  1551. }else{
  1552. mob_unlocktarget(md,tick);
  1553. if(md->state.state==MS_WALK)
  1554. mob_stop_walking(md,4); // 歩行中なら停止
  1555. return 0;
  1556. }
  1557. }
  1558. // It is skill use at the time of /standby at the time of a walk.
  1559. if( mobskill_use(md,tick,-1) )
  1560. return 0;
  1561. // 歩行処理
  1562. if( mode&1 && mob_can_move(md) && // 移動可能MOB&動ける状態にある
  1563. (md->master_id==0 || md->state.special_mob_ai || md->master_dist>10) ){ //取り巻きMOBじゃない
  1564. if( DIFF_TICK(md->next_walktime,tick) > + 7000 &&
  1565. (md->walkpath.path_len==0 || md->walkpath.path_pos>=md->walkpath.path_len) ){
  1566. md->next_walktime = tick + 3000*rand()%2000;
  1567. }
  1568. // Random movement
  1569. if( mob_randomwalk(md,tick) )
  1570. return 0;
  1571. }
  1572. // Since he has finished walking, it stands by.
  1573. if( md->walkpath.path_len==0 || md->walkpath.path_pos>=md->walkpath.path_len )
  1574. md->state.skillstate=MSS_IDLE;
  1575. return 0;
  1576. }
  1577. /*==========================================
  1578. * Serious processing for mob in PC field of view (foreachclient)
  1579. *------------------------------------------
  1580. */
  1581. static int mob_ai_sub_foreachclient(struct map_session_data *sd,va_list ap)
  1582. {
  1583. unsigned int tick;
  1584. nullpo_retr(0, sd);
  1585. nullpo_retr(0, ap);
  1586. tick=va_arg(ap,unsigned int);
  1587. map_foreachinarea(mob_ai_sub_hard,sd->bl.m,
  1588. sd->bl.x-AREA_SIZE*2,sd->bl.y-AREA_SIZE*2,
  1589. sd->bl.x+AREA_SIZE*2,sd->bl.y+AREA_SIZE*2,
  1590. BL_MOB,tick);
  1591. return 0;
  1592. }
  1593. /*==========================================
  1594. * Serious processing for mob in PC field of view (interval timer function)
  1595. *------------------------------------------
  1596. */
  1597. static int mob_ai_hard(int tid,unsigned int tick,int id,int data)
  1598. {
  1599. clif_foreachclient(mob_ai_sub_foreachclient,tick);
  1600. return 0;
  1601. }
  1602. /*==========================================
  1603. * Negligent mode MOB AI (PC is not in near)
  1604. *------------------------------------------
  1605. */
  1606. static int mob_ai_sub_lazy(void * key,void * data,va_list app)
  1607. {
  1608. struct mob_data *md=data;
  1609. unsigned int tick;
  1610. va_list ap;
  1611. nullpo_retr(0, md);
  1612. nullpo_retr(0, app);
  1613. nullpo_retr(0, ap=va_arg(app,va_list));
  1614. if(md->bl.type!=BL_MOB)
  1615. return 0;
  1616. if(!md->bl.type || md->bl.type!=BL_MOB)
  1617. return 0;
  1618. tick=va_arg(ap,unsigned int);
  1619. if(DIFF_TICK(tick,md->last_thinktime)<MIN_MOBTHINKTIME*10)
  1620. return 0;
  1621. md->last_thinktime=tick;
  1622. if(md->bl.prev==NULL || md->skilltimer!=-1){
  1623. if(DIFF_TICK(tick,md->next_walktime)>MIN_MOBTHINKTIME*10)
  1624. md->next_walktime=tick;
  1625. return 0;
  1626. }
  1627. if(DIFF_TICK(md->next_walktime,tick)<0 &&
  1628. (mob_db[md->class].mode&1) && mob_can_move(md) ){
  1629. if( map[md->bl.m].users>0 ){
  1630. // Since PC is in the same map, somewhat better negligent processing is carried out.
  1631. // It sometimes moves.
  1632. if(rand()%1000<MOB_LAZYMOVEPERC)
  1633. mob_randomwalk(md,tick);
  1634. // MOB which is not not the summons MOB but BOSS, either sometimes reboils.
  1635. else if( rand()%1000<MOB_LAZYWARPPERC && md->x0<=0 && md->master_id!=0 &&
  1636. mob_db[md->class].mexp <= 0 && !(mob_db[md->class].mode & 0x20))
  1637. mob_spawn(md->bl.id);
  1638. }else{
  1639. // Since PC is not even in the same map, suitable processing is carried out even if it takes.
  1640. // MOB which is not BOSS which is not Summons MOB, either -- a case -- sometimes -- leaping
  1641. if( rand()%1000<MOB_LAZYWARPPERC && md->x0<=0 && md->master_id!=0 &&
  1642. mob_db[md->class].mexp <= 0 && !(mob_db[md->class].mode & 0x20))
  1643. mob_warp(md,-1,-1,-1,-1);
  1644. }
  1645. md->next_walktime = tick+rand()%10000+5000;
  1646. }
  1647. return 0;
  1648. }
  1649. /*==========================================
  1650. * Negligent processing for mob outside PC field of view (interval timer function)
  1651. *------------------------------------------
  1652. */
  1653. static int mob_ai_lazy(int tid,unsigned int tick,int id,int data)
  1654. {
  1655. map_foreachiddb(mob_ai_sub_lazy,tick);
  1656. return 0;
  1657. }
  1658. /*==========================================
  1659. * The structure object for item drop with delay
  1660. * Since it is only two being able to pass [ int ] a timer function
  1661. * Data is put in and passed to this structure object.
  1662. *------------------------------------------
  1663. */
  1664. struct delay_item_drop {
  1665. int m,x,y;
  1666. int nameid,amount;
  1667. struct map_session_data *first_sd,*second_sd,*third_sd;
  1668. };
  1669. struct delay_item_drop2 {
  1670. int m,x,y;
  1671. struct item item_data;
  1672. struct map_session_data *first_sd,*second_sd,*third_sd;
  1673. };
  1674. /*==========================================
  1675. * item drop with delay (timer function)
  1676. *------------------------------------------
  1677. */
  1678. static int mob_delay_item_drop(int tid,unsigned int tick,int id,int data)
  1679. {
  1680. struct delay_item_drop *ditem;
  1681. struct item temp_item;
  1682. int flag;
  1683. nullpo_retr(0, ditem=(struct delay_item_drop *)id);
  1684. memset(&temp_item,0,sizeof(temp_item));
  1685. temp_item.nameid = ditem->nameid;
  1686. temp_item.amount = ditem->amount;
  1687. temp_item.identify = !itemdb_isequip3(temp_item.nameid);
  1688. if(battle_config.item_auto_get){
  1689. if(ditem->first_sd && (flag = pc_additem(ditem->first_sd,&temp_item,ditem->amount))){
  1690. clif_additem(ditem->first_sd,0,0,flag);
  1691. map_addflooritem(&temp_item,1,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
  1692. }
  1693. free(ditem);
  1694. return 0;
  1695. }
  1696. map_addflooritem(&temp_item,1,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
  1697. free(ditem);
  1698. return 0;
  1699. }
  1700. /*==========================================
  1701. * item drop (timer function)-lootitem with delay
  1702. *------------------------------------------
  1703. */
  1704. static int mob_delay_item_drop2(int tid,unsigned int tick,int id,int data)
  1705. {
  1706. struct delay_item_drop2 *ditem;
  1707. int flag;
  1708. nullpo_retr(0, ditem=(struct delay_item_drop2 *)id);
  1709. if(battle_config.item_auto_get){
  1710. if(ditem->first_sd && (flag = pc_additem(ditem->first_sd,&ditem->item_data,ditem->item_data.amount))){
  1711. clif_additem(ditem->first_sd,0,0,flag);
  1712. map_addflooritem(&ditem->item_data,ditem->item_data.amount,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
  1713. }
  1714. free(ditem);
  1715. return 0;
  1716. }
  1717. map_addflooritem(&ditem->item_data,ditem->item_data.amount,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
  1718. free(ditem);
  1719. return 0;
  1720. }
  1721. /*==========================================
  1722. * mob data is erased.
  1723. *------------------------------------------
  1724. */
  1725. int mob_delete(struct mob_data *md)
  1726. {
  1727. nullpo_retr(1, md);
  1728. if(md->bl.prev == NULL)
  1729. return 1;
  1730. mob_changestate(md,MS_DEAD,0);
  1731. clif_clearchar_area(&md->bl,1);
  1732. map_delblock(&md->bl);
  1733. if(mob_get_viewclass(md->class) <= 1000)
  1734. clif_clearchar_delay(gettick()+3000,&md->bl,0);
  1735. mob_deleteslave(md);
  1736. mob_setdelayspawn(md->bl.id);
  1737. return 0;
  1738. }
  1739. int mob_catch_delete(struct mob_data *md,int type)
  1740. {
  1741. nullpo_retr(1, md);
  1742. if(md->bl.prev == NULL)
  1743. return 1;
  1744. mob_changestate(md,MS_DEAD,0);
  1745. clif_clearchar_area(&md->bl,type);
  1746. map_delblock(&md->bl);
  1747. mob_setdelayspawn(md->bl.id);
  1748. return 0;
  1749. }
  1750. int mob_timer_delete(int tid, unsigned int tick, int id, int data)
  1751. {
  1752. struct block_list *bl=map_id2bl(id);
  1753. struct mob_data *md;
  1754. nullpo_retr(0, bl);
  1755. md = (struct mob_data *)bl;
  1756. mob_catch_delete(md,3);
  1757. return 0;
  1758. }
  1759. /*==========================================
  1760. *
  1761. *------------------------------------------
  1762. */
  1763. int mob_deleteslave_sub(struct block_list *bl,va_list ap)
  1764. {
  1765. struct mob_data *md;
  1766. int id;
  1767. nullpo_retr(0, bl);
  1768. nullpo_retr(0, ap);
  1769. nullpo_retr(0, md = (struct mob_data *)bl);
  1770. id=va_arg(ap,int);
  1771. if(md->master_id > 0 && md->master_id == id )
  1772. mob_damage(NULL,md,md->hp,1);
  1773. return 0;
  1774. }
  1775. /*==========================================
  1776. *
  1777. *------------------------------------------
  1778. */
  1779. int mob_deleteslave(struct mob_data *md)
  1780. {
  1781. nullpo_retr(0, md);
  1782. map_foreachinarea(mob_deleteslave_sub, md->bl.m,
  1783. 0,0,map[md->bl.m].xs,map[md->bl.m].ys,
  1784. BL_MOB,md->bl.id);
  1785. return 0;
  1786. }
  1787. /*==========================================
  1788. * It is the damage of sd to damage to md.
  1789. *------------------------------------------
  1790. */
  1791. int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
  1792. {
  1793. int i,count,minpos,mindmg;
  1794. struct map_session_data *sd = NULL,*tmpsd[DAMAGELOG_SIZE];
  1795. struct {
  1796. struct party *p;
  1797. int id,base_exp,job_exp,zeny;
  1798. } pt[DAMAGELOG_SIZE];
  1799. int pnum=0;
  1800. int mvp_damage,max_hp;
  1801. unsigned int tick = gettick();
  1802. struct map_session_data *mvp_sd = NULL, *second_sd = NULL,*third_sd = NULL;
  1803. double tdmg,temp;
  1804. struct item item;
  1805. int ret;
  1806. int drop_rate;
  1807. int skill,sp;
  1808. nullpo_retr(0, md); //srcはNULLで呼ばれる場合もあるので、他でチェック
  1809. max_hp = battle_get_max_hp(&md->bl);
  1810. if(src && src->type == BL_PC) {
  1811. sd = (struct map_session_data *)src;
  1812. mvp_sd = sd;
  1813. }
  1814. // if(battle_config.battle_log)
  1815. // printf("mob_damage %d %d %d\n",md->hp,max_hp,damage);
  1816. if(md->bl.prev==NULL){
  1817. if(battle_config.error_log==1)
  1818. printf("mob_damage : BlockError!!\n");
  1819. return 0;
  1820. }
  1821. if(md->state.state==MS_DEAD || md->hp<=0) {
  1822. if(md->bl.prev != NULL) {
  1823. mob_changestate(md,MS_DEAD,0);
  1824. mobskill_use(md,tick,-1); // It is skill at the time of death.
  1825. clif_clearchar_area(&md->bl,1);
  1826. map_delblock(&md->bl);
  1827. mob_setdelayspawn(md->bl.id);
  1828. }
  1829. return 0;
  1830. }
  1831. if(md->sc_data[SC_ENDURE].timer == -1)
  1832. mob_stop_walking(md,3);
  1833. if(damage > max_hp>>2)
  1834. skill_stop_dancing(&md->bl,0);
  1835. if(md->hp > max_hp)
  1836. md->hp = max_hp;
  1837. // The amount of overkill rounds to hp.
  1838. if(damage>md->hp)
  1839. damage=md->hp;
  1840. if(!(type&2)) {
  1841. if(sd!=NULL){
  1842. for(i=0,minpos=0,mindmg=0x7fffffff;i<DAMAGELOG_SIZE;i++){
  1843. if(md->dmglog[i].id==sd->bl.id)
  1844. break;
  1845. if(md->dmglog[i].id==0){
  1846. minpos=i;
  1847. mindmg=0;
  1848. }
  1849. else if(md->dmglog[i].dmg<mindmg){
  1850. minpos=i;
  1851. mindmg=md->dmglog[i].dmg;
  1852. }
  1853. }
  1854. if(i<DAMAGELOG_SIZE)
  1855. md->dmglog[i].dmg+=damage;
  1856. else {
  1857. md->dmglog[minpos].id=sd->bl.id;
  1858. md->dmglog[minpos].dmg=damage;
  1859. }
  1860. if(md->attacked_id <= 0 && md->state.special_mob_ai==0)
  1861. md->attacked_id = sd->bl.id;
  1862. }
  1863. if(src && src->type == BL_PET && battle_config.pet_attack_exp_to_master==1) {
  1864. struct pet_data *pd = (struct pet_data *)src;
  1865. nullpo_retr(0, pd);
  1866. for(i=0,minpos=0,mindmg=0x7fffffff;i<DAMAGELOG_SIZE;i++){
  1867. if(md->dmglog[i].id==pd->msd->bl.id)
  1868. break;
  1869. if(md->dmglog[i].id==0){
  1870. minpos=i;
  1871. mindmg=0;
  1872. }
  1873. else if(md->dmglog[i].dmg<mindmg){
  1874. minpos=i;
  1875. mindmg=md->dmglog[i].dmg;
  1876. }
  1877. }
  1878. if(i<DAMAGELOG_SIZE)
  1879. md->dmglog[i].dmg+=(damage*battle_config.pet_attack_exp_rate)/100;
  1880. else {
  1881. md->dmglog[minpos].id=pd->msd->bl.id;
  1882. md->dmglog[minpos].dmg=(damage*battle_config.pet_attack_exp_rate)/100;
  1883. }
  1884. }
  1885. if(src && src->type == BL_MOB && ((struct mob_data*)src)->state.special_mob_ai){
  1886. struct mob_data *md2 = (struct mob_data *)src;
  1887. nullpo_retr(0, md2);
  1888. for(i=0,minpos=0,mindmg=0x7fffffff;i<DAMAGELOG_SIZE;i++){
  1889. if(md->dmglog[i].id==md2->master_id)
  1890. break;
  1891. if(md->dmglog[i].id==0){
  1892. minpos=i;
  1893. mindmg=0;
  1894. }
  1895. else if(md->dmglog[i].dmg<mindmg){
  1896. minpos=i;
  1897. mindmg=md->dmglog[i].dmg;
  1898. }
  1899. }
  1900. if(i<DAMAGELOG_SIZE)
  1901. md->dmglog[i].dmg+=damage;
  1902. else {
  1903. md->dmglog[minpos].id=md2->master_id;
  1904. md->dmglog[minpos].dmg=damage;
  1905. if(md->attacked_id <= 0 && md->state.special_mob_ai==0)
  1906. md->attacked_id = md2->master_id;
  1907. }
  1908. }
  1909. }
  1910. md->hp-=damage;
  1911. if(md->class >= 1285 && md->class <=1287) { // guardian hp update [Valaris]
  1912. struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
  1913. if(gc) {
  1914. if(md->bl.id==gc->GID0) {
  1915. gc->Ghp0=md->hp;
  1916. if(gc->Ghp0<=0) {
  1917. guild_castledatasave(gc->castle_id,10,0);
  1918. guild_castledatasave(gc->castle_id,18,0);
  1919. }
  1920. }
  1921. if(md->bl.id==gc->GID1) {
  1922. gc->Ghp1=md->hp;
  1923. if(gc->Ghp1<=0) {
  1924. guild_castledatasave(gc->castle_id,11,0);
  1925. guild_castledatasave(gc->castle_id,19,0);
  1926. }
  1927. }
  1928. if(md->bl.id==gc->GID2) {
  1929. gc->Ghp2=md->hp;
  1930. if(gc->Ghp2<=0) {
  1931. guild_castledatasave(gc->castle_id,12,0);
  1932. guild_castledatasave(gc->castle_id,20,0);
  1933. }
  1934. }
  1935. if(md->bl.id==gc->GID3) {
  1936. gc->Ghp3=md->hp;
  1937. if(gc->Ghp3<=0) {
  1938. guild_castledatasave(gc->castle_id,13,0);
  1939. guild_castledatasave(gc->castle_id,21,0);
  1940. }
  1941. }
  1942. if(md->bl.id==gc->GID4) {
  1943. gc->Ghp4=md->hp;
  1944. if(gc->Ghp4<=0) {
  1945. guild_castledatasave(gc->castle_id,14,0);
  1946. guild_castledatasave(gc->castle_id,22,0);
  1947. }
  1948. }
  1949. if(md->bl.id==gc->GID5) {
  1950. gc->Ghp5=md->hp;
  1951. if(gc->Ghp5<=0) {
  1952. guild_castledatasave(gc->castle_id,15,0);
  1953. guild_castledatasave(gc->castle_id,23,0);
  1954. }
  1955. }
  1956. if(md->bl.id==gc->GID6) {
  1957. gc->Ghp6=md->hp;
  1958. if(gc->Ghp6<=0) {
  1959. guild_castledatasave(gc->castle_id,16,0);
  1960. guild_castledatasave(gc->castle_id,24,0);
  1961. }
  1962. }
  1963. if(md->bl.id==gc->GID7) {
  1964. gc->Ghp7=md->hp;
  1965. if(gc->Ghp7<=0) {
  1966. guild_castledatasave(gc->castle_id,17,0);
  1967. guild_castledatasave(gc->castle_id,25,0);
  1968. }
  1969. }
  1970. }
  1971. } // end addition [Valaris]
  1972. if(md->option&2 )
  1973. skill_status_change_end(&md->bl, SC_HIDING, -1);
  1974. if(md->option&4 )
  1975. skill_status_change_end(&md->bl, SC_CLOAKING, -1);
  1976. if(md->state.special_mob_ai == 2){//スフィアーマイン
  1977. int skillidx=0;
  1978. if((skillidx=mob_skillid2skillidx(md->class,NPC_SELFDESTRUCTION2))>=0){
  1979. md->mode |= 0x1;
  1980. md->next_walktime=tick;
  1981. mobskill_use_id(md,&md->bl,skillidx);//自爆詠唱開始
  1982. md->state.special_mob_ai++;
  1983. }
  1984. if (md->master_id==src->id)
  1985. md->target_dir=map_calc_dir(src,md->bl.x,md->bl.y)+1;
  1986. }
  1987. if(md->hp>0){
  1988. return 0;
  1989. }
  1990. // ----- ここから死亡処理 -----
  1991. map_freeblock_lock();
  1992. mob_changestate(md,MS_DEAD,0);
  1993. mobskill_use(md,tick,-1); // 死亡時スキル
  1994. memset(tmpsd,0,sizeof(tmpsd));
  1995. memset(pt,0,sizeof(pt));
  1996. max_hp = battle_get_max_hp(&md->bl);
  1997. if(src && src->type == BL_MOB)
  1998. mob_unlocktarget((struct mob_data *)src,tick);
  1999. /* ソウルドレイン */
  2000. if(sd && sd->state.attack_type == BF_MAGIC && (skill=pc_checkskill(sd,HW_SOULDRAIN))>0){
  2001. clif_skill_nodamage(src,&md->bl,HW_SOULDRAIN,skill,1);
  2002. sp = (battle_get_lv(&md->bl))*(65+15*skill)/100;
  2003. if(sd->status.sp + sp > sd->status.max_sp)
  2004. sp = sd->status.max_sp - sd->status.sp;
  2005. sd->status.sp += sp;
  2006. clif_heal(sd->fd,SP_SP,sp);
  2007. }
  2008. // map外に消えた人は計算から除くので
  2009. // overkill分は無いけどsumはmax_hpとは違う
  2010. tdmg = 0;
  2011. for(i=0,count=0,mvp_damage=0;i<DAMAGELOG_SIZE;i++){
  2012. if(md->dmglog[i].id==0)
  2013. continue;
  2014. tmpsd[i] = map_id2sd(md->dmglog[i].id);
  2015. if(tmpsd[i] == NULL)
  2016. continue;
  2017. count++;
  2018. if(tmpsd[i]->bl.m != md->bl.m || pc_isdead(tmpsd[i]))
  2019. continue;
  2020. tdmg += (double)md->dmglog[i].dmg;
  2021. if(mvp_damage<md->dmglog[i].dmg){
  2022. third_sd = second_sd;
  2023. second_sd = mvp_sd;
  2024. mvp_sd=tmpsd[i];
  2025. mvp_damage=md->dmglog[i].dmg;
  2026. }
  2027. }
  2028. // [MouseJstr]
  2029. if((map[md->bl.m].flag.pvp == 0) || (battle_config.pvp_exp == 1)) {
  2030. /* if((double)max_hp < tdmg)
  2031. dmg_rate = ((double)max_hp) / tdmg;
  2032. else dmg_rate = 1;*/
  2033. // 経験値の分配
  2034. for(i=0;i<DAMAGELOG_SIZE;i++){
  2035. int pid,base_exp,job_exp,flag=1,zeny=0;
  2036. double per;
  2037. struct party *p;
  2038. if(tmpsd[i]==NULL || tmpsd[i]->bl.m != md->bl.m || pc_isdead(tmpsd[i]))
  2039. continue;
  2040. /* jAthena's exp formula
  2041. // per = ((double)md->dmglog[i].dmg)*(9.+(double)((count > 6)? 6:count))/10./((double)max_hp) * dmg_rate;
  2042. per = ((double)md->dmglog[i].dmg)*(9.+(double)((count > 6)? 6:count))/10./tdmg;
  2043. temp = ((double)mob_db[md->class].base_exp * (double)battle_config.base_exp_rate / 100. * per);
  2044. base_exp = (temp > 2147483647.)? 0x7fffffff:(int)temp;
  2045. if(mob_db[md->class].base_exp > 0 && base_exp < 1) base_exp = 1;
  2046. if(base_exp < 0) base_exp = 0;
  2047. temp = ((double)mob_db[md->class].job_exp * (double)battle_config.job_exp_rate / 100. * per);
  2048. job_exp = (temp > 2147483647.)? 0x7fffffff:(int)temp;
  2049. if(mob_db[md->class].job_exp > 0 && job_exp < 1) job_exp = 1;
  2050. if(job_exp < 0) job_exp = 0;
  2051. */
  2052. //eAthena's exp formula rather than jAthena's
  2053. per=(double)md->dmglog[i].dmg*256*(9+(double)((count > 6)? 6:count))/10/(double)max_hp;
  2054. if(per>512) per=512;
  2055. if(per<1) per=1;
  2056. base_exp=mob_db[md->class].base_exp*per/256;
  2057. if(base_exp < 1) base_exp = 1;
  2058. if(sd && md && battle_config.pk_mode==1 && (mob_db[md->class].lv - sd->status.base_level >= 20)) {
  2059. base_exp*=1.15; // pk_mode additional exp if monster >20 levels [Valaris]
  2060. }
  2061. job_exp=mob_db[md->class].job_exp*per/256;
  2062. if(job_exp < 1) job_exp = 1;
  2063. if(sd && md && battle_config.pk_mode==1 && (mob_db[md->class].lv - sd->status.base_level >= 20)) {
  2064. job_exp*=1.15; // pk_mode additional exp if monster >20 levels [Valaris]
  2065. }
  2066. if(md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1) { // for summoned creatures [Valaris]
  2067. base_exp = 0;
  2068. job_exp = 0;
  2069. }
  2070. else {
  2071. if(battle_config.zeny_from_mobs) {
  2072. if(md->level > 0) zeny=(md->level+rand()%md->level)*per/256; // zeny calculation moblv + random moblv [Valaris]
  2073. if(mob_db[md->class].mexp > 0)
  2074. zeny*=rand()%250;
  2075. }
  2076. if(battle_config.mobs_level_up && md->level > mob_db[md->class].lv) { // [Valaris]
  2077. job_exp+=((md->level-mob_db[md->class].lv)*mob_db[md->class].job_exp*.03)*per/256;
  2078. base_exp+=((md->level-mob_db[md->class].lv)*mob_db[md->class].base_exp*.03)*per/256;
  2079. }
  2080. }
  2081. if((pid=tmpsd[i]->status.party_id)>0){ // パーティに入っている
  2082. int j=0;
  2083. for(j=0;j<pnum;j++) // 公平パーティリストにいるかどうか
  2084. if(pt[j].id==pid)
  2085. break;
  2086. if(j==pnum){ // いないときは公平かどうか確認
  2087. if((p=party_search(pid))!=NULL && p->exp!=0){
  2088. pt[pnum].id=pid;
  2089. pt[pnum].p=p;
  2090. pt[pnum].base_exp=base_exp;
  2091. pt[pnum].job_exp=job_exp;
  2092. if(battle_config.zeny_from_mobs)
  2093. pt[pnum].zeny=zeny; // zeny share [Valaris]
  2094. pnum++;
  2095. flag=0;
  2096. }
  2097. }else{ // いるときは公平
  2098. pt[j].base_exp+=base_exp;
  2099. pt[j].job_exp+=job_exp;
  2100. if(battle_config.zeny_from_mobs)
  2101. pt[j].zeny+=zeny; // zeny share [Valaris]
  2102. flag=0;
  2103. }
  2104. }
  2105. if(flag) { // added zeny from mobs [Valaris]
  2106. if(base_exp > 0 || job_exp > 0)
  2107. pc_gainexp(tmpsd[i],base_exp,job_exp);
  2108. if (battle_config.zeny_from_mobs && zeny > 0) {
  2109. pc_getzeny(tmpsd[i],zeny); // zeny from mobs [Valaris]
  2110. }
  2111. }
  2112. }
  2113. // 公平分配
  2114. for(i=0;i<pnum;i++)
  2115. party_exp_share(pt[i].p,md->bl.m,pt[i].base_exp,pt[i].job_exp,pt[i].zeny);
  2116. // item drop
  2117. if(!(type&1)) {
  2118. int log_item[8] = {0};
  2119. for(i=0;i<8;i++){
  2120. struct delay_item_drop *ditem;
  2121. int drop_rate;
  2122. if(md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1) // Added [Valaris]
  2123. break; // End
  2124. if(mob_db[md->class].dropitem[i].nameid <= 0)
  2125. continue;
  2126. drop_rate = mob_db[md->class].dropitem[i].p;
  2127. if(drop_rate <= 0 && battle_config.drop_rate0item)
  2128. drop_rate = 1;
  2129. if(battle_config.drops_by_luk>0 && sd && md) drop_rate+=(sd->status.luk*battle_config.drops_by_luk)/100; // drops affected by luk [Valaris]
  2130. if(sd && md && battle_config.pk_mode==1 && (mob_db[md->class].lv - sd->status.base_level >= 20)) drop_rate*=1.25; // pk_mode increase drops if 20 level difference [Valaris]
  2131. if(drop_rate <= rand()%10000)
  2132. continue;
  2133. ditem=(struct delay_item_drop *)aCalloc(1,sizeof(struct delay_item_drop));
  2134. ditem->nameid = mob_db[md->class].dropitem[i].nameid;
  2135. log_item[i] = ditem->nameid;
  2136. ditem->amount = 1;
  2137. ditem->m = md->bl.m;
  2138. ditem->x = md->bl.x;
  2139. ditem->y = md->bl.y;
  2140. ditem->first_sd = mvp_sd;
  2141. ditem->second_sd = second_sd;
  2142. ditem->third_sd = third_sd;
  2143. add_timer(tick+500+i,mob_delay_item_drop,(int)ditem,0);
  2144. }
  2145. #ifndef TXT_ONLY
  2146. if(log_config.drop > 0)
  2147. log_drop(mvp_sd, md->class, log_item);
  2148. #endif
  2149. // Ore Discovery [Celest]
  2150. if (pc_checkskill(sd,BS_FINDINGORE)>0 && battle_config.finding_ore_rate/100 >= rand()%1000) {
  2151. struct delay_item_drop *ditem;
  2152. int itemid[17] = { 714, 756, 757, 969, 984, 985, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1002 };
  2153. ditem=(struct delay_item_drop *)aCalloc(1,sizeof(struct delay_item_drop));
  2154. ditem->nameid = itemid[rand()%17];
  2155. // log_item[i] = ditem->nameid;
  2156. ditem->amount = 1;
  2157. ditem->m = md->bl.m;
  2158. ditem->x = md->bl.x;
  2159. ditem->y = md->bl.y;
  2160. ditem->first_sd = mvp_sd;
  2161. ditem->second_sd = second_sd;
  2162. ditem->third_sd = third_sd;
  2163. add_timer(tick+500+i,mob_delay_item_drop,(int)ditem,0);
  2164. }
  2165. #ifndef TXT_ONLY
  2166. if(log_config.drop > 0)
  2167. log_drop(mvp_sd, md->class, log_item);
  2168. #endif
  2169. if(sd && sd->state.attack_type == BF_WEAPON) {
  2170. for(i=0;i<sd->monster_drop_item_count;i++) {
  2171. struct delay_item_drop *ditem;
  2172. int race = battle_get_race(&md->bl);
  2173. if(sd->monster_drop_itemid[i] <= 0)
  2174. continue;
  2175. if(sd->monster_drop_race[i] & (1<<race) ||
  2176. (mob_db[md->class].mode & 0x20 && sd->monster_drop_race[i] & 1<<10) ||
  2177. (!(mob_db[md->class].mode & 0x20) && sd->monster_drop_race[i] & 1<<11) ) {
  2178. if(sd->monster_drop_itemrate[i] <= rand()%10000)
  2179. continue;
  2180. ditem=(struct delay_item_drop *)aCalloc(1,sizeof(struct delay_item_drop));
  2181. ditem->nameid = sd->monster_drop_itemid[i];
  2182. ditem->amount = 1;
  2183. ditem->m = md->bl.m;
  2184. ditem->x = md->bl.x;
  2185. ditem->y = md->bl.y;
  2186. ditem->first_sd = mvp_sd;
  2187. ditem->second_sd = second_sd;
  2188. ditem->third_sd = third_sd;
  2189. add_timer(tick+520+i,mob_delay_item_drop,(int)ditem,0);
  2190. }
  2191. }
  2192. if(sd->get_zeny_num > 0)
  2193. pc_getzeny(sd,mob_db[md->class].lv*10 + rand()%(sd->get_zeny_num+1));
  2194. }
  2195. if(md->lootitem) {
  2196. for(i=0;i<md->lootitem_count;i++) {
  2197. struct delay_item_drop2 *ditem;
  2198. ditem=(struct delay_item_drop2 *)aCalloc(1,sizeof(struct delay_item_drop2));
  2199. memcpy(&ditem->item_data,&md->lootitem[i],sizeof(md->lootitem[0]));
  2200. ditem->m = md->bl.m;
  2201. ditem->x = md->bl.x;
  2202. ditem->y = md->bl.y;
  2203. ditem->first_sd = mvp_sd;
  2204. ditem->second_sd = second_sd;
  2205. ditem->third_sd = third_sd;
  2206. add_timer(tick+540+i,mob_delay_item_drop2,(int)ditem,0);
  2207. }
  2208. }
  2209. }
  2210. // mvp処理
  2211. if(mvp_sd && mob_db[md->class].mexp > 0 ){
  2212. int log_mvp[2] = {0};
  2213. int j;
  2214. int mexp;
  2215. temp = ((double)mob_db[md->class].mexp * (9.+(double)count)/10.); //[Gengar]
  2216. mexp = (temp > 2147483647.)? 0x7fffffff:(int)temp;
  2217. if(mexp < 1) mexp = 1;
  2218. clif_mvp_effect(mvp_sd); // エフェクト
  2219. clif_mvp_exp(mvp_sd,mexp);
  2220. pc_gainexp(mvp_sd,mexp,0);
  2221. log_mvp[1] = mexp;
  2222. for(j=0;j<3;j++){
  2223. i = rand() % 3;
  2224. if(mob_db[md->class].mvpitem[i].nameid <= 0)
  2225. continue;
  2226. drop_rate = mob_db[md->class].mvpitem[i].p;
  2227. if(drop_rate <= 0 && battle_config.drop_rate0item)
  2228. drop_rate = 1;
  2229. if(drop_rate < battle_config.item_drop_mvp_min)
  2230. drop_rate = battle_config.item_drop_mvp_min;
  2231. if(drop_rate > battle_config.item_drop_mvp_max)
  2232. drop_rate = battle_config.item_drop_mvp_max;
  2233. if(drop_rate <= rand()%10000)
  2234. continue;
  2235. memset(&item,0,sizeof(item));
  2236. item.nameid=mob_db[md->class].mvpitem[i].nameid;
  2237. item.identify=!itemdb_isequip3(item.nameid);
  2238. clif_mvp_item(mvp_sd,item.nameid);
  2239. log_mvp[0] = item.nameid;
  2240. if(mvp_sd->weight*2 > mvp_sd->max_weight)
  2241. map_addflooritem(&item,1,mvp_sd->bl.m,mvp_sd->bl.x,mvp_sd->bl.y,mvp_sd,second_sd,third_sd,1);
  2242. else if((ret = pc_additem(mvp_sd,&item,1))) {
  2243. clif_additem(sd,0,0,ret);
  2244. map_addflooritem(&item,1,mvp_sd->bl.m,mvp_sd->bl.x,mvp_sd->bl.y,mvp_sd,second_sd,third_sd,1);
  2245. }
  2246. break;
  2247. }
  2248. #ifndef TXT_ONLY
  2249. if(log_config.mvpdrop > 0)
  2250. log_mvpdrop(mvp_sd, md->class, log_mvp);
  2251. #endif
  2252. }
  2253. } // [MouseJstr]
  2254. // <Agit> NPC Event [OnAgitBreak]
  2255. if(md->npc_event[0] && strcmp(((md->npc_event)+strlen(md->npc_event)-13),"::OnAgitBreak") == 0) {
  2256. printf("MOB.C: Run NPC_Event[OnAgitBreak].\n");
  2257. if (agit_flag == 1) //Call to Run NPC_Event[OnAgitBreak]
  2258. guild_agit_break(md);
  2259. }
  2260. // SCRIPT実行
  2261. if(md->npc_event[0]){
  2262. // if(battle_config.battle_log)
  2263. // printf("mob_damage : run event : %s\n",md->npc_event);
  2264. if(src && src->type == BL_PET)
  2265. sd = ((struct pet_data *)src)->msd;
  2266. if(sd == NULL) {
  2267. if(mvp_sd != NULL)
  2268. sd = mvp_sd;
  2269. else {
  2270. struct map_session_data *tmpsd;
  2271. int i;
  2272. for(i=0;i<fd_max;i++){
  2273. if(session[i] && (tmpsd=session[i]->session_data) && tmpsd->state.auth) {
  2274. if(md->bl.m == tmpsd->bl.m) {
  2275. sd = tmpsd;
  2276. break;
  2277. }
  2278. }
  2279. }
  2280. }
  2281. }
  2282. if(sd)
  2283. npc_event(sd,md->npc_event,0);
  2284. }
  2285. clif_clearchar_area(&md->bl,1);
  2286. if(md->level) md->level=0;
  2287. map_delblock(&md->bl);
  2288. if(mob_get_viewclass(md->class) <= 1000)
  2289. clif_clearchar_delay(tick+3000,&md->bl,0);
  2290. mob_deleteslave(md);
  2291. mob_setdelayspawn(md->bl.id);
  2292. map_freeblock_unlock();
  2293. return 0;
  2294. }
  2295. /*==========================================
  2296. *
  2297. *------------------------------------------
  2298. */
  2299. int mob_class_change(struct mob_data *md,int *value)
  2300. {
  2301. unsigned int tick = gettick();
  2302. int i,c,hp_rate,max_hp,class,count = 0;
  2303. nullpo_retr(0, md);
  2304. nullpo_retr(0, value);
  2305. if(value[0]<=1000 || value[0]>MAX_MOB_DB)
  2306. return 0;
  2307. if(md->bl.prev == NULL) return 0;
  2308. while(count < 5 && value[count] > 1000 && value[count] <= MAX_MOB_DB) count++;
  2309. if(count < 1) return 0;
  2310. class = value[rand()%count];
  2311. if(class<=1000 || class>MAX_MOB_DB) return 0;
  2312. max_hp = battle_get_max_hp(&md->bl);
  2313. hp_rate = md->hp*100/max_hp;
  2314. clif_mob_class_change(md,class);
  2315. md->class = class;
  2316. max_hp = battle_get_max_hp(&md->bl);
  2317. if(battle_config.monster_class_change_full_recover==1) {
  2318. md->hp = max_hp;
  2319. memset(md->dmglog,0,sizeof(md->dmglog));
  2320. }
  2321. else
  2322. md->hp = max_hp*hp_rate/100;
  2323. if(md->hp > max_hp) md->hp = max_hp;
  2324. else if(md->hp < 1) md->hp = 1;
  2325. memcpy(md->name,mob_db[class].jname,24);
  2326. memset(&md->state,0,sizeof(md->state));
  2327. md->attacked_id = 0;
  2328. md->target_id = 0;
  2329. md->move_fail_count = 0;
  2330. md->speed = mob_db[md->class].speed;
  2331. md->def_ele = mob_db[md->class].element;
  2332. mob_changestate(md,MS_IDLE,0);
  2333. skill_castcancel(&md->bl,0);
  2334. md->state.skillstate = MSS_IDLE;
  2335. md->last_thinktime = tick;
  2336. md->next_walktime = tick+rand()%50+5000;
  2337. md->attackabletime = tick;
  2338. md->canmove_tick = tick;
  2339. for(i=0,c=tick-1000*3600*10;i<MAX_MOBSKILL;i++)
  2340. md->skilldelay[i] = c;
  2341. md->skillid=0;
  2342. md->skilllv=0;
  2343. if(md->lootitem == NULL && mob_db[class].mode&0x02)
  2344. md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
  2345. skill_clear_unitgroup(&md->bl);
  2346. skill_cleartimerskill(&md->bl);
  2347. clif_clearchar_area(&md->bl,0);
  2348. clif_spawnmob(md);
  2349. return 0;
  2350. }
  2351. /*==========================================
  2352. * mob回復
  2353. *------------------------------------------
  2354. */
  2355. int mob_heal(struct mob_data *md,int heal)
  2356. {
  2357. int max_hp = battle_get_max_hp(&md->bl);
  2358. nullpo_retr(0, md);
  2359. md->hp += heal;
  2360. if( max_hp < md->hp )
  2361. md->hp = max_hp;
  2362. if(md->class >= 1285 && md->class <=1287) { // guardian hp update [Valaris]
  2363. struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
  2364. if(gc) {
  2365. if(md->bl.id==gc->GID0) gc->Ghp0=md->hp;
  2366. if(md->bl.id==gc->GID1) gc->Ghp1=md->hp;
  2367. if(md->bl.id==gc->GID2) gc->Ghp2=md->hp;
  2368. if(md->bl.id==gc->GID3) gc->Ghp3=md->hp;
  2369. if(md->bl.id==gc->GID4) gc->Ghp4=md->hp;
  2370. if(md->bl.id==gc->GID5) gc->Ghp5=md->hp;
  2371. if(md->bl.id==gc->GID6) gc->Ghp6=md->hp;
  2372. if(md->bl.id==gc->GID7) gc->Ghp7=md->hp;
  2373. }
  2374. } // end addition [Valaris]
  2375. return 0;
  2376. }
  2377. /*==========================================
  2378. * Added by RoVeRT
  2379. *------------------------------------------
  2380. */
  2381. int mob_warpslave_sub(struct block_list *bl,va_list ap)
  2382. {
  2383. struct mob_data *md=(struct mob_data *)bl;
  2384. int id,x,y;
  2385. id=va_arg(ap,int);
  2386. x=va_arg(ap,int);
  2387. y=va_arg(ap,int);
  2388. if( md->master_id==id ) {
  2389. mob_warp(md,-1,x,y,2);
  2390. }
  2391. return 0;
  2392. }
  2393. /*==========================================
  2394. * Added by RoVeRT
  2395. *------------------------------------------
  2396. */
  2397. int mob_warpslave(struct mob_data *md,int x, int y)
  2398. {
  2399. //printf("warp slave\n");
  2400. map_foreachinarea(mob_warpslave_sub, md->bl.m,
  2401. x-AREA_SIZE,y-AREA_SIZE,
  2402. x+AREA_SIZE,y+AREA_SIZE,BL_MOB,
  2403. md->bl.id, md->bl.x, md->bl.y );
  2404. return 0;
  2405. }
  2406. /*==========================================
  2407. * mobワープ
  2408. *------------------------------------------
  2409. */
  2410. int mob_warp(struct mob_data *md,int m,int x,int y,int type)
  2411. {
  2412. int i=0,xs=0,ys=0,bx=x,by=y;
  2413. nullpo_retr(0, md);
  2414. if( md->bl.prev==NULL )
  2415. return 0;
  2416. if( m<0 ) m=md->bl.m;
  2417. if(type >= 0) {
  2418. if(map[md->bl.m].flag.monster_noteleport)
  2419. return 0;
  2420. clif_clearchar_area(&md->bl,type);
  2421. }
  2422. skill_unit_out_all(&md->bl,gettick(),1);
  2423. map_delblock(&md->bl);
  2424. if(bx>0 && by>0){ // 位置指定の場合周囲9セルを探索
  2425. xs=ys=9;
  2426. }
  2427. while( ( x<0 || y<0 || map_getcell(m,x,y,CELL_CHKNOPASS)) && (i++)<1000 ){
  2428. if( xs>0 && ys>0 && i<250 ){ // 指定位置付近の探索
  2429. x=bx+rand()%xs-xs/2;
  2430. y=by+rand()%ys-ys/2;
  2431. }else{ // 完全ランダム探索
  2432. x=rand()%(map[m].xs-2)+1;
  2433. y=rand()%(map[m].ys-2)+1;
  2434. }
  2435. }
  2436. md->dir=0;
  2437. if(i<1000){
  2438. md->bl.x=md->to_x=x;
  2439. md->bl.y=md->to_y=y;
  2440. md->bl.m=m;
  2441. }else {
  2442. m=md->bl.m;
  2443. if(battle_config.error_log==1)
  2444. printf("MOB %d warp failed, class = %d\n",md->bl.id,md->class);
  2445. }
  2446. md->target_id=0; // タゲを解除する
  2447. md->state.targettype=NONE_ATTACKABLE;
  2448. md->attacked_id=0;
  2449. md->state.skillstate=MSS_IDLE;
  2450. mob_changestate(md,MS_IDLE,0);
  2451. if(type>0 && i==1000) {
  2452. if(battle_config.battle_log)
  2453. printf("MOB %d warp to (%d,%d), class = %d\n",md->bl.id,x,y,md->class);
  2454. }
  2455. map_addblock(&md->bl);
  2456. if(type>0)
  2457. {
  2458. clif_spawnmob(md);
  2459. mob_warpslave(md,md->bl.x,md->bl.y);
  2460. }
  2461. return 0;
  2462. }
  2463. /*==========================================
  2464. * 画面内の取り巻きの数計算用(foreachinarea)
  2465. *------------------------------------------
  2466. */
  2467. int mob_countslave_sub(struct block_list *bl,va_list ap)
  2468. {
  2469. int id,*c;
  2470. struct mob_data *md;
  2471. id=va_arg(ap,int);
  2472. nullpo_retr(0, bl);
  2473. nullpo_retr(0, ap);
  2474. nullpo_retr(0, c=va_arg(ap,int *));
  2475. nullpo_retr(0, md = (struct mob_data *)bl);
  2476. if( md->master_id==id )
  2477. (*c)++;
  2478. return 0;
  2479. }
  2480. /*==========================================
  2481. * 画面内の取り巻きの数計算
  2482. *------------------------------------------
  2483. */
  2484. int mob_countslave(struct mob_data *md)
  2485. {
  2486. int c=0;
  2487. nullpo_retr(0, md);
  2488. map_foreachinarea(mob_countslave_sub, md->bl.m,
  2489. 0,0,map[md->bl.m].xs-1,map[md->bl.m].ys-1,
  2490. BL_MOB,md->bl.id,&c);
  2491. return c;
  2492. }
  2493. /*==========================================
  2494. * 手下MOB召喚
  2495. *------------------------------------------
  2496. */
  2497. int mob_summonslave(struct mob_data *md2,int *value,int amount,int flag)
  2498. {
  2499. struct mob_data *md;
  2500. int bx,by,m,count = 0,class,k,a = amount;
  2501. nullpo_retr(0, md2);
  2502. nullpo_retr(0, value);
  2503. bx=md2->bl.x;
  2504. by=md2->bl.y;
  2505. m=md2->bl.m;
  2506. if(value[0]<=1000 || value[0]>MAX_MOB_DB) // 値が異常なら召喚を止める
  2507. return 0;
  2508. while(count < 21 && value[count] > 1000 && value[count] <= 2000) count++;
  2509. if(count < 1) return 0;
  2510. for(k=0;k<count;k++) {
  2511. amount = a;
  2512. class = value[k];
  2513. if(class<=1000 || class>MAX_MOB_DB) continue;
  2514. for(;amount>0;amount--){
  2515. int x=0,y=0,i=0;
  2516. md=(struct mob_data *)aCalloc(1,sizeof(struct mob_data));
  2517. if(mob_db[class].mode&0x02)
  2518. md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
  2519. else
  2520. md->lootitem=NULL;
  2521. while((x<=0 || y<=0 || map_getcell(m,x,y,CELL_CHKNOPASS)) && (i++)<100){
  2522. x=rand()%9-4+bx;
  2523. y=rand()%9-4+by;
  2524. }
  2525. if(i>=100){
  2526. x=bx;
  2527. y=by;
  2528. }
  2529. mob_spawn_dataset(md,"--ja--",class);
  2530. md->bl.m=m;
  2531. md->bl.x=x;
  2532. md->bl.y=y;
  2533. md->m =m;
  2534. md->x0=x;
  2535. md->y0=y;
  2536. md->xs=0;
  2537. md->ys=0;
  2538. md->speed=md2->speed;
  2539. md->spawndelay1=-1; // 一度のみフラグ
  2540. md->spawndelay2=-1; // 一度のみフラグ
  2541. memset(md->npc_event,0,sizeof(md->npc_event));
  2542. md->bl.type=BL_MOB;
  2543. map_addiddb(&md->bl);
  2544. mob_spawn(md->bl.id);
  2545. clif_skill_nodamage(&md->bl,&md->bl,(flag)? NPC_SUMMONSLAVE:NPC_SUMMONMONSTER,a,1);
  2546. if(flag)
  2547. md->master_id=md2->bl.id;
  2548. }
  2549. }
  2550. return 0;
  2551. }
  2552. /*==========================================
  2553. * 自分をロックしているPCの数を数える(foreachclient)
  2554. *------------------------------------------
  2555. */
  2556. static int mob_counttargeted_sub(struct block_list *bl,va_list ap)
  2557. {
  2558. int id,*c,target_lv;
  2559. struct block_list *src;
  2560. id=va_arg(ap,int);
  2561. nullpo_retr(0, bl);
  2562. nullpo_retr(0, ap);
  2563. nullpo_retr(0, c=va_arg(ap,int *));
  2564. src=va_arg(ap,struct block_list *);
  2565. target_lv=va_arg(ap,int);
  2566. if(id == bl->id || (src && id == src->id)) return 0;
  2567. if(bl->type == BL_PC) {
  2568. struct map_session_data *sd = (struct map_session_data *)bl;
  2569. if(sd && sd->attacktarget == id && sd->attacktimer != -1 && sd->attacktarget_lv >= target_lv)
  2570. (*c)++;
  2571. }
  2572. else if(bl->type == BL_MOB) {
  2573. struct mob_data *md = (struct mob_data *)bl;
  2574. if(md && md->target_id == id && md->timer != -1 && md->state.state == MS_ATTACK && md->target_lv >= target_lv)
  2575. (*c)++;
  2576. }
  2577. else if(bl->type == BL_PET) {
  2578. struct pet_data *pd = (struct pet_data *)bl;
  2579. if(pd->target_id == id && pd->timer != -1 && pd->state.state == MS_ATTACK && pd->target_lv >= target_lv)
  2580. (*c)++;
  2581. }
  2582. return 0;
  2583. }
  2584. /*==========================================
  2585. * 自分をロックしているPCの数を数える
  2586. *------------------------------------------
  2587. */
  2588. int mob_counttargeted(struct mob_data *md,struct block_list *src,int target_lv)
  2589. {
  2590. int c=0;
  2591. nullpo_retr(0, md);
  2592. map_foreachinarea(mob_counttargeted_sub, md->bl.m,
  2593. md->bl.x-AREA_SIZE,md->bl.y-AREA_SIZE,
  2594. md->bl.x+AREA_SIZE,md->bl.y+AREA_SIZE,0,md->bl.id,&c,src,target_lv);
  2595. return c;
  2596. }
  2597. /*==========================================
  2598. *MOBskillから該当skillidのskillidxを返す
  2599. *------------------------------------------
  2600. */
  2601. int mob_skillid2skillidx(int class,int skillid)
  2602. {
  2603. int i;
  2604. struct mob_skill *ms=mob_db[class].skill;
  2605. if(ms==NULL)
  2606. return -1;
  2607. for(i=0;i<mob_db[class].maxskill;i++){
  2608. if(ms[i].skill_id == skillid)
  2609. return i;
  2610. }
  2611. return -1;
  2612. }
  2613. //
  2614. // MOBスキル
  2615. //
  2616. /*==========================================
  2617. * スキル使用(詠唱完了、ID指定)
  2618. *------------------------------------------
  2619. */
  2620. int mobskill_castend_id( int tid, unsigned int tick, int id,int data )
  2621. {
  2622. struct mob_data* md=NULL;
  2623. struct block_list *bl;
  2624. struct block_list *mbl;
  2625. int range;
  2626. if((mbl = map_id2bl(id)) == NULL ) //詠唱したMobがもういないというのは良くある正常処理
  2627. return 0;
  2628. if((md=(struct mob_data *)mbl) == NULL ){
  2629. printf("mobskill_castend_id nullpo mbl->id:%d\n",mbl->id);
  2630. return 0;
  2631. }
  2632. if( md->bl.type!=BL_MOB || md->bl.prev==NULL )
  2633. return 0;
  2634. if( md->skilltimer != tid ) // タイマIDの確認
  2635. return 0;
  2636. md->skilltimer=-1;
  2637. //沈黙や状態異常など
  2638. if(md->sc_data){
  2639. if(md->opt1>0 || md->sc_data[SC_DIVINA].timer != -1 || md->sc_data[SC_ROKISWEIL].timer != -1 || md->sc_data[SC_STEELBODY].timer != -1)
  2640. return 0;
  2641. if(md->sc_data[SC_AUTOCOUNTER].timer != -1 && md->skillid != KN_AUTOCOUNTER) //オートカウンター
  2642. return 0;
  2643. if(md->sc_data[SC_BLADESTOP].timer != -1) //白刃取り
  2644. return 0;
  2645. if(md->sc_data[SC_BERSERK].timer != -1) //バーサーク
  2646. return 0;
  2647. }
  2648. if(md->skillid != NPC_EMOTION)
  2649. md->last_thinktime=tick + battle_get_adelay(&md->bl);
  2650. if((bl = map_id2bl(md->skilltarget)) == NULL || bl->prev==NULL){ //スキルターゲットが存在しない
  2651. //printf("mobskill_castend_id nullpo\n");//ターゲットがいないときはnullpoじゃなくて普通に終了
  2652. return 0;
  2653. }
  2654. if(md->bl.m != bl->m)
  2655. return 0;
  2656. if(md->skillid == PR_LEXAETERNA) {
  2657. struct status_change *sc_data = battle_get_sc_data(bl);
  2658. if(sc_data && (sc_data[SC_FREEZE].timer != -1 || (sc_data[SC_STONE].timer != -1 && sc_data[SC_STONE].val2 == 0)))
  2659. return 0;
  2660. }
  2661. else if(md->skillid == RG_BACKSTAP) {
  2662. int dir = map_calc_dir(&md->bl,bl->x,bl->y),t_dir = battle_get_dir(bl);
  2663. int dist = distance(md->bl.x,md->bl.y,bl->x,bl->y);
  2664. if(bl->type != BL_SKILL && (dist == 0 || map_check_dir(dir,t_dir)))
  2665. return 0;
  2666. }
  2667. if( ( (skill_get_inf(md->skillid)&1) || (skill_get_inf2(md->skillid)&4) ) && // 彼我敵対関係チェック
  2668. battle_check_target(&md->bl,bl, BCT_ENEMY)<=0 )
  2669. return 0;
  2670. range = skill_get_range(md->skillid,md->skilllv);
  2671. if(range < 0)
  2672. range = battle_get_range(&md->bl) - (range + 1);
  2673. if(range + battle_config.mob_skill_add_range < distance(md->bl.x,md->bl.y,bl->x,bl->y))
  2674. return 0;
  2675. md->skilldelay[md->skillidx]=tick;
  2676. if(battle_config.mob_skill_log)
  2677. printf("MOB skill castend skill=%d, class = %d\n",md->skillid,md->class);
  2678. // mob_stop_walking(md,0);
  2679. switch( skill_get_nk(md->skillid) )
  2680. {
  2681. // 攻撃系/吹き飛ばし系
  2682. case 0: case 2:
  2683. skill_castend_damage_id(&md->bl,bl,md->skillid,md->skilllv,tick,0);
  2684. break;
  2685. case 1:// 支援系
  2686. if(!mob_db[md->class].skill[md->skillidx].val[0] &&
  2687. (md->skillid==AL_HEAL || (md->skillid==ALL_RESURRECTION && bl->type != BL_PC)) && battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl)) )
  2688. skill_castend_damage_id(&md->bl,bl,md->skillid,md->skilllv,tick,0);
  2689. else
  2690. skill_castend_nodamage_id(&md->bl,bl,md->skillid,md->skilllv,tick,0);
  2691. break;
  2692. }
  2693. return 0;
  2694. }
  2695. /*==========================================
  2696. * スキル使用(詠唱完了、場所指定)
  2697. *------------------------------------------
  2698. */
  2699. int mobskill_castend_pos( int tid, unsigned int tick, int id,int data )
  2700. {
  2701. struct mob_data* md=NULL;
  2702. struct block_list *bl;
  2703. int range,maxcount;
  2704. //mobskill_castend_id同様詠唱したMobが詠唱完了時にもういないというのはありそうなのでnullpoから除外
  2705. if((bl=map_id2bl(id))==NULL)
  2706. return 0;
  2707. nullpo_retr(0, md=(struct mob_data *)bl);
  2708. if( md->bl.type!=BL_MOB || md->bl.prev==NULL )
  2709. return 0;
  2710. if( md->skilltimer != tid ) // タイマIDの確認
  2711. return 0;
  2712. md->skilltimer=-1;
  2713. if(md->sc_data){
  2714. if(md->opt1>0 || md->sc_data[SC_DIVINA].timer != -1 || md->sc_data[SC_ROKISWEIL].timer != -1 || md->sc_data[SC_STEELBODY].timer != -1)
  2715. return 0;
  2716. if(md->sc_data[SC_AUTOCOUNTER].timer != -1 && md->skillid != KN_AUTOCOUNTER) //オートカウンター
  2717. return 0;
  2718. if(md->sc_data[SC_BLADESTOP].timer != -1) //白刃取り
  2719. return 0;
  2720. if(md->sc_data[SC_BERSERK].timer != -1) //バーサーク
  2721. return 0;
  2722. }
  2723. if(battle_config.monster_skill_reiteration == 0) {
  2724. range = -1;
  2725. switch(md->skillid) {
  2726. case MG_SAFETYWALL:
  2727. case WZ_FIREPILLAR:
  2728. case HT_SKIDTRAP:
  2729. case HT_LANDMINE:
  2730. case HT_ANKLESNARE:
  2731. case HT_SHOCKWAVE:
  2732. case HT_SANDMAN:
  2733. case HT_FLASHER:
  2734. case HT_FREEZINGTRAP:
  2735. case HT_BLASTMINE:
  2736. case HT_CLAYMORETRAP:
  2737. case PF_SPIDERWEB: /* スパイダーウェッブ */
  2738. range = 0;
  2739. break;
  2740. case AL_PNEUMA:
  2741. case AL_WARP:
  2742. range = 1;
  2743. break;
  2744. }
  2745. if(range >= 0) {
  2746. if(skill_check_unit_range(md->bl.m,md->skillx,md->skilly,range,md->skillid) > 0)
  2747. return 0;
  2748. }
  2749. }
  2750. if(battle_config.monster_skill_nofootset) {
  2751. range = -1;
  2752. switch(md->skillid) {
  2753. case WZ_FIREPILLAR:
  2754. case HT_SKIDTRAP:
  2755. case HT_LANDMINE:
  2756. case HT_ANKLESNARE:
  2757. case HT_SHOCKWAVE:
  2758. case HT_SANDMAN:
  2759. case HT_FLASHER:
  2760. case HT_FREEZINGTRAP:
  2761. case HT_BLASTMINE:
  2762. case HT_CLAYMORETRAP:
  2763. case AM_DEMONSTRATION:
  2764. case PF_SPIDERWEB: /* スパイダーウェッブ */
  2765. range = 1;
  2766. break;
  2767. case AL_WARP:
  2768. range = 0;
  2769. break;
  2770. }
  2771. if(range >= 0) {
  2772. if(skill_check_unit_range2(md->bl.m,md->skillx,md->skilly,range) > 0)
  2773. return 0;
  2774. }
  2775. }
  2776. if(battle_config.monster_land_skill_limit) {
  2777. maxcount = skill_get_maxcount(md->skillid);
  2778. if(maxcount > 0) {
  2779. int i,c;
  2780. for(i=c=0;i<MAX_MOBSKILLUNITGROUP;i++) {
  2781. if(md->skillunit[i].alive_count > 0 && md->skillunit[i].skill_id == md->skillid)
  2782. c++;
  2783. }
  2784. if(c >= maxcount)
  2785. return 0;
  2786. }
  2787. }
  2788. range = skill_get_range(md->skillid,md->skilllv);
  2789. if(range < 0)
  2790. range = battle_get_range(&md->bl) - (range + 1);
  2791. if(range + battle_config.mob_skill_add_range < distance(md->bl.x,md->bl.y,md->skillx,md->skilly))
  2792. return 0;
  2793. md->skilldelay[md->skillidx]=tick;
  2794. if(battle_config.mob_skill_log)
  2795. printf("MOB skill castend skill=%d, class = %d\n",md->skillid,md->class);
  2796. // mob_stop_walking(md,0);
  2797. skill_castend_pos2(&md->bl,md->skillx,md->skilly,md->skillid,md->skilllv,tick,0);
  2798. return 0;
  2799. }
  2800. /*==========================================
  2801. * Skill use (an aria start, ID specification)
  2802. *------------------------------------------
  2803. */
  2804. int mobskill_use_id(struct mob_data *md,struct block_list *target,int skill_idx)
  2805. {
  2806. int casttime,range;
  2807. struct mob_skill *ms;
  2808. int skill_id, skill_lv, forcecast = 0;
  2809. nullpo_retr(0, md);
  2810. nullpo_retr(0, ms=&mob_db[md->class].skill[skill_idx]);
  2811. if( target==NULL && (target=map_id2bl(md->target_id))==NULL )
  2812. return 0;
  2813. if( target->prev==NULL || md->bl.prev==NULL )
  2814. return 0;
  2815. skill_id=ms->skill_id;
  2816. skill_lv=ms->skill_lv;
  2817. // 沈黙や異常
  2818. if(md->sc_data){
  2819. if(md->opt1>0 || md->sc_data[SC_DIVINA].timer != -1 || md->sc_data[SC_ROKISWEIL].timer != -1 || md->sc_data[SC_STEELBODY].timer != -1)
  2820. return 0;
  2821. if(md->sc_data[SC_AUTOCOUNTER].timer != -1 && md->skillid != KN_AUTOCOUNTER) //オートカウンター
  2822. return 0;
  2823. if(md->sc_data[SC_BLADESTOP].timer != -1) //白刃取り
  2824. return 0;
  2825. if(md->sc_data[SC_BERSERK].timer != -1) //バーサーク
  2826. return 0;
  2827. }
  2828. if(md->option&4 && skill_id==TF_HIDING)
  2829. return 0;
  2830. if(md->option&2 && skill_id!=TF_HIDING && skill_id!=AS_GRIMTOOTH && skill_id!=RG_BACKSTAP && skill_id!=RG_RAID)
  2831. return 0;
  2832. if(map[md->bl.m].flag.gvg && (skill_id == SM_ENDURE || skill_id == AL_TELEPORT || skill_id == AL_WARP ||
  2833. skill_id == WZ_ICEWALL || skill_id == TF_BACKSLIDING))
  2834. return 0;
  2835. if(skill_get_inf2(skill_id)&0x200 && md->bl.id == target->id)
  2836. return 0;
  2837. // 射程と障害物チェック
  2838. range = skill_get_range(skill_id,skill_lv);
  2839. if(range < 0)
  2840. range = battle_get_range(&md->bl) - (range + 1);
  2841. if(!battle_check_range(&md->bl,target,range))
  2842. return 0;
  2843. // delay=skill_delayfix(&md->bl, skill_get_delay( skill_id,skill_lv) );
  2844. casttime=skill_castfix(&md->bl,ms->casttime);
  2845. md->state.skillcastcancel=ms->cancel;
  2846. md->skilldelay[skill_idx]=gettick();
  2847. switch(skill_id){ /* 何か特殊な処理が必要 */
  2848. case ALL_RESURRECTION: /* リザレクション */
  2849. if(target->type != BL_PC && battle_check_undead(battle_get_race(target),battle_get_elem_type(target))){ /* 敵がアンデッドなら */
  2850. forcecast=1; /* ターンアンデットと同じ詠唱時間 */
  2851. casttime=skill_castfix(&md->bl, skill_get_cast(PR_TURNUNDEAD,skill_lv) );
  2852. }
  2853. break;
  2854. case MO_EXTREMITYFIST: /*阿修羅覇鳳拳*/
  2855. case SA_MAGICROD:
  2856. case SA_SPELLBREAKER:
  2857. forcecast=1;
  2858. break;
  2859. case NPC_SUMMONSLAVE:
  2860. case NPC_SUMMONMONSTER:
  2861. if(md->master_id!=0)
  2862. return 0;
  2863. break;
  2864. }
  2865. if(battle_config.mob_skill_log)
  2866. printf("MOB skill use target_id=%d skill=%d lv=%d cast=%d, class = %d\n",target->id,skill_id,skill_lv,casttime,md->class);
  2867. if(casttime>0 || forcecast){ // 詠唱が必要
  2868. // struct mob_data *md2;
  2869. mob_stop_walking(md,0); // 歩行停止
  2870. clif_skillcasting( &md->bl,
  2871. md->bl.id, target->id, 0,0, skill_id,casttime);
  2872. // 詠唱反応モンスター
  2873. /* if( target->type==BL_MOB && mob_db[(md2=(struct mob_data *)target)->class].mode&0x10 &&
  2874. md2->state.state!=MS_ATTACK){
  2875. md2->target_id=md->bl.id;
  2876. md->state.targettype = ATTACKABLE;
  2877. md2->min_chase=13;
  2878. }*/
  2879. }
  2880. if( casttime<=0 ) // 詠唱の無いものはキャンセルされない
  2881. md->state.skillcastcancel=0;
  2882. md->skilltarget = target->id;
  2883. md->skillx = 0;
  2884. md->skilly = 0;
  2885. md->skillid = skill_id;
  2886. md->skilllv = skill_lv;
  2887. md->skillidx = skill_idx;
  2888. if(!(battle_config.monster_cloak_check_type&2) && md->sc_data[SC_CLOAKING].timer != -1 && md->skillid != AS_CLOAKING)
  2889. skill_status_change_end(&md->bl,SC_CLOAKING,-1);
  2890. if( casttime>0 ){
  2891. md->skilltimer =
  2892. add_timer( gettick()+casttime, mobskill_castend_id, md->bl.id, 0 );
  2893. }else{
  2894. md->skilltimer = -1;
  2895. mobskill_castend_id(md->skilltimer,gettick(),md->bl.id, 0);
  2896. }
  2897. return 1;
  2898. }
  2899. /*==========================================
  2900. * スキル使用(場所指定)
  2901. *------------------------------------------
  2902. */
  2903. int mobskill_use_pos( struct mob_data *md,
  2904. int skill_x, int skill_y, int skill_idx)
  2905. {
  2906. int casttime=0,range;
  2907. struct mob_skill *ms;
  2908. struct block_list bl;
  2909. int skill_id, skill_lv;
  2910. nullpo_retr(0, md);
  2911. nullpo_retr(0, ms=&mob_db[md->class].skill[skill_idx]);
  2912. if( md->bl.prev==NULL )
  2913. return 0;
  2914. skill_id=ms->skill_id;
  2915. skill_lv=ms->skill_lv;
  2916. //沈黙や状態異常など
  2917. if(md->sc_data){
  2918. if(md->opt1>0 || md->sc_data[SC_DIVINA].timer != -1 || md->sc_data[SC_ROKISWEIL].timer != -1 || md->sc_data[SC_STEELBODY].timer != -1)
  2919. return 0;
  2920. if(md->sc_data[SC_AUTOCOUNTER].timer != -1 && md->skillid != KN_AUTOCOUNTER) //オートカウンター
  2921. return 0;
  2922. if(md->sc_data[SC_BLADESTOP].timer != -1) //白刃取り
  2923. return 0;
  2924. if(md->sc_data[SC_BERSERK].timer != -1) //バーサーク
  2925. return 0;
  2926. }
  2927. if(md->option&2)
  2928. return 0;
  2929. if(map[md->bl.m].flag.gvg && (skill_id == SM_ENDURE || skill_id == AL_TELEPORT || skill_id == AL_WARP ||
  2930. skill_id == WZ_ICEWALL || skill_id == TF_BACKSLIDING))
  2931. return 0;
  2932. // 射程と障害物チェック
  2933. bl.type = BL_NUL;
  2934. bl.m = md->bl.m;
  2935. bl.x = skill_x;
  2936. bl.y = skill_y;
  2937. range = skill_get_range(skill_id,skill_lv);
  2938. if(range < 0)
  2939. range = battle_get_range(&md->bl) - (range + 1);
  2940. if(!battle_check_range(&md->bl,&bl,range))
  2941. return 0;
  2942. // delay=skill_delayfix(&sd->bl, skill_get_delay( skill_id,skill_lv) );
  2943. casttime=skill_castfix(&md->bl,ms->casttime);
  2944. md->skilldelay[skill_idx]=gettick();
  2945. md->state.skillcastcancel=ms->cancel;
  2946. if(battle_config.mob_skill_log)
  2947. printf("MOB skill use target_pos=(%d,%d) skill=%d lv=%d cast=%d, class = %d\n",
  2948. skill_x,skill_y,skill_id,skill_lv,casttime,md->class);
  2949. if( casttime>0 ) { // A cast time is required.
  2950. mob_stop_walking(md,0); // 歩行停止
  2951. clif_skillcasting( &md->bl,
  2952. md->bl.id, 0, skill_x,skill_y, skill_id,casttime);
  2953. }
  2954. if( casttime<=0 ) // A skill without a cast time wont be cancelled.
  2955. md->state.skillcastcancel=0;
  2956. md->skillx = skill_x;
  2957. md->skilly = skill_y;
  2958. md->skilltarget = 0;
  2959. md->skillid = skill_id;
  2960. md->skilllv = skill_lv;
  2961. md->skillidx = skill_idx;
  2962. if(!(battle_config.monster_cloak_check_type&2) && md->sc_data[SC_CLOAKING].timer != -1)
  2963. skill_status_change_end(&md->bl,SC_CLOAKING,-1);
  2964. if( casttime>0 ){
  2965. md->skilltimer =
  2966. add_timer( gettick()+casttime, mobskill_castend_pos, md->bl.id, 0 );
  2967. }else{
  2968. md->skilltimer = -1;
  2969. mobskill_castend_pos(md->skilltimer,gettick(),md->bl.id, 0);
  2970. }
  2971. return 1;
  2972. }
  2973. /*==========================================
  2974. * Friendly Mob whose HP is decreasing by a nearby MOB is looked for.
  2975. *------------------------------------------
  2976. */
  2977. int mob_getfriendhpltmaxrate_sub(struct block_list *bl,va_list ap)
  2978. {
  2979. int rate;
  2980. struct mob_data **fr, *md, *mmd;
  2981. nullpo_retr(0, bl);
  2982. nullpo_retr(0, ap);
  2983. nullpo_retr(0, mmd=va_arg(ap,struct mob_data *));
  2984. md=(struct mob_data *)bl;
  2985. if( mmd->bl.id == bl->id )
  2986. return 0;
  2987. rate=va_arg(ap,int);
  2988. fr=va_arg(ap,struct mob_data **);
  2989. if( md->hp < mob_db[md->class].max_hp*rate/100 )
  2990. (*fr)=md;
  2991. return 0;
  2992. }
  2993. struct mob_data *mob_getfriendhpltmaxrate(struct mob_data *md,int rate)
  2994. {
  2995. struct mob_data *fr=NULL;
  2996. const int r=8;
  2997. nullpo_retr(NULL, md);
  2998. map_foreachinarea(mob_getfriendhpltmaxrate_sub, md->bl.m,
  2999. md->bl.x-r ,md->bl.y-r, md->bl.x+r, md->bl.y+r,
  3000. BL_MOB,md,rate,&fr);
  3001. return fr;
  3002. }
  3003. /*==========================================
  3004. * What a status state suits by nearby MOB is looked for.
  3005. *------------------------------------------
  3006. */
  3007. int mob_getfriendstatus_sub(struct block_list *bl,va_list ap)
  3008. {
  3009. int cond1,cond2;
  3010. struct mob_data **fr, *md, *mmd;
  3011. int flag=0;
  3012. nullpo_retr(0, bl);
  3013. nullpo_retr(0, ap);
  3014. nullpo_retr(0, md=(struct mob_data *)bl);
  3015. nullpo_retr(0, mmd=va_arg(ap,struct mob_data *));
  3016. if( mmd->bl.id == bl->id )
  3017. return 0;
  3018. cond1=va_arg(ap,int);
  3019. cond2=va_arg(ap,int);
  3020. fr=va_arg(ap,struct mob_data **);
  3021. if( cond2==-1 ){
  3022. int j;
  3023. for(j=SC_STONE;j<=SC_BLIND && !flag;j++){
  3024. flag=(md->sc_data[j].timer!=-1 );
  3025. }
  3026. }else
  3027. flag=( md->sc_data[cond2].timer!=-1 );
  3028. if( flag^( cond1==MSC_FRIENDSTATUSOFF ) )
  3029. (*fr)=md;
  3030. return 0;
  3031. }
  3032. struct mob_data *mob_getfriendstatus(struct mob_data *md,int cond1,int cond2)
  3033. {
  3034. struct mob_data *fr=NULL;
  3035. const int r=8;
  3036. nullpo_retr(0, md);
  3037. map_foreachinarea(mob_getfriendstatus_sub, md->bl.m,
  3038. md->bl.x-r ,md->bl.y-r, md->bl.x+r, md->bl.y+r,
  3039. BL_MOB,md,cond1,cond2,&fr);
  3040. return fr;
  3041. }
  3042. /*==========================================
  3043. * Skill use judging
  3044. *------------------------------------------
  3045. */
  3046. int mobskill_use(struct mob_data *md,unsigned int tick,int event)
  3047. {
  3048. struct mob_skill *ms;
  3049. // struct block_list *target=NULL;
  3050. int i,max_hp;
  3051. nullpo_retr(0, md);
  3052. nullpo_retr(0, ms = mob_db[md->class].skill);
  3053. max_hp = battle_get_max_hp(&md->bl);
  3054. if(battle_config.mob_skill_use == 0 || md->skilltimer != -1)
  3055. return 0;
  3056. if(md->state.special_mob_ai)
  3057. return 0;
  3058. if(md->sc_data[SC_SELFDESTRUCTION].timer!=-1) //自爆中はスキルを使わない
  3059. return 0;
  3060. for(i=0;i<mob_db[md->class].maxskill;i++){
  3061. int c2=ms[i].cond2,flag=0;
  3062. struct mob_data *fmd=NULL;
  3063. // ディレイ中
  3064. if( DIFF_TICK(tick,md->skilldelay[i])<ms[i].delay )
  3065. continue;
  3066. // 状態判定
  3067. if( ms[i].state>=0 && ms[i].state!=md->state.skillstate )
  3068. continue;
  3069. // 条件判定
  3070. flag=(event==ms[i].cond1);
  3071. if(!flag){
  3072. switch( ms[i].cond1 ){
  3073. case MSC_ALWAYS:
  3074. flag=1; break;
  3075. case MSC_MYHPLTMAXRATE: // HP< maxhp%
  3076. flag=( md->hp < max_hp*c2/100 ); break;
  3077. case MSC_MYSTATUSON: // status[num] on
  3078. case MSC_MYSTATUSOFF: // status[num] off
  3079. if( ms[i].cond2==-1 ){
  3080. int j;
  3081. for(j=SC_STONE;j<=SC_BLIND && !flag;j++){
  3082. flag=(md->sc_data[j].timer!=-1 );
  3083. }
  3084. }else
  3085. flag=( md->sc_data[ms[i].cond2].timer!=-1 );
  3086. flag^=( ms[i].cond1==MSC_MYSTATUSOFF ); break;
  3087. case MSC_FRIENDHPLTMAXRATE: // friend HP < maxhp%
  3088. flag=(( fmd=mob_getfriendhpltmaxrate(md,ms[i].cond2) )!=NULL ); break;
  3089. case MSC_FRIENDSTATUSON: // friend status[num] on
  3090. case MSC_FRIENDSTATUSOFF: // friend status[num] off
  3091. flag=(( fmd=mob_getfriendstatus(md,ms[i].cond1,ms[i].cond2) )!=NULL ); break;
  3092. case MSC_SLAVELT: // slave < num
  3093. flag=( mob_countslave(md) < c2 ); break;
  3094. case MSC_ATTACKPCGT: // attack pc > num
  3095. flag=( mob_counttargeted(md,NULL,0) > c2 ); break;
  3096. case MSC_SLAVELE: // slave <= num
  3097. flag=( mob_countslave(md) <= c2 ); break;
  3098. case MSC_ATTACKPCGE: // attack pc >= num
  3099. flag=( mob_counttargeted(md,NULL,0) >= c2 ); break;
  3100. case MSC_SKILLUSED: // specificated skill used
  3101. flag=( (event&0xffff)==MSC_SKILLUSED && ((event>>16)==c2 || c2==0)); break;
  3102. }
  3103. }
  3104. // 確率判定
  3105. if( flag && rand()%10000 < ms[i].permillage ){
  3106. if( skill_get_inf(ms[i].skill_id)&2 ){
  3107. // 場所指定
  3108. struct block_list *bl = NULL;
  3109. int x=0,y=0;
  3110. if( ms[i].target<=MST_AROUND ){
  3111. bl= ((ms[i].target==MST_TARGET || ms[i].target==MST_AROUND5)? map_id2bl(md->target_id):
  3112. (ms[i].target==MST_FRIEND)? &fmd->bl : &md->bl);
  3113. if(bl!=NULL){
  3114. x=bl->x; y=bl->y;
  3115. }
  3116. }
  3117. if( x<=0 || y<=0 )
  3118. continue;
  3119. // 自分の周囲
  3120. if( ms[i].target>=MST_AROUND1 ){
  3121. int bx=x, by=y, i=0, m=bl->m, r=ms[i].target-MST_AROUND1;
  3122. do{
  3123. bx=x + rand()%(r*2+3) - r;
  3124. by=y + rand()%(r*2+3) - r;
  3125. }while( ( bx<=0 || by<=0 || bx>=map[m].xs || by>=map[m].ys ||
  3126. map_getcell(m,bx,by,CELL_CHKNOPASS)) && (i++)<1000);
  3127. if(i<1000){
  3128. x=bx; y=by;
  3129. }
  3130. }
  3131. // 相手の周囲
  3132. if( ms[i].target>=MST_AROUND5 ){
  3133. int bx=x, by=y, i=0,m=bl->m, r=(ms[i].target-MST_AROUND5)+1;
  3134. do{
  3135. bx=x + rand()%(r*2+1) - r;
  3136. by=y + rand()%(r*2+1) - r;
  3137. }while( ( bx<=0 || by<=0 || bx>=map[m].xs || by>=map[m].ys ||
  3138. map_getcell(m,bx,by,CELL_CHKNOPASS)) && (i++)<1000);
  3139. if(i<1000){
  3140. x=bx; y=by;
  3141. }
  3142. }
  3143. if(!mobskill_use_pos(md,x,y,i))
  3144. return 0;
  3145. }else{
  3146. // ID指定
  3147. if( ms[i].target<=MST_FRIEND ){
  3148. struct block_list *bl = NULL;
  3149. bl= ((ms[i].target==MST_TARGET)? map_id2bl(md->target_id):
  3150. (ms[i].target==MST_FRIEND)? &fmd->bl : &md->bl);
  3151. if(bl && !mobskill_use_id(md,bl,i))
  3152. return 0;
  3153. }
  3154. }
  3155. if(ms[i].emotion >= 0)
  3156. clif_emotion(&md->bl,ms[i].emotion);
  3157. return 1;
  3158. }
  3159. }
  3160. return 0;
  3161. }
  3162. /*==========================================
  3163. * Skill use event processing
  3164. *------------------------------------------
  3165. */
  3166. int mobskill_event(struct mob_data *md,int flag)
  3167. {
  3168. nullpo_retr(0, md);
  3169. if(flag==-1 && mobskill_use(md,gettick(),MSC_CASTTARGETED))
  3170. return 1;
  3171. if( (flag&BF_SHORT) && mobskill_use(md,gettick(),MSC_CLOSEDATTACKED))
  3172. return 1;
  3173. if( (flag&BF_LONG) && mobskill_use(md,gettick(),MSC_LONGRANGEATTACKED))
  3174. return 1;
  3175. return 0;
  3176. }
  3177. /*==========================================
  3178. * Mobがエンペリウムなどの場合の判定
  3179. *------------------------------------------
  3180. */
  3181. int mob_gvmobcheck(struct map_session_data *sd, struct block_list *bl)
  3182. {
  3183. struct mob_data *md=NULL;
  3184. nullpo_retr(0,sd);
  3185. nullpo_retr(0,bl);
  3186. if(bl->type==BL_MOB && (md=(struct mob_data *)bl) &&
  3187. (md->class == 1288 || md->class == 1287 || md->class == 1286 || md->class == 1285))
  3188. {
  3189. struct guild_castle *gc=guild_mapname2gc(map[sd->bl.m].name);
  3190. struct guild *g=guild_search(sd->status.guild_id);
  3191. if(g == NULL && md->class == 1288)
  3192. return 0;//ギルド未加入ならダメージ無し
  3193. else if(gc != NULL && !map[sd->bl.m].flag.gvg)
  3194. return 0;//砦内でGvじゃないときはダメージなし
  3195. else if(g && gc != NULL && g->guild_id == gc->guild_id)
  3196. return 0;//自占領ギルドのエンペならダメージ無し
  3197. else if(g && guild_checkskill(g,GD_APPROVAL) <= 0 && md->class == 1288)
  3198. return 0;//正規ギルド承認がないとダメージ無し
  3199. }
  3200. return 1;
  3201. }
  3202. /*==========================================
  3203. * スキル用タイマー削除
  3204. *------------------------------------------
  3205. */
  3206. int mobskill_deltimer(struct mob_data *md )
  3207. {
  3208. nullpo_retr(0, md);
  3209. if( md->skilltimer!=-1 ){
  3210. if( skill_get_inf( md->skillid )&2 )
  3211. delete_timer( md->skilltimer, mobskill_castend_pos );
  3212. else
  3213. delete_timer( md->skilltimer, mobskill_castend_id );
  3214. md->skilltimer=-1;
  3215. }
  3216. return 0;
  3217. }
  3218. //
  3219. // 初期化
  3220. //
  3221. /*==========================================
  3222. * Since un-setting [ mob ] up was used, it is an initial provisional value setup.
  3223. *------------------------------------------
  3224. */
  3225. static int mob_makedummymobdb(int class)
  3226. {
  3227. int i;
  3228. sprintf(mob_db[class].name,"mob%d",class);
  3229. sprintf(mob_db[class].jname,"mob%d",class);
  3230. mob_db[class].lv=1;
  3231. mob_db[class].max_hp=1000;
  3232. mob_db[class].max_sp=1;
  3233. mob_db[class].base_exp=2;
  3234. mob_db[class].job_exp=1;
  3235. mob_db[class].range=1;
  3236. mob_db[class].atk1=7;
  3237. mob_db[class].atk2=10;
  3238. mob_db[class].def=0;
  3239. mob_db[class].mdef=0;
  3240. mob_db[class].str=1;
  3241. mob_db[class].agi=1;
  3242. mob_db[class].vit=1;
  3243. mob_db[class].int_=1;
  3244. mob_db[class].dex=6;
  3245. mob_db[class].luk=2;
  3246. mob_db[class].range2=10;
  3247. mob_db[class].range3=10;
  3248. mob_db[class].size=0;
  3249. mob_db[class].race=0;
  3250. mob_db[class].element=0;
  3251. mob_db[class].mode=0;
  3252. mob_db[class].speed=300;
  3253. mob_db[class].adelay=1000;
  3254. mob_db[class].amotion=500;
  3255. mob_db[class].dmotion=500;
  3256. mob_db[class].dropitem[0].nameid=909; // Jellopy
  3257. mob_db[class].dropitem[0].p=1000;
  3258. for(i=1;i<8;i++){
  3259. mob_db[class].dropitem[i].nameid=0;
  3260. mob_db[class].dropitem[i].p=0;
  3261. }
  3262. // Item1,Item2
  3263. mob_db[class].mexp=0;
  3264. mob_db[class].mexpper=0;
  3265. for(i=0;i<3;i++){
  3266. mob_db[class].mvpitem[i].nameid=0;
  3267. mob_db[class].mvpitem[i].p=0;
  3268. }
  3269. for(i=0;i<MAX_RANDOMMONSTER;i++)
  3270. mob_db[class].summonper[i]=0;
  3271. return 0;
  3272. }
  3273. /*==========================================
  3274. * db/mob_db.txt reading
  3275. *------------------------------------------
  3276. */
  3277. static int mob_readdb(void)
  3278. {
  3279. FILE *fp;
  3280. char line[1024];
  3281. char *filename[]={ "db/mob_db.txt","db/mob_db2.txt" };
  3282. int i;
  3283. memset(mob_db,0,sizeof(mob_db));
  3284. for(i=0;i<2;i++){
  3285. fp=fopen(filename[i],"r");
  3286. if(fp==NULL){
  3287. if(i>0)
  3288. continue;
  3289. return -1;
  3290. }
  3291. while(fgets(line,1020,fp)){
  3292. int class,i;
  3293. char *str[55],*p,*np;
  3294. if(line[0] == '/' && line[1] == '/')
  3295. continue;
  3296. for(i=0,p=line;i<55;i++){
  3297. if((np=strchr(p,','))!=NULL){
  3298. str[i]=p;
  3299. *np=0;
  3300. p=np+1;
  3301. } else
  3302. str[i]=p;
  3303. }
  3304. class=atoi(str[0]);
  3305. if(class<=1000 || class>MAX_MOB_DB)
  3306. continue;
  3307. mob_db[class].view_class=class;
  3308. memcpy(mob_db[class].name,str[1],24);
  3309. memcpy(mob_db[class].jname,str[2],24);
  3310. mob_db[class].lv=atoi(str[3]);
  3311. mob_db[class].max_hp=atoi(str[4]);
  3312. mob_db[class].max_sp=atoi(str[5]);
  3313. mob_db[class].base_exp=atoi(str[6]);
  3314. if(mob_db[class].base_exp < 0)
  3315. mob_db[class].base_exp = 0;
  3316. else if(mob_db[class].base_exp > 0 && (mob_db[class].base_exp*battle_config.base_exp_rate/100 > 1000000000 ||
  3317. mob_db[class].base_exp*battle_config.base_exp_rate/100 < 0))
  3318. mob_db[class].base_exp=1000000000;
  3319. else
  3320. mob_db[class].base_exp*= battle_config.base_exp_rate/100;
  3321. mob_db[class].job_exp=atoi(str[7]);
  3322. if(mob_db[class].job_exp < 0)
  3323. mob_db[class].job_exp = 0;
  3324. else if(mob_db[class].job_exp > 0 && (mob_db[class].job_exp*battle_config.job_exp_rate/100 > 1000000000 ||
  3325. mob_db[class].job_exp*battle_config.job_exp_rate/100 < 0))
  3326. mob_db[class].job_exp=1000000000;
  3327. else
  3328. mob_db[class].job_exp*=battle_config.job_exp_rate/100;
  3329. mob_db[class].range=atoi(str[8]);
  3330. mob_db[class].atk1=atoi(str[9]);
  3331. mob_db[class].atk2=atoi(str[10]);
  3332. mob_db[class].def=atoi(str[11]);
  3333. mob_db[class].mdef=atoi(str[12]);
  3334. mob_db[class].str=atoi(str[13]);
  3335. mob_db[class].agi=atoi(str[14]);
  3336. mob_db[class].vit=atoi(str[15]);
  3337. mob_db[class].int_=atoi(str[16]);
  3338. mob_db[class].dex=atoi(str[17]);
  3339. mob_db[class].luk=atoi(str[18]);
  3340. mob_db[class].range2=atoi(str[19]);
  3341. mob_db[class].range3=atoi(str[20]);
  3342. mob_db[class].size=atoi(str[21]);
  3343. mob_db[class].race=atoi(str[22]);
  3344. mob_db[class].element=atoi(str[23]);
  3345. mob_db[class].mode=atoi(str[24]);
  3346. mob_db[class].speed=atoi(str[25]);
  3347. mob_db[class].adelay=atoi(str[26]);
  3348. mob_db[class].amotion=atoi(str[27]);
  3349. mob_db[class].dmotion=atoi(str[28]);
  3350. for(i=0;i<8;i++){
  3351. int rate = 0,type,ratemin,ratemax;
  3352. mob_db[class].dropitem[i].nameid=atoi(str[29+i*2]);
  3353. type = itemdb_type(mob_db[class].dropitem[i].nameid);
  3354. if (type == 0) { // Added [Valaris]
  3355. rate = battle_config.item_rate_heal;
  3356. ratemin = battle_config.item_drop_heal_min;
  3357. ratemax = battle_config.item_drop_heal_max;
  3358. }
  3359. else if (type == 2) {
  3360. rate = battle_config.item_rate_use;
  3361. ratemin = battle_config.item_drop_use_min;
  3362. ratemax = battle_config.item_drop_use_max; // End
  3363. }
  3364. else if (type == 4 || type == 5 || type == 8) { // Changed to include Pet Equip
  3365. rate = battle_config.item_rate_equip;
  3366. ratemin = battle_config.item_drop_equip_min;
  3367. ratemax = battle_config.item_drop_equip_max;
  3368. }
  3369. else if (type == 6) {
  3370. rate = battle_config.item_rate_card;
  3371. ratemin = battle_config.item_drop_card_min;
  3372. ratemax = battle_config.item_drop_card_max;
  3373. }
  3374. else {
  3375. rate = battle_config.item_rate_common;
  3376. ratemin = battle_config.item_drop_common_min;
  3377. ratemax = battle_config.item_drop_common_max;
  3378. }
  3379. if (battle_config.item_rate_details == 1) { //ドロップレート詳細項目が1の時 レート=x/100倍
  3380. if (rate < 10)
  3381. rate = rate * battle_config.item_rate_1/100;
  3382. else if (rate >= 10 && rate < 100)
  3383. rate = rate * battle_config.item_rate_10/100;
  3384. else if (rate >= 100 && rate < 1000)
  3385. rate = rate * battle_config.item_rate_100/100;
  3386. else rate = rate * battle_config.item_rate_1000/100;
  3387. }
  3388. else if (battle_config.item_rate_details == 2) { //ドロップレート詳細項目が2の時 レート=x/100倍 min max 指定
  3389. if (rate >= 1 && rate < 10) {
  3390. if (rate * battle_config.item_rate_1/100 < battle_config.item_rate_1_min)
  3391. rate = battle_config.item_rate_1_min;
  3392. else if (rate * battle_config.item_rate_1/100 > battle_config.item_rate_1_max)
  3393. rate = battle_config.item_rate_1_max;
  3394. else rate = rate * battle_config.item_rate_1/100;
  3395. }
  3396. else if (rate >= 10 && rate < 100) {
  3397. if (rate * battle_config.item_rate_10/100 < battle_config.item_rate_10_min)
  3398. rate = battle_config.item_rate_10_min;
  3399. else if (rate * battle_config.item_rate_10/100 > battle_config.item_rate_10_max)
  3400. rate = battle_config.item_rate_10_max;
  3401. else rate = rate * battle_config.item_rate_10/100;
  3402. }
  3403. else if (rate >= 100 && rate < 1000) {
  3404. if (rate * battle_config.item_rate_100/100 < battle_config.item_rate_100_min)
  3405. rate = battle_config.item_rate_100_min;
  3406. else if (rate * battle_config.item_rate_100/100 > battle_config.item_rate_100_max)
  3407. rate = battle_config.item_rate_100_max;
  3408. else rate = rate * battle_config.item_rate_100/100;
  3409. }
  3410. else if (rate >= 1000) {
  3411. if (rate * battle_config.item_rate_1000/100 < battle_config.item_rate_1000_min)
  3412. rate = battle_config.item_rate_1000_min;
  3413. else if (rate * battle_config.item_rate_1000/100 > battle_config.item_rate_1000_max)
  3414. rate = battle_config.item_rate_1000_max;
  3415. else rate = rate * battle_config.item_rate_1000/100;
  3416. }
  3417. }
  3418. rate = rate * atoi(str[30+i*2])/100;
  3419. rate = (rate < ratemin)? ratemin: (rate > ratemax)? ratemax: rate;
  3420. mob_db[class].dropitem[i].p = rate;
  3421. }
  3422. // Item1,Item2
  3423. mob_db[class].mexp=atoi(str[45])*battle_config.mvp_exp_rate/100;
  3424. mob_db[class].mexpper=atoi(str[46]);
  3425. for(i=0;i<3;i++){
  3426. mob_db[class].mvpitem[i].nameid=atoi(str[47+i*2]);
  3427. mob_db[class].mvpitem[i].p=atoi(str[48+i*2])*battle_config.mvp_item_rate/100;
  3428. }
  3429. for(i=0;i<MAX_RANDOMMONSTER;i++)
  3430. mob_db[class].summonper[i]=0;
  3431. mob_db[class].maxskill=0;
  3432. mob_db[class].sex=0;
  3433. mob_db[class].hair=0;
  3434. mob_db[class].hair_color=0;
  3435. mob_db[class].weapon=0;
  3436. mob_db[class].shield=0;
  3437. mob_db[class].head_top=0;
  3438. mob_db[class].head_mid=0;
  3439. mob_db[class].head_buttom=0;
  3440. mob_db[class].clothes_color=0; //Add for player monster dye - Valaris
  3441. }
  3442. fclose(fp);
  3443. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n",filename[i]);
  3444. ShowStatus(tmp_output);
  3445. }
  3446. return 0;
  3447. }
  3448. /*==========================================
  3449. * MOB display graphic change data reading
  3450. *------------------------------------------
  3451. */
  3452. static int mob_readdb_mobavail(void)
  3453. {
  3454. FILE *fp;
  3455. char line[1024];
  3456. int ln=0;
  3457. int class,j,k;
  3458. char *str[20],*p,*np;
  3459. if( (fp=fopen("db/mob_avail.txt","r"))==NULL ){
  3460. printf("can't read db/mob_avail.txt\n");
  3461. return -1;
  3462. }
  3463. while(fgets(line,1020,fp)){
  3464. if(line[0]=='/' && line[1]=='/')
  3465. continue;
  3466. memset(str,0,sizeof(str));
  3467. for(j=0,p=line;j<12;j++){
  3468. if((np=strchr(p,','))!=NULL){
  3469. str[j]=p;
  3470. *np=0;
  3471. p=np+1;
  3472. } else
  3473. str[j]=p;
  3474. }
  3475. if(str[0]==NULL)
  3476. continue;
  3477. class=atoi(str[0]);
  3478. if(class<=1000 || class>MAX_MOB_DB) // 値が異常なら処理しない。
  3479. continue;
  3480. k=atoi(str[1]);
  3481. if(k >= 0)
  3482. mob_db[class].view_class=k;
  3483. if((mob_db[class].view_class < 24) || (mob_db[class].view_class > 4000)) {
  3484. mob_db[class].sex=atoi(str[2]);
  3485. mob_db[class].hair=atoi(str[3]);
  3486. mob_db[class].hair_color=atoi(str[4]);
  3487. mob_db[class].weapon=atoi(str[5]);
  3488. mob_db[class].shield=atoi(str[6]);
  3489. mob_db[class].head_top=atoi(str[7]);
  3490. mob_db[class].head_mid=atoi(str[8]);
  3491. mob_db[class].head_buttom=atoi(str[9]);
  3492. mob_db[class].option=atoi(str[10])&~0x46;
  3493. mob_db[class].clothes_color=atoi(str[11]); // Monster player dye option - Valaris
  3494. }
  3495. else if(atoi(str[2]) > 0) mob_db[class].equip=atoi(str[2]); // mob equipment [Valaris]
  3496. ln++;
  3497. }
  3498. fclose(fp);
  3499. sprintf(tmp_output,"Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"db/mob_avail.txt");
  3500. ShowStatus(tmp_output);
  3501. return 0;
  3502. }
  3503. /*==========================================
  3504. * Reading of random monster data
  3505. *------------------------------------------
  3506. */
  3507. static int mob_read_randommonster(void)
  3508. {
  3509. FILE *fp;
  3510. char line[1024];
  3511. char *str[10],*p;
  3512. int i,j;
  3513. const char* mobfile[] = {
  3514. "db/mob_branch.txt",
  3515. "db/mob_poring.txt",
  3516. "db/mob_boss.txt" };
  3517. for(i=0;i<MAX_RANDOMMONSTER;i++){
  3518. mob_db[0].summonper[i] = 1002; // 設定し忘れた場合はポリンが出るようにしておく
  3519. fp=fopen(mobfile[i],"r");
  3520. if(fp==NULL){
  3521. printf("can't read %s\n",mobfile[i]);
  3522. return -1;
  3523. }
  3524. while(fgets(line,1020,fp)){
  3525. int class,per;
  3526. if(line[0] == '/' && line[1] == '/')
  3527. continue;
  3528. memset(str,0,sizeof(str));
  3529. for(j=0,p=line;j<3 && p;j++){
  3530. str[j]=p;
  3531. p=strchr(p,',');
  3532. if(p) *p++=0;
  3533. }
  3534. if(str[0]==NULL || str[2]==NULL)
  3535. continue;
  3536. class = atoi(str[0]);
  3537. per=atoi(str[2]);
  3538. if((class>1000 && class<=MAX_MOB_DB) || class==0)
  3539. mob_db[class].summonper[i]=per;
  3540. }
  3541. fclose(fp);
  3542. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n",mobfile[i]);
  3543. ShowStatus(tmp_output);
  3544. }
  3545. return 0;
  3546. }
  3547. /*==========================================
  3548. * db/mob_skill_db.txt reading
  3549. *------------------------------------------
  3550. */
  3551. static int mob_readskilldb(void)
  3552. {
  3553. FILE *fp;
  3554. char line[1024];
  3555. int i;
  3556. const struct {
  3557. char str[32];
  3558. int id;
  3559. } cond1[] = {
  3560. { "always", MSC_ALWAYS },
  3561. { "myhpltmaxrate", MSC_MYHPLTMAXRATE },
  3562. { "friendhpltmaxrate",MSC_FRIENDHPLTMAXRATE },
  3563. { "mystatuson", MSC_MYSTATUSON },
  3564. { "mystatusoff", MSC_MYSTATUSOFF },
  3565. { "friendstatuson", MSC_FRIENDSTATUSON },
  3566. { "friendstatusoff", MSC_FRIENDSTATUSOFF },
  3567. { "attackpcgt", MSC_ATTACKPCGT },
  3568. { "attackpcge", MSC_ATTACKPCGE },
  3569. { "slavelt", MSC_SLAVELT },
  3570. { "slavele", MSC_SLAVELE },
  3571. { "closedattacked", MSC_CLOSEDATTACKED },
  3572. { "longrangeattacked",MSC_LONGRANGEATTACKED },
  3573. { "skillused", MSC_SKILLUSED },
  3574. { "casttargeted", MSC_CASTTARGETED },
  3575. }, cond2[] ={
  3576. { "anybad", -1 },
  3577. { "stone", SC_STONE },
  3578. { "freeze", SC_FREEZE },
  3579. { "stan", SC_STAN },
  3580. { "sleep", SC_SLEEP },
  3581. { "poison", SC_POISON },
  3582. { "curse", SC_CURSE },
  3583. { "silence", SC_SILENCE },
  3584. { "confusion", SC_CONFUSION },
  3585. { "blind", SC_BLIND },
  3586. { "hiding", SC_HIDING },
  3587. { "sight", SC_SIGHT },
  3588. }, state[] = {
  3589. { "any", -1 },
  3590. { "idle", MSS_IDLE },
  3591. { "walk", MSS_WALK },
  3592. { "attack", MSS_ATTACK },
  3593. { "dead", MSS_DEAD },
  3594. { "loot", MSS_LOOT },
  3595. { "chase", MSS_CHASE },
  3596. }, target[] = {
  3597. { "target", MST_TARGET },
  3598. { "self", MST_SELF },
  3599. { "friend", MST_FRIEND },
  3600. { "around5", MST_AROUND5 },
  3601. { "around6", MST_AROUND6 },
  3602. { "around7", MST_AROUND7 },
  3603. { "around8", MST_AROUND8 },
  3604. { "around1", MST_AROUND1 },
  3605. { "around2", MST_AROUND2 },
  3606. { "around3", MST_AROUND3 },
  3607. { "around4", MST_AROUND4 },
  3608. { "around", MST_AROUND },
  3609. };
  3610. int x;
  3611. char *filename[]={ "db/mob_skill_db.txt","db/mob_skill_db2.txt" };
  3612. for(x=0;x<2;x++){
  3613. fp=fopen(filename[x],"r");
  3614. if(fp==NULL){
  3615. if(x==0)
  3616. printf("can't read %s\n",filename[x]);
  3617. continue;
  3618. }
  3619. while(fgets(line,1020,fp)){
  3620. char *sp[20],*p;
  3621. int mob_id;
  3622. struct mob_skill *ms;
  3623. int j=0;
  3624. if(line[0] == '/' && line[1] == '/')
  3625. continue;
  3626. memset(sp,0,sizeof(sp));
  3627. for(i=0,p=line;i<18 && p;i++){
  3628. sp[i]=p;
  3629. if((p=strchr(p,','))!=NULL)
  3630. *p++=0;
  3631. }
  3632. if( (mob_id=atoi(sp[0]))<=0 )
  3633. continue;
  3634. if( strcmp(sp[1],"clear")==0 ){
  3635. memset(mob_db[mob_id].skill,0,sizeof(mob_db[mob_id].skill));
  3636. mob_db[mob_id].maxskill=0;
  3637. continue;
  3638. }
  3639. for(i=0;i<MAX_MOBSKILL;i++)
  3640. if( (ms=&mob_db[mob_id].skill[i])->skill_id == 0)
  3641. break;
  3642. if(i==MAX_MOBSKILL){
  3643. printf("mob_skill: readdb: too many skill ! [%s] in %d[%s]\n",
  3644. sp[1],mob_id,mob_db[mob_id].jname);
  3645. continue;
  3646. }
  3647. ms->state=atoi(sp[2]);
  3648. for(j=0;j<sizeof(state)/sizeof(state[0]);j++){
  3649. if( strcmp(sp[2],state[j].str)==0)
  3650. ms->state=state[j].id;
  3651. }
  3652. ms->skill_id=atoi(sp[3]);
  3653. ms->skill_lv=atoi(sp[4]);
  3654. ms->permillage=atoi(sp[5]);
  3655. ms->casttime=atoi(sp[6]);
  3656. ms->delay=atoi(sp[7]);
  3657. ms->cancel=atoi(sp[8]);
  3658. if( strcmp(sp[8],"yes")==0 ) ms->cancel=1;
  3659. ms->target=atoi(sp[9]);
  3660. for(j=0;j<sizeof(target)/sizeof(target[0]);j++){
  3661. if( strcmp(sp[9],target[j].str)==0)
  3662. ms->target=target[j].id;
  3663. }
  3664. ms->cond1=-1;
  3665. for(j=0;j<sizeof(cond1)/sizeof(cond1[0]);j++){
  3666. if( strcmp(sp[10],cond1[j].str)==0)
  3667. ms->cond1=cond1[j].id;
  3668. }
  3669. ms->cond2=atoi(sp[11]);
  3670. for(j=0;j<sizeof(cond2)/sizeof(cond2[0]);j++){
  3671. if( strcmp(sp[11],cond2[j].str)==0)
  3672. ms->cond2=cond2[j].id;
  3673. }
  3674. ms->val[0]=atoi(sp[12]);
  3675. ms->val[1]=atoi(sp[13]);
  3676. ms->val[2]=atoi(sp[14]);
  3677. ms->val[3]=atoi(sp[15]);
  3678. ms->val[4]=atoi(sp[16]);
  3679. if(sp[17] != NULL && strlen(sp[17])>2)
  3680. ms->emotion=atoi(sp[17]);
  3681. else
  3682. ms->emotion=-1;
  3683. mob_db[mob_id].maxskill=i+1;
  3684. }
  3685. fclose(fp);
  3686. sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n",filename[x]);
  3687. ShowStatus(tmp_output);
  3688. }
  3689. return 0;
  3690. }
  3691. void mob_reload(void)
  3692. {
  3693. /*
  3694. <empty monster database>
  3695. mob_read();
  3696. */
  3697. do_init_mob();
  3698. }
  3699. #ifndef TXT_ONLY
  3700. /*==========================================
  3701. * SQL reading
  3702. *------------------------------------------
  3703. */
  3704. static int mob_read_sqldb(void)
  3705. {
  3706. char line[1024];
  3707. int i,class;
  3708. long unsigned int ln=0;
  3709. char *str[55],*p,*np;
  3710. memset(mob_db,0,sizeof(mob_db));
  3711. sprintf (tmp_sql, "SELECT * FROM `%s`",mob_db_db);
  3712. if(mysql_query(&mmysql_handle, tmp_sql) ) {
  3713. printf("DB server Error (select %s to Memory)- %s\n",mob_db_db,mysql_error(&mmysql_handle) );
  3714. }
  3715. sql_res = mysql_store_result(&mmysql_handle);
  3716. if (sql_res) {
  3717. while((sql_row = mysql_fetch_row(sql_res))){
  3718. sprintf(line,"%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
  3719. sql_row[0],sql_row[1],sql_row[2],sql_row[3],sql_row[4],
  3720. sql_row[5],sql_row[6],sql_row[7],sql_row[8],sql_row[9],
  3721. sql_row[10],sql_row[11],sql_row[12],sql_row[13],sql_row[14],
  3722. sql_row[15],sql_row[16],sql_row[17],sql_row[18],sql_row[19],
  3723. sql_row[20],sql_row[21],sql_row[22],sql_row[23],sql_row[24],
  3724. sql_row[25],sql_row[26],sql_row[27],sql_row[28],sql_row[29],
  3725. sql_row[30],sql_row[31],sql_row[32],sql_row[33],sql_row[34],
  3726. sql_row[35],sql_row[36],sql_row[37],sql_row[38],sql_row[39],
  3727. sql_row[40],sql_row[41],sql_row[42],sql_row[43],sql_row[44],
  3728. sql_row[45],sql_row[46],sql_row[47],sql_row[48],sql_row[49],
  3729. sql_row[50],sql_row[51],sql_row[52]);
  3730. for(i=0,p=line;i<55;i++){
  3731. if((np=strchr(p,','))!=NULL){
  3732. str[i]=p;
  3733. *np=0;
  3734. p=np+1;
  3735. } else
  3736. str[i]=p;
  3737. }
  3738. class=atoi(str[0]);
  3739. if(class<=1000 || class>MAX_MOB_DB)
  3740. continue;
  3741. ln++;
  3742. mob_db[class].view_class=class;
  3743. memcpy(mob_db[class].name,str[1],24);
  3744. memcpy(mob_db[class].jname,str[2],24);
  3745. mob_db[class].lv=atoi(str[3]);
  3746. mob_db[class].max_hp=atoi(str[4]);
  3747. mob_db[class].max_sp=atoi(str[5]);
  3748. mob_db[class].base_exp=atoi(str[6])*
  3749. battle_config.base_exp_rate/100;
  3750. if(mob_db[class].base_exp <= 0)
  3751. mob_db[class].base_exp = 1;
  3752. mob_db[class].job_exp=atoi(str[7])*
  3753. battle_config.job_exp_rate/100;
  3754. if(mob_db[class].job_exp <= 0)
  3755. mob_db[class].job_exp = 1;
  3756. mob_db[class].range=atoi(str[8]);
  3757. mob_db[class].atk1=atoi(str[9]);
  3758. mob_db[class].atk2=atoi(str[10]);
  3759. mob_db[class].def=atoi(str[11]);
  3760. mob_db[class].mdef=atoi(str[12]);
  3761. mob_db[class].str=atoi(str[13]);
  3762. mob_db[class].agi=atoi(str[14]);
  3763. mob_db[class].vit=atoi(str[15]);
  3764. mob_db[class].int_=atoi(str[16]);
  3765. mob_db[class].dex=atoi(str[17]);
  3766. mob_db[class].luk=atoi(str[18]);
  3767. mob_db[class].range2=atoi(str[19]);
  3768. mob_db[class].range3=atoi(str[20]);
  3769. mob_db[class].size=atoi(str[21]);
  3770. mob_db[class].race=atoi(str[22]);
  3771. mob_db[class].element=atoi(str[23]);
  3772. mob_db[class].mode=atoi(str[24]);
  3773. mob_db[class].speed=atoi(str[25]);
  3774. mob_db[class].adelay=atoi(str[26]);
  3775. mob_db[class].amotion=atoi(str[27]);
  3776. mob_db[class].dmotion=atoi(str[28]);
  3777. for(i=0;i<8;i++){
  3778. int rate = 0,type,ratemin,ratemax;
  3779. mob_db[class].dropitem[i].nameid=atoi(str[29+i*2]);
  3780. type = itemdb_type(mob_db[class].dropitem[i].nameid);
  3781. if (type == 0) { // Added by Valaris
  3782. rate = battle_config.item_rate_heal;
  3783. ratemin = battle_config.item_drop_heal_min;
  3784. ratemax = battle_config.item_drop_heal_max;
  3785. }
  3786. else if (type == 2) {
  3787. rate = battle_config.item_rate_use;
  3788. ratemin = battle_config.item_drop_use_min;
  3789. ratemax = battle_config.item_drop_use_max; // End
  3790. }
  3791. else if (type == 4 || type == 5 || type == 8) { // Changed to include Pet Equip
  3792. rate = battle_config.item_rate_equip;
  3793. ratemin = battle_config.item_drop_equip_min;
  3794. ratemax = battle_config.item_drop_equip_max;
  3795. }
  3796. else if (type == 6) {
  3797. rate = battle_config.item_rate_card;
  3798. ratemin = battle_config.item_drop_card_min;
  3799. ratemax = battle_config.item_drop_card_max;
  3800. }
  3801. else {
  3802. rate = battle_config.item_rate_common;
  3803. ratemin = battle_config.item_drop_common_min;
  3804. ratemax = battle_config.item_drop_common_max;
  3805. }
  3806. rate = (rate / 100) * atoi(str[30+i*2]);
  3807. rate = (rate < ratemin)? ratemin: (rate > ratemax)? ratemax: rate;
  3808. mob_db[class].dropitem[i].p = rate;
  3809. }
  3810. mob_db[class].mexp=atoi(str[45])*battle_config.mvp_exp_rate/100;
  3811. mob_db[class].mexpper=atoi(str[46]);
  3812. for(i=0;i<3;i++){
  3813. mob_db[class].mvpitem[i].nameid=atoi(str[47+i*2]);
  3814. mob_db[class].mvpitem[i].p=atoi(str[48+i*2])*battle_config.mvp_item_rate/100;
  3815. }
  3816. for(i=0;i<MAX_RANDOMMONSTER;i++)
  3817. mob_db[class].summonper[i]=0;
  3818. mob_db[class].maxskill=0;
  3819. mob_db[class].sex=0;
  3820. mob_db[class].hair=0;
  3821. mob_db[class].hair_color=0;
  3822. mob_db[class].weapon=0;
  3823. mob_db[class].shield=0;
  3824. mob_db[class].head_top=0;
  3825. mob_db[class].head_mid=0;
  3826. mob_db[class].head_buttom=0;
  3827. }
  3828. mysql_free_result(sql_res);
  3829. sprintf(tmp_output,"Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,mob_db_db);
  3830. ShowStatus(tmp_output);
  3831. }
  3832. return 0;
  3833. }
  3834. #endif /* not TXT_ONLY */
  3835. /*==========================================
  3836. * Circumference initialization of mob
  3837. *------------------------------------------
  3838. */
  3839. int do_init_mob(void)
  3840. {
  3841. #ifndef TXT_ONLY
  3842. if(db_use_sqldbs)
  3843. mob_read_sqldb();
  3844. else
  3845. #endif /* TXT_ONLY */
  3846. mob_readdb();
  3847. mob_readdb_mobavail();
  3848. mob_read_randommonster();
  3849. mob_readskilldb();
  3850. add_timer_func_list(mob_timer,"mob_timer");
  3851. add_timer_func_list(mob_delayspawn,"mob_delayspawn");
  3852. add_timer_func_list(mob_delay_item_drop,"mob_delay_item_drop");
  3853. add_timer_func_list(mob_delay_item_drop2,"mob_delay_item_drop2");
  3854. add_timer_func_list(mob_ai_hard,"mob_ai_hard");
  3855. add_timer_func_list(mob_ai_lazy,"mob_ai_lazy");
  3856. add_timer_func_list(mobskill_castend_id,"mobskill_castend_id");
  3857. add_timer_func_list(mobskill_castend_pos,"mobskill_castend_pos");
  3858. add_timer_func_list(mob_timer_delete,"mob_timer_delete");
  3859. add_timer_interval(gettick()+MIN_MOBTHINKTIME,mob_ai_hard,0,0,MIN_MOBTHINKTIME);
  3860. add_timer_interval(gettick()+MIN_MOBTHINKTIME*10,mob_ai_lazy,0,0,MIN_MOBTHINKTIME*10);
  3861. return 0;
  3862. }