pet.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "db.h"
  7. #include "timer.h"
  8. #include "socket.h"
  9. #include "nullpo.h"
  10. #include "malloc.h"
  11. #include "pc.h"
  12. #include "status.h"
  13. #include "map.h"
  14. #include "intif.h"
  15. #include "clif.h"
  16. #include "chrif.h"
  17. #include "pet.h"
  18. #include "itemdb.h"
  19. #include "battle.h"
  20. #include "mob.h"
  21. #include "npc.h"
  22. #include "script.h"
  23. #include "skill.h"
  24. #include "showmsg.h"
  25. #define MIN_PETTHINKTIME 100
  26. struct pet_db pet_db[MAX_PET_DB];
  27. static int dirx[8]={0,-1,-1,-1,0,1,1,1};
  28. static int diry[8]={1,1,0,-1,-1,-1,0,1};
  29. static int pet_performance_val(struct map_session_data *sd)
  30. {
  31. nullpo_retr(0, sd);
  32. Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
  33. if(sd->pet.intimate > 900)
  34. return (sd->petDB->s_perfor > 0)? 4:3;
  35. else if(sd->pet.intimate > 750)
  36. return 2;
  37. else
  38. return 1;
  39. }
  40. int pet_hungry_val(struct map_session_data *sd)
  41. {
  42. nullpo_retr(0, sd);
  43. Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
  44. if(sd->pet.hungry > 90)
  45. return 4;
  46. else if(sd->pet.hungry > 75)
  47. return 3;
  48. else if(sd->pet.hungry > 25)
  49. return 2;
  50. else if(sd->pet.hungry > 10)
  51. return 1;
  52. else
  53. return 0;
  54. }
  55. static int pet_calc_pos(struct pet_data *pd,int tx,int ty,int dir)
  56. {
  57. int x,y,dx,dy;
  58. int i,k;
  59. nullpo_retr(0, pd);
  60. pd->ud.to_x = tx;
  61. pd->ud.to_y = ty;
  62. if(dir < 0 || dir >= 8)
  63. return 1;
  64. dx = -dirx[dir]*2;
  65. dy = -diry[dir]*2;
  66. x = tx + dx;
  67. y = ty + dy;
  68. if(!unit_can_reach(&pd->bl,x,y)) {
  69. if(dx > 0) x--;
  70. else if(dx < 0) x++;
  71. if(dy > 0) y--;
  72. else if(dy < 0) y++;
  73. if(!unit_can_reach(&pd->bl,x,y)) {
  74. for(i=0;i<12;i++) {
  75. k = rand()%8;
  76. dx = -dirx[k]*2;
  77. dy = -diry[k]*2;
  78. x = tx + dx;
  79. y = ty + dy;
  80. if(unit_can_reach(&pd->bl,x,y))
  81. break;
  82. else {
  83. if(dx > 0) x--;
  84. else if(dx < 0) x++;
  85. if(dy > 0) y--;
  86. else if(dy < 0) y++;
  87. if(unit_can_reach(&pd->bl,x,y))
  88. break;
  89. }
  90. }
  91. if(i>=12) {
  92. x = tx;
  93. y = ty;
  94. if(!unit_can_reach(&pd->bl,x,y))
  95. return 1;
  96. }
  97. }
  98. }
  99. pd->ud.to_x = x;
  100. pd->ud.to_y = y;
  101. return 0;
  102. }
  103. int pet_unlocktarget(struct pet_data *pd)
  104. {
  105. nullpo_retr(0, pd);
  106. pd->target_id=0;
  107. pet_stop_attack(pd);
  108. return 0;
  109. }
  110. /*==========================================
  111. * Pet Attack Skill [Skotlex]
  112. *------------------------------------------
  113. */
  114. int pet_attackskill(struct pet_data *pd, int target_id)
  115. {
  116. struct block_list *bl;
  117. if (!battle_config.pet_status_support || !pd->a_skill ||
  118. (battle_config.pet_equip_required && !pd->equip))
  119. return 0;
  120. if (rand()%100 < (pd->a_skill->rate +pd->msd->pet.intimate*pd->a_skill->bonusrate/1000))
  121. { //Skotlex: Use pet's skill
  122. bl=map_id2bl(target_id);
  123. if(bl == NULL || pd->bl.m != bl->m || bl->prev == NULL || status_isdead(bl) ||
  124. !check_distance_bl(&pd->bl, bl, pd->db->range3))
  125. return 0;
  126. if (skill_get_inf(pd->a_skill->id) & INF_GROUND_SKILL)
  127. unit_skilluse_pos(&pd->bl, bl->x, bl->y, pd->a_skill->id, pd->a_skill->lv);
  128. else
  129. unit_skilluse_id(&pd->bl, bl->id, pd->a_skill->id, pd->a_skill->lv);
  130. return 1; //Skill invoked.
  131. }
  132. return 0;
  133. }
  134. int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type)
  135. {
  136. struct pet_data *pd;
  137. int rate;
  138. pd = sd->pd;
  139. Assert((pd->msd == 0) || (pd->msd->pd == pd));
  140. if(bl == NULL || bl->type != BL_MOB || bl->prev == NULL ||
  141. sd->pet.intimate < battle_config.pet_support_min_friendly ||
  142. sd->pet.hungry < 1 ||
  143. pd->class_ == status_get_class(bl))
  144. return 0;
  145. if(pd->bl.m != bl->m ||
  146. !check_distance_bl(&pd->bl, bl, pd->db->range2))
  147. return 0;
  148. if (!status_check_skilluse(&pd->bl, bl, 0, 0))
  149. return 0;
  150. if(!type) {
  151. rate = sd->petDB->attack_rate;
  152. rate = rate * pd->rate_fix/1000;
  153. if(sd->petDB->attack_rate > 0 && rate <= 0)
  154. rate = 1;
  155. } else {
  156. rate = sd->petDB->defence_attack_rate;
  157. rate = rate * pd->rate_fix/1000;
  158. if(sd->petDB->defence_attack_rate > 0 && rate <= 0)
  159. rate = 1;
  160. }
  161. if(rand()%10000 < rate)
  162. {
  163. if(pd->target_id == 0 || rand()%10000 < sd->petDB->change_target_rate)
  164. pd->target_id = bl->id;
  165. }
  166. return 0;
  167. }
  168. /*==========================================
  169. * Pet SC Check [Skotlex]
  170. *------------------------------------------
  171. */
  172. int pet_sc_check(struct map_session_data *sd, int type)
  173. {
  174. struct pet_data *pd;
  175. nullpo_retr(0, sd);
  176. pd = sd->pd;
  177. if (pd == NULL ||
  178. (battle_config.pet_equip_required && pd->equip == 0) ||
  179. pd->recovery == NULL ||
  180. pd->recovery->timer != -1 ||
  181. pd->recovery->type != type)
  182. return 1;
  183. pd->recovery->timer = add_timer(gettick()+pd->recovery->delay*1000,pet_recovery_timer,sd->bl.id,0);
  184. return 0;
  185. }
  186. static int pet_hungry(int tid,unsigned int tick,int id,int data)
  187. {
  188. struct map_session_data *sd;
  189. int interval,t;
  190. sd=map_id2sd(id);
  191. if(sd==NULL)
  192. return 1;
  193. Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
  194. if(sd->pet_hungry_timer != tid){
  195. if(battle_config.error_log)
  196. ShowError("pet_hungry_timer %d != %d\n",sd->pet_hungry_timer,tid);
  197. return 0;
  198. }
  199. sd->pet_hungry_timer = -1;
  200. if(!sd->status.pet_id || !sd->pd || !sd->petDB)
  201. return 1;
  202. if (sd->pet.intimate <= 0)
  203. return 1; //You lost the pet already, the rest is irrelevant.
  204. sd->pet.hungry--;
  205. t = sd->pet.intimate;
  206. if(sd->pet.hungry < 0) {
  207. pet_stop_attack(sd->pd);
  208. sd->pet.hungry = 0;
  209. sd->pet.intimate -= battle_config.pet_hungry_friendly_decrease;
  210. if(sd->pet.intimate <= 0) {
  211. sd->pet.intimate = 0;
  212. sd->pd->speed = sd->pd->db->speed;
  213. if(battle_config.pet_status_support && t > 0) {
  214. if(sd->bl.prev != NULL)
  215. status_calc_pc(sd,0);
  216. else
  217. status_calc_pc(sd,2);
  218. }
  219. }
  220. status_calc_pet(sd, 0);
  221. clif_send_petdata(sd,1,sd->pet.intimate);
  222. }
  223. clif_send_petdata(sd,2,sd->pet.hungry);
  224. if(battle_config.pet_hungry_delay_rate != 100)
  225. interval = (sd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100;
  226. else
  227. interval = sd->petDB->hungry_delay;
  228. if(interval <= 0)
  229. interval = 1;
  230. sd->pet_hungry_timer = add_timer(tick+interval,pet_hungry,sd->bl.id,0);
  231. return 0;
  232. }
  233. int search_petDB_index(int key,int type)
  234. {
  235. int i;
  236. for(i=0;i<MAX_PET_DB;i++) {
  237. if(pet_db[i].class_ <= 0)
  238. continue;
  239. switch(type) {
  240. case PET_CLASS:
  241. if(pet_db[i].class_ == key)
  242. return i;
  243. break;
  244. case PET_CATCH:
  245. if(pet_db[i].itemID == key)
  246. return i;
  247. break;
  248. case PET_EGG:
  249. if(pet_db[i].EggID == key)
  250. return i;
  251. break;
  252. case PET_EQUIP:
  253. if(pet_db[i].AcceID == key)
  254. return i;
  255. break;
  256. case PET_FOOD:
  257. if(pet_db[i].FoodID == key)
  258. return i;
  259. break;
  260. default:
  261. return -1;
  262. }
  263. }
  264. return -1;
  265. }
  266. int pet_hungry_timer_delete(struct map_session_data *sd)
  267. {
  268. nullpo_retr(0, sd);
  269. if(sd->pet_hungry_timer != -1) {
  270. delete_timer(sd->pet_hungry_timer,pet_hungry);
  271. sd->pet_hungry_timer = -1;
  272. }
  273. return 0;
  274. }
  275. struct delay_item_drop {
  276. int m,x,y;
  277. int nameid,amount;
  278. struct map_session_data *first_sd,*second_sd,*third_sd;
  279. };
  280. struct delay_item_drop2 {
  281. int m,x,y;
  282. struct item item_data;
  283. struct map_session_data *first_sd,*second_sd,*third_sd;
  284. };
  285. int pet_performance(struct map_session_data *sd)
  286. {
  287. struct pet_data *pd;
  288. nullpo_retr(0, sd);
  289. nullpo_retr(0, pd=sd->pd);
  290. Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
  291. pet_stop_walking(pd,2000<<8);
  292. clif_pet_performance(&pd->bl,rand()%pet_performance_val(sd) + 1);
  293. // ルートしたItemを落とさせる
  294. pet_lootitem_drop(pd,NULL);
  295. return 0;
  296. }
  297. int pet_return_egg(struct map_session_data *sd)
  298. {
  299. struct item tmp_item;
  300. int flag;
  301. nullpo_retr(0, sd);
  302. Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
  303. if(sd->status.pet_id && sd->pd) {
  304. // ルートしたItemを落とさせる
  305. pet_lootitem_drop(sd->pd,sd);
  306. if(sd->petDB == NULL)
  307. return 1;
  308. memset(&tmp_item,0,sizeof(tmp_item));
  309. tmp_item.nameid = sd->petDB->EggID;
  310. tmp_item.identify = 1;
  311. tmp_item.card[0] = (short)0xff00;
  312. tmp_item.card[1] = GetWord(sd->pet.pet_id,0);
  313. tmp_item.card[2] = GetWord(sd->pet.pet_id,1);
  314. tmp_item.card[3] = sd->pet.rename_flag;
  315. if((flag = pc_additem(sd,&tmp_item,1))) {
  316. clif_additem(sd,0,0,flag);
  317. map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
  318. }
  319. sd->pet.incuvate = 1;
  320. intif_save_petdata(sd->status.account_id,&sd->pet);
  321. unit_free(&sd->pd->bl);
  322. if(battle_config.pet_status_support && sd->pet.intimate > 0)
  323. status_calc_pc(sd,0);
  324. memset(&sd->pet, 0, sizeof(struct s_pet));
  325. sd->status.pet_id = 0;
  326. sd->petDB = NULL;
  327. }
  328. return 0;
  329. }
  330. int pet_data_init(struct map_session_data *sd)
  331. {
  332. struct pet_data *pd;
  333. int i=0,interval=0;
  334. nullpo_retr(1, sd);
  335. Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
  336. if(sd->status.account_id != sd->pet.account_id || sd->status.char_id != sd->pet.char_id) {
  337. sd->status.pet_id = 0;
  338. return 1;
  339. }
  340. if (sd->status.pet_id != sd->pet.pet_id) {
  341. if (sd->status.pet_id) {
  342. //Wrong pet?? Set incuvate to no and send it back for saving.
  343. sd->pet.incuvate = 1;
  344. intif_save_petdata(sd->status.account_id,&sd->pet);
  345. sd->status.pet_id = 0;
  346. return 1;
  347. }
  348. //The pet_id value was lost? odd... restore it.
  349. sd->status.pet_id = sd->pet.pet_id;
  350. }
  351. i = search_petDB_index(sd->pet.class_,PET_CLASS);
  352. if(i < 0) {
  353. sd->status.pet_id = 0;
  354. return 1;
  355. }
  356. sd->petDB = &pet_db[i];
  357. sd->pd = pd = (struct pet_data *)aCalloc(1,sizeof(struct pet_data));
  358. pd->bl.m = sd->bl.m;
  359. pd->bl.x = sd->bl.x;
  360. pd->bl.y = sd->bl.y;
  361. pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir);
  362. pd->bl.x = pd->ud.to_x;
  363. pd->bl.y = pd->ud.to_y;
  364. pd->bl.id = npc_get_new_npc_id();
  365. memcpy(pd->name, sd->pet.name, NAME_LENGTH-1);
  366. pd->class_ = sd->pet.class_;
  367. pd->db = mob_db(pd->class_);
  368. pd->equip = sd->pet.equip;
  369. pd->speed = sd->petDB->speed;
  370. pd->bl.subtype = MONS;
  371. pd->bl.type = BL_PET;
  372. pd->msd = sd;
  373. status_set_viewdata(&pd->bl,pd->class_);
  374. unit_dataset(&sd->pd->bl);
  375. pd->ud.dir = sd->ud.dir;
  376. map_addiddb(&pd->bl);
  377. // initialise
  378. if (battle_config.pet_lv_rate) //[Skotlex]
  379. pd->status = (struct pet_status *) aCalloc(1,sizeof(struct pet_status));
  380. status_calc_pet(sd,1);
  381. pd->state.skillbonus = -1;
  382. if (battle_config.pet_status_support) //Skotlex
  383. run_script(pet_db[i].script,0,sd->bl.id,0);
  384. if(sd->pet_hungry_timer != -1)
  385. pet_hungry_timer_delete(sd);
  386. if(battle_config.pet_hungry_delay_rate != 100)
  387. interval = (sd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100;
  388. else
  389. interval = sd->petDB->hungry_delay;
  390. if(interval <= 0)
  391. interval = 1;
  392. sd->pet_hungry_timer = add_timer(gettick()+interval,pet_hungry,sd->bl.id,0);
  393. return 0;
  394. }
  395. int pet_birth_process(struct map_session_data *sd)
  396. {
  397. nullpo_retr(1, sd);
  398. Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
  399. if(sd->status.pet_id && sd->pet.incuvate == 1) {
  400. sd->status.pet_id = 0;
  401. return 1;
  402. }
  403. sd->pet.incuvate = 0;
  404. sd->pet.account_id = sd->status.account_id;
  405. sd->pet.char_id = sd->status.char_id;
  406. sd->status.pet_id = sd->pet.pet_id;
  407. if(pet_data_init(sd)) {
  408. sd->status.pet_id = 0;
  409. sd->pet.incuvate = 1;
  410. sd->pet.account_id = 0;
  411. sd->pet.char_id = 0;
  412. return 1;
  413. }
  414. intif_save_petdata(sd->status.account_id,&sd->pet);
  415. chrif_save(sd,0); //FIXME: As before, is it REALLY Needed to save the char for hatching a pet? [Skotlex]
  416. map_addblock(&sd->pd->bl);
  417. clif_spawn(&sd->pd->bl);
  418. clif_send_petdata(sd,0,0);
  419. clif_send_petdata(sd,5,battle_config.pet_hair_style);
  420. clif_pet_equip(sd->pd,sd->pet.equip);
  421. clif_send_petstatus(sd);
  422. Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
  423. return 0;
  424. }
  425. int pet_recv_petdata(int account_id,struct s_pet *p,int flag)
  426. {
  427. struct map_session_data *sd;
  428. sd = map_id2sd(account_id);
  429. if(sd == NULL)
  430. return 1;
  431. if(flag == 1) {
  432. sd->status.pet_id = 0;
  433. return 1;
  434. }
  435. memcpy(&sd->pet,p,sizeof(struct s_pet));
  436. if(sd->pet.incuvate == 1) {
  437. int i;
  438. //Delete egg from inventory. [Skotlex]
  439. for (i = 0; i < MAX_INVENTORY; i++) {
  440. if(sd->status.inventory[i].card[0] == (short)0xff00 &&
  441. p->pet_id == MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2]))
  442. break;
  443. }
  444. if(i >= MAX_INVENTORY) {
  445. if (battle_config.error_log)
  446. ShowError("pet_recv_petdata: Hatching pet (%d:%s) aborted, couldn't find egg in inventory for removal!\n",p->pet_id, p->name);
  447. sd->status.pet_id = 0;
  448. memset(&sd->pet,0,sizeof(struct s_pet));
  449. sd->pet.incuvate = 1;
  450. return 1;
  451. }
  452. if (!pet_birth_process(sd)) //Pet hatched. Delete egg.
  453. pc_delitem(sd,i,1,0);
  454. } else {
  455. pet_data_init(sd);
  456. if(sd->pd && sd->bl.prev != NULL) {
  457. map_addblock(&sd->pd->bl);
  458. clif_spawn(&sd->pd->bl);
  459. clif_send_petdata(sd,0,0);
  460. clif_send_petdata(sd,5,battle_config.pet_hair_style);
  461. // clif_pet_equip(sd->pd,sd->pet.equip);
  462. clif_send_petstatus(sd);
  463. }
  464. }
  465. if(battle_config.pet_status_support && sd->pet.intimate > 0) {
  466. if(sd->bl.prev != NULL)
  467. status_calc_pc(sd,0);
  468. else
  469. status_calc_pc(sd,2);
  470. }
  471. return 0;
  472. }
  473. int pet_select_egg(struct map_session_data *sd,short egg_index)
  474. {
  475. nullpo_retr(0, sd);
  476. if(egg_index < 0 || egg_index >= MAX_INVENTORY)
  477. return 0; //Forged packet!
  478. if(sd->status.inventory[egg_index].card[0] == (short)0xff00)
  479. intif_request_petdata(sd->status.account_id, sd->status.char_id, MakeDWord(sd->status.inventory[egg_index].card[1], sd->status.inventory[egg_index].card[2]) );
  480. else {
  481. if(battle_config.error_log)
  482. ShowError("wrong egg item inventory %d\n",egg_index);
  483. }
  484. return 0;
  485. }
  486. int pet_catch_process1(struct map_session_data *sd,int target_class)
  487. {
  488. nullpo_retr(0, sd);
  489. sd->catch_target_class = target_class;
  490. clif_catch_process(sd);
  491. return 0;
  492. }
  493. int pet_catch_process2(struct map_session_data *sd,int target_id)
  494. {
  495. struct mob_data *md;
  496. int i=0,pet_catch_rate=0;
  497. nullpo_retr(1, sd);
  498. md=(struct mob_data*)map_id2bl(target_id);
  499. if(!md || md->bl.type != BL_MOB || md->bl.prev == NULL){
  500. //Abort capture.
  501. sd->catch_target_class = -1;
  502. sd->itemid = sd->itemindex = -1;
  503. return 1;
  504. }
  505. if (sd->menuskill_id != SA_TAMINGMONSTER)
  506. { //Exploit?
  507. clif_pet_rulet(sd,0);
  508. sd->catch_target_class = -1;
  509. return 1;
  510. }
  511. if (sd->menuskill_lv > 0)
  512. { //Consume the pet lure [Skotlex]
  513. i=pc_search_inventory(sd,sd->menuskill_lv);
  514. if (i < 0)
  515. { //they tried an exploit?
  516. clif_pet_rulet(sd,0);
  517. sd->catch_target_class = -1;
  518. return 1;
  519. }
  520. //Delete the item
  521. if (sd->itemid == sd->menuskill_lv)
  522. sd->itemid = sd->itemindex = -1;
  523. sd->menuskill_id = sd->menuskill_lv = 0;
  524. pc_delitem(sd,i,1,0);
  525. }
  526. i = search_petDB_index(md->class_,PET_CLASS);
  527. //catch_target_class == 0 is used for universal lures. [Skotlex]
  528. //for now universal lures do not include bosses.
  529. if (sd->catch_target_class == 0 && !(md->db->mode&0x20))
  530. sd->catch_target_class = md->class_;
  531. if(i < 0 || sd->catch_target_class != md->class_) {
  532. clif_emotion(&md->bl, 7); //mob will do /ag if wrong lure is used on them.
  533. clif_pet_rulet(sd,0);
  534. sd->catch_target_class = -1;
  535. return 1;
  536. }
  537. //target_idによる敵→卵判定
  538. // if(battle_config.etc_log)
  539. // printf("mob_id = %d, mob_class = %d\n",md->bl.id,md->class_);
  540. //成功の場合
  541. pet_catch_rate = (pet_db[i].capture + (sd->status.base_level - md->db->lv)*30 + sd->paramc[5]*20)*(200 - md->hp*100/md->db->max_hp)/100;
  542. if(pet_catch_rate < 1) pet_catch_rate = 1;
  543. if(battle_config.pet_catch_rate != 100)
  544. pet_catch_rate = (pet_catch_rate*battle_config.pet_catch_rate)/100;
  545. if(rand()%10000 < pet_catch_rate) {
  546. unit_remove_map(&md->bl,0);
  547. clif_pet_rulet(sd,1);
  548. // if(battle_config.etc_log)
  549. // printf("rulet success %d\n",target_id);
  550. intif_create_pet(sd->status.account_id,sd->status.char_id,pet_db[i].class_,mob_db(pet_db[i].class_)->lv,
  551. pet_db[i].EggID,0,pet_db[i].intimate,100,0,1,pet_db[i].jname);
  552. }
  553. else
  554. {
  555. sd->catch_target_class = -1;
  556. clif_pet_rulet(sd,0);
  557. }
  558. return 0;
  559. }
  560. int pet_get_egg(int account_id,int pet_id,int flag)
  561. { //This function is invoked when a new pet has been created, and at no other time!
  562. struct map_session_data *sd;
  563. struct item tmp_item;
  564. int i=0,ret=0;
  565. if(!flag) {
  566. sd = map_id2sd(account_id);
  567. if(sd == NULL)
  568. return 1;
  569. i = search_petDB_index(sd->catch_target_class,PET_CLASS);
  570. sd->catch_target_class = -1;
  571. if(i >= 0) {
  572. memset(&tmp_item,0,sizeof(tmp_item));
  573. tmp_item.nameid = pet_db[i].EggID;
  574. tmp_item.identify = 1;
  575. tmp_item.card[0] = (short)0xff00;
  576. tmp_item.card[1] = GetWord(pet_id,0);
  577. tmp_item.card[2] = GetWord(pet_id,1);
  578. tmp_item.card[3] = 0; //New pets are not named.
  579. if((ret = pc_additem(sd,&tmp_item,1))) {
  580. clif_additem(sd,0,0,ret);
  581. map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
  582. }
  583. }
  584. else
  585. intif_delete_petdata(pet_id);
  586. }
  587. return 0;
  588. }
  589. int pet_menu(struct map_session_data *sd,int menunum)
  590. {
  591. nullpo_retr(0, sd);
  592. if (sd->pd == NULL)
  593. return 1;
  594. //You lost the pet already.
  595. if(sd->pet.intimate <= 0)
  596. return 1;
  597. switch(menunum) {
  598. case 0:
  599. clif_send_petstatus(sd);
  600. break;
  601. case 1:
  602. pet_food(sd);
  603. break;
  604. case 2:
  605. pet_performance(sd);
  606. break;
  607. case 3:
  608. pet_return_egg(sd);
  609. break;
  610. case 4:
  611. pet_unequipitem(sd);
  612. break;
  613. }
  614. return 0;
  615. }
  616. int pet_change_name(struct map_session_data *sd,char *name)
  617. {
  618. int i;
  619. nullpo_retr(1, sd);
  620. if((sd->pd == NULL) || (sd->pet.rename_flag == 1 && battle_config.pet_rename == 0))
  621. return 1;
  622. for(i=0;i<NAME_LENGTH && name[i];i++){
  623. if( !(name[i]&0xe0) || name[i]==0x7f)
  624. return 1;
  625. }
  626. pet_stop_walking(sd->pd,1);
  627. memcpy(sd->pet.name, name, NAME_LENGTH-1);
  628. memcpy(sd->pd->name, name, NAME_LENGTH-1);
  629. clif_clearchar_area(&sd->pd->bl,0);
  630. clif_spawn(&sd->pd->bl);
  631. clif_send_petdata(sd,0,0);
  632. clif_send_petdata(sd,5,battle_config.pet_hair_style);
  633. sd->pet.rename_flag = 1;
  634. clif_pet_equip(sd->pd,sd->pet.equip);
  635. clif_send_petstatus(sd);
  636. return 0;
  637. }
  638. int pet_equipitem(struct map_session_data *sd,int index)
  639. {
  640. int nameid;
  641. nullpo_retr(1, sd);
  642. nameid = sd->status.inventory[index].nameid;
  643. if(sd->petDB == NULL)
  644. return 1;
  645. if(sd->petDB->AcceID == 0 || nameid != sd->petDB->AcceID || sd->pet.equip != 0) {
  646. clif_equipitemack(sd,0,0,0);
  647. return 1;
  648. }
  649. else {
  650. pc_delitem(sd,index,1,0);
  651. sd->pet.equip = sd->pd->equip = nameid;
  652. status_calc_pc(sd,0);
  653. clif_pet_equip(sd->pd,nameid);
  654. if (battle_config.pet_equip_required)
  655. { //Skotlex: start support timers if needd
  656. if (sd->pd->s_skill && sd->pd->s_skill->timer == -1)
  657. {
  658. if (sd->pd->s_skill->id)
  659. sd->pd->s_skill->timer=add_timer(gettick()+sd->pd->s_skill->delay*1000, pet_skill_support_timer, sd->bl.id, 0);
  660. else
  661. sd->pd->s_skill->timer=add_timer(gettick()+sd->pd->s_skill->delay*1000, pet_heal_timer, sd->bl.id, 0);
  662. }
  663. if (sd->pd->bonus && sd->pd->bonus->timer == -1)
  664. sd->pd->bonus->timer=add_timer(gettick()+sd->pd->bonus->delay*1000, pet_skill_bonus_timer, sd->bl.id, 0);
  665. }
  666. }
  667. return 0;
  668. }
  669. int pet_unequipitem(struct map_session_data *sd)
  670. {
  671. struct item tmp_item;
  672. int nameid,flag;
  673. nullpo_retr(1, sd);
  674. if(sd->petDB == NULL)
  675. return 1;
  676. if(sd->pet.equip == 0)
  677. return 1;
  678. nameid = sd->pet.equip;
  679. sd->pet.equip = sd->pd->equip = 0;
  680. status_calc_pc(sd,0);
  681. clif_pet_equip(sd->pd,0);
  682. memset(&tmp_item,0,sizeof(tmp_item));
  683. tmp_item.nameid = nameid;
  684. tmp_item.identify = 1;
  685. if((flag = pc_additem(sd,&tmp_item,1))) {
  686. clif_additem(sd,0,0,flag);
  687. map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
  688. }
  689. if (battle_config.pet_equip_required)
  690. { //Skotlex: halt support timers if needed
  691. if (sd->pd->s_skill && sd->pd->s_skill->timer != -1)
  692. {
  693. if (sd->pd->s_skill->id)
  694. delete_timer(sd->pd->s_skill->timer, pet_skill_support_timer);
  695. else
  696. delete_timer(sd->pd->s_skill->timer, pet_heal_timer);
  697. sd->pd->s_skill->timer = -1;
  698. }
  699. if (sd->pd->bonus && sd->pd->bonus->timer != -1)
  700. {
  701. delete_timer(sd->pd->bonus->timer, pet_skill_bonus_timer);
  702. sd->pd->bonus->timer = -1;
  703. }
  704. }
  705. return 0;
  706. }
  707. int pet_food(struct map_session_data *sd)
  708. {
  709. int i,k;
  710. nullpo_retr(1, sd);
  711. if(sd->petDB == NULL)
  712. return 1;
  713. i=pc_search_inventory(sd,sd->petDB->FoodID);
  714. if(i < 0) {
  715. clif_pet_food(sd,sd->petDB->FoodID,0);
  716. return 1;
  717. }
  718. pc_delitem(sd,i,1,0);
  719. if(sd->pet.hungry > 90)
  720. sd->pet.intimate -= sd->petDB->r_full;
  721. else {
  722. if(battle_config.pet_friendly_rate != 100)
  723. k = (sd->petDB->r_hungry * battle_config.pet_friendly_rate)/100;
  724. else
  725. k = sd->petDB->r_hungry;
  726. if(sd->pet.hungry > 75) {
  727. k = k >> 1;
  728. if(k <= 0)
  729. k = 1;
  730. }
  731. sd->pet.intimate += k;
  732. }
  733. if(sd->pet.intimate <= 0) {
  734. sd->pet.intimate = 0;
  735. pet_stop_attack(sd->pd);
  736. sd->pd->speed = sd->pd->db->speed;
  737. if(battle_config.pet_status_support) {
  738. if(sd->bl.prev != NULL)
  739. status_calc_pc(sd,0);
  740. else
  741. status_calc_pc(sd,2);
  742. }
  743. }
  744. else if(sd->pet.intimate > 1000)
  745. sd->pet.intimate = 1000;
  746. status_calc_pet(sd, 0);
  747. sd->pet.hungry += sd->petDB->fullness;
  748. if(sd->pet.hungry > 100)
  749. sd->pet.hungry = 100;
  750. clif_send_petdata(sd,2,sd->pet.hungry);
  751. clif_send_petdata(sd,1,sd->pet.intimate);
  752. clif_pet_food(sd,sd->petDB->FoodID,1);
  753. return 0;
  754. }
  755. static int pet_randomwalk(struct pet_data *pd,unsigned int tick)
  756. {
  757. const int retrycount=20;
  758. int speed;
  759. nullpo_retr(0, pd);
  760. Assert((pd->msd == 0) || (pd->msd->pd == pd));
  761. speed = status_get_speed(&pd->bl);
  762. if(DIFF_TICK(pd->next_walktime,tick) < 0){
  763. int i,x,y,c,d=12-pd->move_fail_count;
  764. if(d<5) d=5;
  765. for(i=0;i<retrycount;i++){
  766. int r=rand();
  767. x=pd->bl.x+r%(d*2+1)-d;
  768. y=pd->bl.y+r/(d*2+1)%(d*2+1)-d;
  769. if(map_getcell(pd->bl.m,x,y,CELL_CHKPASS) && unit_walktoxy(&pd->bl,x,y,0)){
  770. pd->move_fail_count=0;
  771. break;
  772. }
  773. if(i+1>=retrycount){
  774. pd->move_fail_count++;
  775. if(pd->move_fail_count>1000){
  776. if(battle_config.error_log)
  777. ShowWarning("PET cant move. hold position %d, class = %d\n",pd->bl.id,pd->class_);
  778. pd->move_fail_count=0;
  779. pd->ud.canmove_tick = tick + 60000;
  780. return 0;
  781. }
  782. }
  783. }
  784. for(i=c=0;i<pd->ud.walkpath.path_len;i++){
  785. if(pd->ud.walkpath.path[i]&1)
  786. c+=speed*14/10;
  787. else
  788. c+=speed;
  789. }
  790. pd->next_walktime = tick+rand()%3000+3000+c;
  791. return 1;
  792. }
  793. return 0;
  794. }
  795. static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick)
  796. {
  797. struct map_session_data *sd;
  798. struct block_list *target = NULL;
  799. int i=0,dx,dy;
  800. sd = pd->msd;
  801. Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
  802. if(pd->bl.prev == NULL || sd == NULL || sd->bl.prev == NULL)
  803. return 0;
  804. if(DIFF_TICK(tick,pd->last_thinktime) < MIN_PETTHINKTIME)
  805. return 0;
  806. pd->last_thinktime=tick;
  807. if(pd->ud.attacktimer != -1 || pd->ud.skilltimer != -1 || pd->bl.m != sd->bl.m)
  808. return 0;
  809. if(pd->ud.walktimer != -1 && pd->ud.walkpath.path_pos <= 3)
  810. return 0; //No thinking when you just started to walk.
  811. if(sd->pet.intimate <= 0) {
  812. //Pet should just... well, random walk.
  813. pet_randomwalk(pd,tick);
  814. return 0;
  815. }
  816. if (!check_distance_bl(&sd->bl, &pd->bl, pd->db->range2)) {
  817. //Master too far, chase.
  818. if(pd->target_id)
  819. pet_unlocktarget(pd);
  820. if(pd->ud.walktimer != -1 && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3))
  821. return 0; //Already walking to him
  822. pd->speed = (sd->speed>>1);
  823. if(pd->speed <= 0)
  824. pd->speed = 1;
  825. pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir);
  826. if(!unit_walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0))
  827. pet_randomwalk(pd,tick);
  828. return 0;
  829. }
  830. //Return speed to normal.
  831. if (pd->speed != sd->petDB->speed)
  832. pd->speed = sd->petDB->speed;
  833. if (pd->target_id) {
  834. target= map_id2bl(pd->target_id);
  835. if (!target || pd->bl.m != target->m || target->prev == NULL ||
  836. !check_distance_bl(&pd->bl, target, pd->db->range3))
  837. pet_unlocktarget(pd);
  838. }
  839. // ペットによるルート
  840. if(!pd->target_id && pd->loot && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0)
  841. //Use half the pet's range of sight.
  842. map_foreachinrange(pet_ai_sub_hard_lootsearch,&pd->bl,
  843. pd->db->range2/2, BL_ITEM,pd,&i);
  844. if (!target) {
  845. //Just walk around.
  846. if (check_distance_bl(&sd->bl, &pd->bl, 3))
  847. return 0; //Already next to master.
  848. if(pd->ud.walktimer != -1 && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3))
  849. return 0; //Already walking to him
  850. pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir);
  851. if(!unit_walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0))
  852. pet_randomwalk(pd,tick);
  853. return 0;
  854. }
  855. if (target->type != BL_ITEM)
  856. { //enemy targetted
  857. if(!battle_check_range(&pd->bl,target,pd->db->range))
  858. { //Chase
  859. if(pd->ud.walktimer != -1 && check_distance_blxy(target, pd->ud.to_x,pd->ud.to_y, pd->db->range))
  860. return 0;
  861. if(!unit_can_reach(&pd->bl, target->x, target->y))
  862. { //Unreachable target.
  863. pet_unlocktarget(pd);
  864. return 0;
  865. }
  866. i=0;
  867. do {
  868. if(i==0) { // 最初はAEGISと同じ方法で検索
  869. dx=target->x - pd->bl.x;
  870. dy=target->y - pd->bl.y;
  871. if(dx<0) dx++;
  872. else if(dx>0) dx--;
  873. if(dy<0) dy++;
  874. else if(dy>0) dy--;
  875. }
  876. else { // だめならAthena式(ランダム)
  877. dx=target->x - pd->bl.x + rand()%3 - 1;
  878. dy=target->y - pd->bl.y + rand()%3 - 1;
  879. }
  880. } while(!unit_walktoxy(&pd->bl,pd->bl.x+dx,pd->bl.y+dy,0) && ++i<5);
  881. if(i>=5) {
  882. if(dx<0) dx=2;
  883. else if(dx>0) dx=-2;
  884. if(dy<0) dy=2;
  885. else if(dy>0) dy=-2;
  886. unit_walktoxy(&pd->bl,pd->bl.x+dx,pd->bl.y+dy,0);
  887. }
  888. return 0;
  889. } //End Chase
  890. pet_stop_walking(pd,1);
  891. //Continuous attack.
  892. unit_attack(&pd->bl, pd->target_id, 1);
  893. } else { //Item Targeted, attempt loot
  894. if (!check_distance_bl(&pd->bl, target, 1))
  895. { //Out of range
  896. if(pd->ud.walktimer != -1 && check_distance_blxy(target, pd->ud.to_x, pd->ud.to_y, 0))
  897. return 0; // 既に移動中
  898. if(!unit_can_reach(&pd->bl, target->x, target->y))
  899. { //Unreachable target.
  900. pet_unlocktarget(pd);
  901. return 0;
  902. }
  903. unit_walktoxy(&pd->bl, target->x, target->y, 1);
  904. } else{ // アイテムまでたどり着いた
  905. struct flooritem_data *fitem = (struct flooritem_data *)target;
  906. pet_stop_walking(pd,1);
  907. if(pd->loot->count < pd->loot->max){
  908. memcpy(&pd->loot->item[pd->loot->count++],&fitem->item_data,sizeof(pd->loot->item[0]));
  909. pd->loot->weight += itemdb_search(fitem->item_data.nameid)->weight*fitem->item_data.amount;
  910. map_clearflooritem(target->id);
  911. }
  912. //Target is unlocked regardless of whether it was picked or not.
  913. pet_unlocktarget(pd);
  914. }
  915. }
  916. return 0;
  917. }
  918. static int pet_ai_sub_foreachclient(struct map_session_data *sd,va_list ap)
  919. {
  920. unsigned int tick;
  921. tick=va_arg(ap,unsigned int);
  922. if(sd->status.pet_id && sd->pd && sd->petDB)
  923. pet_ai_sub_hard(sd->pd,tick);
  924. return 0;
  925. }
  926. static int pet_ai_hard(int tid,unsigned int tick,int id,int data)
  927. {
  928. clif_foreachclient(pet_ai_sub_foreachclient,tick);
  929. return 0;
  930. }
  931. int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
  932. {
  933. struct pet_data* pd;
  934. struct flooritem_data *fitem = (struct flooritem_data *)bl;
  935. struct map_session_data *sd = NULL;
  936. int *itc;
  937. pd=va_arg(ap,struct pet_data *);
  938. itc=va_arg(ap,int *);
  939. // ルート権無し
  940. if(fitem && fitem->first_get_id)
  941. sd = map_id2sd(fitem->first_get_id);
  942. // Removed [Valaris]
  943. //if((pd->lootitem_weight + (itemdb_search(fitem->item_data.))->weight * fitem->item_data.amount) > battle_config.pet_weight)
  944. // return 0;
  945. if(pd->loot == NULL || pd->loot->item == NULL || (pd->loot->count >= pd->loot->max) || (sd && sd->pd != pd))
  946. return 0;
  947. if(bl->m == pd->bl.m && check_distance_bl(&pd->bl, bl, pd->db->range2) &&
  948. unit_can_reach(&pd->bl,bl->x,bl->y) && rand()%1000<1000/(++(*itc)))
  949. pd->target_id=bl->id;
  950. return 0;
  951. }
  952. int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd)
  953. {
  954. int i,flag=0;
  955. struct delay_item_drop2 *ditem_floor, ditem;
  956. if(pd && pd->loot && pd->loot->count) {
  957. memset(&ditem, 0, sizeof(struct delay_item_drop2));
  958. ditem.m = pd->bl.m;
  959. ditem.x = pd->bl.x;
  960. ditem.y = pd->bl.y;
  961. ditem.first_sd = 0;
  962. ditem.second_sd = 0;
  963. ditem.third_sd = 0;
  964. for(i=0;i<pd->loot->count;i++) {
  965. memcpy(&ditem.item_data,&pd->loot->item[i],sizeof(pd->loot->item[0]));
  966. // 落とさないで直接PCのItem欄へ
  967. if(sd){
  968. if((flag = pc_additem(sd,&ditem.item_data,ditem.item_data.amount))){
  969. clif_additem(sd,0,0,flag);
  970. 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);
  971. }
  972. }
  973. else {
  974. ditem_floor=(struct delay_item_drop2 *)aCalloc(1,sizeof(struct delay_item_drop2));
  975. memcpy(ditem_floor, &ditem, sizeof(struct delay_item_drop2));
  976. add_timer(gettick()+540+i,pet_delay_item_drop2,(int)ditem_floor,0);
  977. }
  978. }
  979. //The smart thing to do is use pd->loot->max (thanks for pointing it out, Shinomori)
  980. memset(pd->loot->item,0,pd->loot->max * sizeof(struct item));
  981. pd->loot->count = 0;
  982. pd->loot->weight = 0;
  983. pd->ud.canact_tick = gettick()+10000; // 10*1000msの間拾わない
  984. }
  985. return 1;
  986. }
  987. int pet_delay_item_drop2(int tid,unsigned int tick,int id,int data)
  988. {
  989. struct delay_item_drop2 *ditem;
  990. ditem=(struct delay_item_drop2 *)id;
  991. 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);
  992. aFree(ditem);
  993. return 0;
  994. }
  995. /*==========================================
  996. * pet bonus giving skills [Valaris] / Rewritten by [Skotlex]
  997. *------------------------------------------
  998. */
  999. int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data)
  1000. {
  1001. struct map_session_data *sd=map_id2sd(id);
  1002. struct pet_data *pd;
  1003. int timer = 0;
  1004. if(sd == NULL || sd->pd==NULL || sd->pd->bonus == NULL)
  1005. return 1;
  1006. pd=sd->pd;
  1007. if(pd->bonus->timer != tid) {
  1008. if(battle_config.error_log)
  1009. {
  1010. ShowError("pet_skill_bonus_timer %d != %d\n",pd->bonus->timer,tid);
  1011. pd->bonus->timer = -1;
  1012. }
  1013. return 0;
  1014. }
  1015. // determine the time for the next timer
  1016. if (pd->state.skillbonus == 0) {
  1017. // pet bonuses are not active at the moment, so,
  1018. pd->state.skillbonus = 1;
  1019. timer = pd->bonus->duration*1000; // the duration for pet bonuses to be in effect
  1020. } else if (pd->state.skillbonus == 1) {
  1021. // pet bonuses are already active, so,
  1022. pd->state.skillbonus = 0;
  1023. timer = pd->bonus->delay*1000; // the duration until pet bonuses will be reactivated again
  1024. if (timer <= 0) //Always active bonus
  1025. timer = MIN_PETTHINKTIME;
  1026. }
  1027. // add/remove our bonuses
  1028. status_calc_pc(sd, 0);
  1029. // wait for the next timer
  1030. pd->bonus->timer=add_timer(tick+timer,pet_skill_bonus_timer,sd->bl.id,0);
  1031. return 0;
  1032. }
  1033. /*==========================================
  1034. * pet recovery skills [Valaris] / Rewritten by [Skotlex]
  1035. *------------------------------------------
  1036. */
  1037. int pet_recovery_timer(int tid,unsigned int tick,int id,int data)
  1038. {
  1039. struct map_session_data *sd=map_id2sd(id);
  1040. struct pet_data *pd;
  1041. if(sd==NULL || sd->pd == NULL || sd->pd->recovery == NULL)
  1042. return 1;
  1043. pd=sd->pd;
  1044. if(pd->recovery->timer != tid) {
  1045. if(battle_config.error_log)
  1046. ShowError("pet_recovery_timer %d != %d\n",pd->recovery->timer,tid);
  1047. return 0;
  1048. }
  1049. if(sd->sc.count && sd->sc.data[pd->recovery->type].timer != -1)
  1050. { //Display a heal animation?
  1051. //Detoxify is chosen for now.
  1052. clif_skill_nodamage(&pd->bl,&sd->bl,TF_DETOXIFY,1,1);
  1053. status_change_end(&sd->bl,pd->recovery->type,-1);
  1054. clif_emotion(&pd->bl, 33);
  1055. }
  1056. pd->recovery->timer = -1;
  1057. return 0;
  1058. }
  1059. int pet_heal_timer(int tid,unsigned int tick,int id,int data)
  1060. {
  1061. struct map_session_data *sd=map_id2sd(id);
  1062. struct pet_data *pd;
  1063. short rate = 100;
  1064. if(sd==NULL || sd->pd == NULL || sd->pd->s_skill == NULL)
  1065. return 1;
  1066. pd=sd->pd;
  1067. if(pd->s_skill->timer != tid) {
  1068. if(battle_config.error_log)
  1069. ShowError("pet_heal_timer %d != %d\n",pd->s_skill->timer,tid);
  1070. return 0;
  1071. }
  1072. if(pc_isdead(sd) ||
  1073. (rate = sd->status.sp*100/sd->status.max_sp) > pd->s_skill->sp ||
  1074. (rate = sd->status.hp*100/sd->status.max_hp) > pd->s_skill->hp ||
  1075. (rate = (pd->ud.skilltimer != -1)) //Another skill is in effect
  1076. ) { //Wait (how long? 1 sec for every 10% of remaining)
  1077. pd->s_skill->timer=add_timer(gettick()+(rate>10?rate:10)*100,pet_heal_timer,sd->bl.id,0);
  1078. return 0;
  1079. }
  1080. pet_stop_attack(pd);
  1081. pet_stop_walking(pd,1);
  1082. clif_skill_nodamage(&pd->bl,&sd->bl,AL_HEAL,pd->s_skill->lv,1);
  1083. pc_heal(sd,pd->s_skill->lv,0);
  1084. pd->s_skill->timer=add_timer(tick+pd->s_skill->delay*1000,pet_heal_timer,sd->bl.id,0);
  1085. return 0;
  1086. }
  1087. /*==========================================
  1088. * pet support skills [Skotlex]
  1089. *------------------------------------------
  1090. */
  1091. int pet_skill_support_timer(int tid,unsigned int tick,int id,int data)
  1092. {
  1093. struct map_session_data *sd=map_id2sd(id);
  1094. struct pet_data *pd;
  1095. short rate = 100;
  1096. if(sd==NULL || sd->pd == NULL || sd->pd->s_skill == NULL)
  1097. return 1;
  1098. pd=sd->pd;
  1099. if(pd->s_skill->timer != tid) {
  1100. if(battle_config.error_log)
  1101. ShowError("pet_skill_support_timer %d != %d\n",pd->s_skill->timer,tid);
  1102. return 0;
  1103. }
  1104. if(pc_isdead(sd) ||
  1105. (rate = sd->status.sp*100/sd->status.max_sp) > pd->s_skill->sp ||
  1106. (rate = sd->status.hp*100/sd->status.max_hp) > pd->s_skill->hp ||
  1107. (rate = (pd->ud.skilltimer != -1)) //Another skill is in effect
  1108. ) { //Wait (how long? 1 sec for every 10% of remaining)
  1109. pd->s_skill->timer=add_timer(gettick()+(rate>10?rate:10)*100,pet_skill_support_timer,sd->bl.id,0);
  1110. return 0;
  1111. }
  1112. pet_stop_attack(pd);
  1113. pet_stop_walking(pd,1);
  1114. if (skill_get_inf(pd->s_skill->id) & INF_GROUND_SKILL)
  1115. unit_skilluse_pos(&pd->bl, sd->bl.x, sd->bl.y, pd->s_skill->id, pd->s_skill->lv);
  1116. else
  1117. unit_skilluse_id(&pd->bl, sd->bl.id, pd->s_skill->id, pd->s_skill->lv);
  1118. pd->s_skill->timer=add_timer(tick+pd->s_skill->delay*1000,pet_skill_support_timer,sd->bl.id,0);
  1119. return 0;
  1120. }
  1121. /*==========================================
  1122. *ペットデータ読み込み
  1123. *------------------------------------------
  1124. */
  1125. int read_petdb()
  1126. {
  1127. FILE *fp;
  1128. char line[1024];
  1129. int nameid,i,k;
  1130. int j=0;
  1131. int lines;
  1132. char *filename[]={"pet_db.txt","pet_db2.txt"};
  1133. char *str[32],*p,*np;
  1134. //Remove any previous scripts in case reloaddb was invoked.
  1135. for(j =0; j < MAX_PET_DB; j++)
  1136. if (pet_db[j].script) {
  1137. aFree(pet_db[j].script);
  1138. pet_db[j].script = NULL;
  1139. }
  1140. j = 0;
  1141. memset(pet_db,0,sizeof(pet_db));
  1142. for(i=0;i<2;i++){
  1143. sprintf(line, "%s/%s", db_path, filename[i]);
  1144. fp=fopen(line,"r");
  1145. if(fp==NULL){
  1146. if(i>0)
  1147. continue;
  1148. ShowError("can't read %s\n",line);
  1149. return -1;
  1150. }
  1151. lines = 0;
  1152. while(fgets(line,1020,fp) && j < MAX_PET_DB){
  1153. lines++;
  1154. if(line[0] == '/' && line[1] == '/')
  1155. continue;
  1156. for(k=0,p=line;k<20;k++){
  1157. if((np=strchr(p,','))!=NULL){
  1158. str[k]=p;
  1159. *np=0;
  1160. p=np+1;
  1161. } else {
  1162. str[k]=p;
  1163. p+=strlen(p);
  1164. }
  1165. }
  1166. nameid=atoi(str[0]);
  1167. if(nameid<=0 || nameid>2000)
  1168. continue;
  1169. //MobID,Name,JName,ItemID,EggID,AcceID,FoodID,"Fullness (1回の餌での満腹度増加率%)","HungryDeray (/min)","R_Hungry (空腹時餌やり親密度増加率%)","R_Full (とても満腹時餌やり親密度減少率%)","Intimate (捕獲時親密度%)","Die (死亡時親密度減少率%)","Capture (捕獲率%)",(Name)
  1170. pet_db[j].class_ = nameid;
  1171. memcpy(pet_db[j].name,str[1],NAME_LENGTH-1);
  1172. memcpy(pet_db[j].jname,str[2],NAME_LENGTH-1);
  1173. pet_db[j].itemID=atoi(str[3]);
  1174. pet_db[j].EggID=atoi(str[4]);
  1175. pet_db[j].AcceID=atoi(str[5]);
  1176. pet_db[j].FoodID=atoi(str[6]);
  1177. pet_db[j].fullness=atoi(str[7]);
  1178. pet_db[j].hungry_delay=atoi(str[8])*1000;
  1179. pet_db[j].r_hungry=atoi(str[9]);
  1180. if(pet_db[j].r_hungry <= 0)
  1181. pet_db[j].r_hungry=1;
  1182. pet_db[j].r_full=atoi(str[10]);
  1183. pet_db[j].intimate=atoi(str[11]);
  1184. pet_db[j].die=atoi(str[12]);
  1185. pet_db[j].capture=atoi(str[13]);
  1186. pet_db[j].speed=atoi(str[14]);
  1187. pet_db[j].s_perfor=(char)atoi(str[15]);
  1188. pet_db[j].talk_convert_class=atoi(str[16]);
  1189. pet_db[j].attack_rate=atoi(str[17]);
  1190. pet_db[j].defence_attack_rate=atoi(str[18]);
  1191. pet_db[j].change_target_rate=atoi(str[19]);
  1192. pet_db[j].script = NULL;
  1193. if((np=strchr(p,'{'))==NULL)
  1194. continue;
  1195. pet_db[j].script = parse_script((unsigned char *) np,lines);
  1196. j++;
  1197. }
  1198. if (j >= MAX_PET_DB)
  1199. ShowWarning("read_petdb: Reached max number of pets [%d]. Remaining pets were not read.\n ", MAX_PET_DB);
  1200. fclose(fp);
  1201. ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' pets in '"CL_WHITE"%s"CL_RESET"'.\n",j,filename[i]);
  1202. }
  1203. return 0;
  1204. }
  1205. /*==========================================
  1206. * スキル関係初期化処理
  1207. *------------------------------------------
  1208. */
  1209. int do_init_pet(void)
  1210. {
  1211. memset(pet_db,0,sizeof(pet_db));
  1212. read_petdb();
  1213. add_timer_func_list(pet_hungry,"pet_hungry");
  1214. add_timer_func_list(pet_ai_hard,"pet_ai_hard");
  1215. add_timer_func_list(pet_skill_bonus_timer,"pet_skill_bonus_timer"); // [Valaris]
  1216. add_timer_func_list(pet_delay_item_drop2,"pet_delay_item_drop2");
  1217. add_timer_func_list(pet_skill_support_timer, "pet_skill_support_timer"); // [Skotlex]
  1218. add_timer_func_list(pet_recovery_timer,"pet_recovery_timer"); // [Valaris]
  1219. add_timer_func_list(pet_heal_timer,"pet_heal_timer"); // [Valaris]
  1220. add_timer_interval(gettick()+MIN_PETTHINKTIME,pet_ai_hard,0,0,MIN_PETTHINKTIME);
  1221. return 0;
  1222. }
  1223. int do_final_pet(void) {
  1224. int i;
  1225. for(i = 0;i < MAX_PET_DB; i++) {
  1226. if(pet_db[i].script) {
  1227. aFree(pet_db[i].script);
  1228. pet_db[i].script = NULL;
  1229. }
  1230. }
  1231. return 0;
  1232. }