mercenary.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/cbasetypes.h"
  4. #include "../common/malloc.h"
  5. #include "../common/socket.h"
  6. #include "../common/timer.h"
  7. #include "../common/nullpo.h"
  8. #include "../common/mmo.h"
  9. #include "../common/showmsg.h"
  10. #include "../common/utils.h"
  11. #include "log.h"
  12. #include "clif.h"
  13. #include "chrif.h"
  14. #include "intif.h"
  15. #include "itemdb.h"
  16. #include "map.h"
  17. #include "pc.h"
  18. #include "status.h"
  19. #include "skill.h"
  20. #include "mob.h"
  21. #include "pet.h"
  22. #include "battle.h"
  23. #include "party.h"
  24. #include "guild.h"
  25. #include "atcommand.h"
  26. #include "script.h"
  27. #include "npc.h"
  28. #include "trade.h"
  29. #include "unit.h"
  30. #include "mercenary.h"
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <math.h>
  35. struct s_mercenary_db mercenary_db[MAX_MERCENARY_CLASS]; // Mercenary Database
  36. int merc_search_index(int class_)
  37. {
  38. int i;
  39. ARR_FIND(0, MAX_MERCENARY_CLASS, i, mercenary_db[i].class_ == class_);
  40. return (i == MAX_MERCENARY_CLASS)?-1:i;
  41. }
  42. bool merc_class(int class_)
  43. {
  44. return (bool)(merc_search_index(class_) > -1);
  45. }
  46. struct view_data * merc_get_viewdata(int class_)
  47. {
  48. int i = merc_search_index(class_);
  49. if( i < 0 )
  50. return 0;
  51. return &mercenary_db[i].vd;
  52. }
  53. int merc_create(struct map_session_data *sd, int class_, unsigned int lifetime)
  54. {
  55. struct s_mercenary merc;
  56. struct s_mercenary_db *db;
  57. int i;
  58. nullpo_retr(1,sd);
  59. if( (i = merc_search_index(class_)) < 0 )
  60. return 0;
  61. db = &mercenary_db[i];
  62. memset(&merc,0,sizeof(struct s_mercenary));
  63. merc.char_id = sd->status.char_id;
  64. merc.class_ = class_;
  65. merc.hp = db->status.max_hp;
  66. merc.sp = db->status.max_sp;
  67. merc.remain_life_time = lifetime;
  68. // Request Char Server to create this mercenary
  69. intif_mercenary_create(&merc);
  70. return 1;
  71. }
  72. int mercenary_save(struct mercenary_data *md)
  73. {
  74. md->mercenary.hp = md->battle_status.hp;
  75. md->mercenary.sp = md->battle_status.sp;
  76. intif_mercenary_save(&md->mercenary);
  77. return 1;
  78. }
  79. int merc_data_received(struct s_mercenary *merc, bool flag)
  80. {
  81. struct map_session_data *sd;
  82. struct mercenary_data *md;
  83. struct s_mercenary_db *db;
  84. int i = merc_search_index(merc->class_);
  85. if( (sd = map_charid2sd(merc->char_id)) == NULL )
  86. return 0;
  87. if( !flag || i < 0 )
  88. { // Not created - loaded - DB info
  89. sd->status.mer_id = 0;
  90. return 0;
  91. }
  92. sd->status.mer_id = merc->mercenary_id;
  93. db = &mercenary_db[i];
  94. if( !sd->md )
  95. {
  96. sd->md = md = (struct mercenary_data*)aCalloc(1,sizeof(struct mercenary_data));
  97. md->bl.type = BL_MER;
  98. md->bl.id = npc_get_new_npc_id();
  99. md->master = sd;
  100. md->db = db;
  101. memcpy(&md->mercenary, merc, sizeof(struct s_mercenary));
  102. status_set_viewdata(&md->bl, md->mercenary.class_);
  103. status_change_init(&md->bl);
  104. unit_dataset(&md->bl);
  105. md->ud.dir = sd->ud.dir;
  106. md->bl.m = sd->bl.m;
  107. md->bl.x = sd->bl.x;
  108. md->bl.y = sd->bl.y;
  109. unit_calc_pos(&md->bl, sd->bl.x, sd->bl.y, sd->ud.dir);
  110. md->bl.x = md->ud.to_x;
  111. md->bl.y = md->ud.to_y;
  112. map_addiddb(&md->bl);
  113. status_calc_mercenary(md,1);
  114. }
  115. else
  116. memcpy(&sd->md->mercenary, merc, sizeof(struct s_mercenary));
  117. md = sd->md;
  118. if( md && md->bl.prev == NULL && sd->bl.prev != NULL )
  119. {
  120. map_addblock(&md->bl);
  121. clif_spawn(&md->bl);
  122. clif_mercenary_info(sd);
  123. clif_mercenary_skillblock(sd);
  124. // init timers
  125. }
  126. return 1;
  127. }
  128. int read_mercenarydb(void)
  129. {
  130. FILE *fp;
  131. char line[1024], *p;
  132. char *str[26];
  133. int i, j = 0, k = 0, ele;
  134. struct s_mercenary_db *db;
  135. struct status_data *status;
  136. sprintf(line, "%s/%s", db_path, "mercenary_db.txt");
  137. memset(mercenary_db,0,sizeof(mercenary_db));
  138. fp = fopen(line, "r");
  139. if( !fp )
  140. {
  141. ShowError("read_mercenarydb : can't read mercenary_db.txt\n");
  142. return -1;
  143. }
  144. while( fgets(line, sizeof(line), fp) && j < MAX_MERCENARY_CLASS )
  145. {
  146. k++;
  147. if( line[0] == '/' && line[1] == '/' )
  148. continue;
  149. i = 0;
  150. p = strtok(line, ",");
  151. while( p != NULL && i < 26 )
  152. {
  153. str[i++] = p;
  154. p = strtok(NULL, ",");
  155. }
  156. if( i < 26 )
  157. {
  158. ShowError("read_mercenarydb : Incorrect number of columns at mercenary_db.txt line %d.\n", k);
  159. continue;
  160. }
  161. db = &mercenary_db[j];
  162. db->class_ = atoi(str[0]);
  163. strncpy(db->sprite, str[1], NAME_LENGTH);
  164. strncpy(db->name, str[2], NAME_LENGTH);
  165. db->lv = atoi(str[3]);
  166. status = &db->status;
  167. db->vd.class_ = db->class_;
  168. status->max_hp = atoi(str[4]);
  169. status->max_sp = atoi(str[5]);
  170. status->rhw.range = atoi(str[6]);
  171. status->rhw.atk = atoi(str[7]);
  172. status->rhw.atk2 = atoi(str[8]);
  173. status->def = atoi(str[9]);
  174. status->mdef = atoi(str[10]);
  175. status->str = atoi(str[11]);
  176. status->agi = atoi(str[12]);
  177. status->vit = atoi(str[13]);
  178. status->int_ = atoi(str[14]);
  179. status->dex = atoi(str[15]);
  180. status->luk = atoi(str[16]);
  181. db->range2 = atoi(str[17]);
  182. db->range3 = atoi(str[18]);
  183. status->size = atoi(str[19]);
  184. status->race = atoi(str[20]);
  185. ele = atoi(str[21]);
  186. status->def_ele = ele%10;
  187. status->ele_lv = ele/20;
  188. if( status->def_ele >= ELE_MAX )
  189. {
  190. ShowWarning("Mercenary %d has invalid element type %d (max element is %d)\n", db->class_, status->def_ele, ELE_MAX - 1);
  191. status->def_ele = ELE_NEUTRAL;
  192. }
  193. if( status->ele_lv < 1 || status->ele_lv > 4 )
  194. {
  195. ShowWarning("Mercenary %d has invalid element level %d (max is 4)\n", db->class_, status->ele_lv);
  196. status->ele_lv = 1;
  197. }
  198. status->speed = atoi(str[22]);
  199. status->adelay = atoi(str[23]);
  200. status->amotion = atoi(str[24]);
  201. status->dmotion = atoi(str[25]);
  202. j++;
  203. }
  204. fclose(fp);
  205. ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' mercenaries in '"CL_WHITE"db/mercenary_db.txt"CL_RESET"'.\n",j);
  206. return 0;
  207. }
  208. int read_mercenary_skilldb(void)
  209. {
  210. FILE *fp;
  211. char line[1024], *p;
  212. char *str[3];
  213. struct s_mercenary_db *db;
  214. int i, j = 0, k = 0, class_;
  215. int skillid, skilllv;
  216. sprintf(line, "%s/%s", db_path, "mercenary_skill_db.txt");
  217. fp = fopen(line, "r");
  218. if( !fp )
  219. {
  220. ShowError("read_mercenary_skilldb : can't read mercenary_skill_db.txt\n");
  221. return -1;
  222. }
  223. while( fgets(line, sizeof(line), fp) )
  224. {
  225. k++;
  226. if( line[0] == '/' && line[1] == '/' )
  227. continue;
  228. i = 0;
  229. p = strtok(line, ",");
  230. while( p != NULL && i < 3 )
  231. {
  232. str[i++] = p;
  233. p = strtok(NULL, ",");
  234. }
  235. if( i < 3 )
  236. {
  237. ShowError("read_mercenary_skilldb : Incorrect number of columns at mercenary_skill_db.txt line %d.\n", k);
  238. continue;
  239. }
  240. class_ = atoi(str[0]);
  241. ARR_FIND(0, MAX_MERCENARY_CLASS, i, class_ == mercenary_db[i].class_);
  242. if( i == MAX_MERCENARY_CLASS )
  243. {
  244. ShowError("read_mercenary_skilldb : Class not found in mercenary_db for skill entry, line %d.\n", k);
  245. continue;
  246. }
  247. skillid = atoi(str[1]);
  248. if( skillid < MC_SKILLBASE || skillid >= MC_SKILLBASE + MAX_MERCSKILL )
  249. {
  250. ShowError("read_mercenary_skilldb : Skill out of range, line %d.\n", k);
  251. continue;
  252. }
  253. db = &mercenary_db[i];
  254. skilllv = atoi(str[2]);
  255. i = skillid - MC_SKILLBASE;
  256. db->skill[i].id = skillid;
  257. db->skill[i].lv = skilllv;
  258. j++;
  259. }
  260. fclose(fp);
  261. ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"db/mercenary_skill_db.txt"CL_RESET"'.\n",j);
  262. return 0;
  263. }
  264. int do_init_mercenary(void)
  265. {
  266. read_mercenarydb();
  267. read_mercenary_skilldb();
  268. //add_timer_func_list(mercenary_contract, "mercenary_contract");
  269. return 0;
  270. }
  271. int do_final_mercenary(void);