mob.c 118 KB

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