pet.c 36 KB

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