PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/map/elemental.c

https://gitlab.com/evol/hercules
C | 1054 lines | 794 code | 186 blank | 74 comment | 196 complexity | ffab9625fec51eff3b6fbce04ab577b3 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0
  1. /**
  2. * This file is part of Hercules.
  3. * http://herc.ws - http://github.com/HerculesWS/Hercules
  4. *
  5. * Copyright (C) 2012-2015 Hercules Dev Team
  6. * Copyright (C) Athena Dev Teams
  7. *
  8. * Hercules is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #define HERCULES_CORE
  22. #include "elemental.h"
  23. #include "map/atcommand.h"
  24. #include "map/battle.h"
  25. #include "map/chrif.h"
  26. #include "map/clif.h"
  27. #include "map/guild.h"
  28. #include "map/intif.h"
  29. #include "map/itemdb.h"
  30. #include "map/log.h"
  31. #include "map/map.h"
  32. #include "map/mob.h"
  33. #include "map/npc.h"
  34. #include "map/party.h"
  35. #include "map/pc.h"
  36. #include "map/pet.h"
  37. #include "map/script.h"
  38. #include "map/skill.h"
  39. #include "map/status.h"
  40. #include "map/trade.h"
  41. #include "map/unit.h"
  42. #include "common/cbasetypes.h"
  43. #include "common/memmgr.h"
  44. #include "common/mmo.h"
  45. #include "common/nullpo.h"
  46. #include "common/random.h"
  47. #include "common/showmsg.h"
  48. #include "common/socket.h"
  49. #include "common/strlib.h"
  50. #include "common/timer.h"
  51. #include "common/utils.h"
  52. #include <math.h>
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56. struct elemental_interface elemental_s;
  57. struct elemental_interface *elemental;
  58. int elemental_search_index(int class_) {
  59. int i;
  60. ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, elemental->db[i].class_ == class_);
  61. return (i == MAX_ELEMENTAL_CLASS)?-1:i;
  62. }
  63. bool elemental_class(int class_) {
  64. return (bool)(elemental->search_index(class_) > -1);
  65. }
  66. struct view_data * elemental_get_viewdata(int class_) {
  67. int i = elemental->search_index(class_);
  68. if( i < 0 )
  69. return 0;
  70. return &elemental->db[i].vd;
  71. }
  72. int elemental_create(struct map_session_data *sd, int class_, unsigned int lifetime) {
  73. struct s_elemental ele;
  74. struct s_elemental_db *db;
  75. int i, summon_level, skill_level;
  76. nullpo_retr(1,sd);
  77. if( (i = elemental->search_index(class_)) < 0 )
  78. return 0;
  79. db = &elemental->db[i];
  80. memset(&ele,0,sizeof(struct s_elemental));
  81. ele.char_id = sd->status.char_id;
  82. ele.class_ = class_;
  83. ele.mode = EL_MODE_PASSIVE; // Initial mode
  84. summon_level = db->status.size+1; // summon level
  85. //[(Caster's Max HP/ 3 ) + (Caster's INT x 10 )+ (Caster's Job Level x 20 )] x [(Elemental Summon Level + 2) / 3]
  86. ele.hp = ele.max_hp = (sd->battle_status.max_hp/3 + sd->battle_status.int_*10 + sd->status.job_level) * ((summon_level + 2) / 3);
  87. //Caster's Max SP /4
  88. ele.sp = ele.max_sp = sd->battle_status.max_sp/4;
  89. //Caster's [ Max SP / (18 / Elemental Summon Skill Level) 1- 100 ]
  90. ele.atk = (sd->battle_status.max_sp / (18 / summon_level) * 1 - 100);
  91. //Caster's [ Max SP / (18 / Elemental Summon Skill Level) ]
  92. ele.atk2 = sd->battle_status.max_sp / 18;
  93. //Caster's HIT + (Caster's Base Level)
  94. ele.hit = sd->battle_status.hit + sd->status.base_level;
  95. //[Elemental Summon Skill Level x (Caster's INT / 2 + Caster's DEX / 4)]
  96. ele.matk = summon_level * (sd->battle_status.int_ / 2 + sd->battle_status.dex / 4);
  97. //150 + [Caster's DEX / 10] + [Elemental Summon Skill Level x 3 ]
  98. ele.amotion = 150 + sd->battle_status.dex / 10 + summon_level * 3;
  99. //Caster's DEF + (Caster's Base Level / (5 - Elemental Summon Skill Level)
  100. ele.def = sd->battle_status.def + sd->status.base_level / (5-summon_level);
  101. //Caster's MDEF + (Caster's INT / (5 - Elemental Summon Skill Level)
  102. ele.mdef = sd->battle_status.mdef + sd->battle_status.int_ / (5-summon_level);
  103. //Caster's FLEE + (Caster's Base Level / (5 - Elemental Summon Skill Level)
  104. ele.flee = sd->status.base_level / (5-summon_level);
  105. //Caster's HIT + (Caster's Base Level)
  106. ele.hit = sd->battle_status.hit + sd->status.base_level;
  107. //per individual bonuses
  108. switch(db->class_){
  109. case ELEID_EL_AGNI_S:
  110. case ELEID_EL_AGNI_M:
  111. case ELEID_EL_AGNI_L:
  112. //ATK + (Summon Agni Skill Level x 20) / HIT + (Summon Agni Skill Level x 10)
  113. ele.atk += summon_level * 20;
  114. ele.atk2 += summon_level * 20;
  115. ele.hit += summon_level * 10;
  116. break;
  117. case ELEID_EL_AQUA_S:
  118. case ELEID_EL_AQUA_M:
  119. case ELEID_EL_AQUA_L:
  120. //MDEF + (Summon Aqua Skill Level x 10) / MATK + (Summon Aqua Skill Level x 20)
  121. ele.mdef += summon_level * 10;
  122. ele.matk += summon_level * 20;
  123. break;
  124. case ELEID_EL_VENTUS_S:
  125. case ELEID_EL_VENTUS_M:
  126. case ELEID_EL_VENTUS_L:
  127. //FLEE + (Summon Ventus Skill Level x 20) / MATK + (Summon Ventus Skill Level x 10)
  128. ele.flee += summon_level * 20;
  129. ele.matk += summon_level * 10;
  130. break;
  131. case ELEID_EL_TERA_S:
  132. case ELEID_EL_TERA_M:
  133. case ELEID_EL_TERA_L:
  134. //DEF + (Summon Tera Skill Level x 25) / ATK + (Summon Tera Skill Level x 5)
  135. ele.def += summon_level * 25;
  136. ele.atk += summon_level * 5;
  137. ele.atk2 += summon_level * 5;
  138. break;
  139. }
  140. if ((skill_level=pc->checkskill(sd,SO_EL_SYMPATHY)) > 0) {
  141. ele.hp = ele.max_hp += ele.max_hp * 5 * skill_level / 100;
  142. ele.sp = ele.max_sp += ele.max_sp * 5 * skill_level / 100;
  143. ele.atk += 25 * skill_level;
  144. ele.atk2 += 25 * skill_level;
  145. ele.matk += 25 * skill_level;
  146. }
  147. ele.life_time = lifetime;
  148. // Request Char Server to create this elemental
  149. intif->elemental_create(&ele);
  150. return 1;
  151. }
  152. int elemental_get_lifetime(struct elemental_data *ed) {
  153. const struct TimerData * td;
  154. if( ed == NULL || ed->summon_timer == INVALID_TIMER )
  155. return 0;
  156. td = timer->get(ed->summon_timer);
  157. return (td != NULL) ? DIFF_TICK32(td->tick, timer->gettick()) : 0;
  158. }
  159. int elemental_save(struct elemental_data *ed) {
  160. nullpo_retr(1, ed);
  161. ed->elemental.mode = ed->battle_status.mode;
  162. ed->elemental.hp = ed->battle_status.hp;
  163. ed->elemental.sp = ed->battle_status.sp;
  164. ed->elemental.max_hp = ed->battle_status.max_hp;
  165. ed->elemental.max_sp = ed->battle_status.max_sp;
  166. ed->elemental.atk = ed->battle_status.rhw.atk;
  167. ed->elemental.atk2 = ed->battle_status.rhw.atk2;
  168. ed->elemental.matk = ed->battle_status.matk_min;
  169. ed->elemental.def = ed->battle_status.def;
  170. ed->elemental.mdef = ed->battle_status.mdef;
  171. ed->elemental.flee = ed->battle_status.flee;
  172. ed->elemental.hit = ed->battle_status.hit;
  173. ed->elemental.life_time = elemental->get_lifetime(ed);
  174. intif->elemental_save(&ed->elemental);
  175. return 1;
  176. }
  177. int elemental_summon_end_timer(int tid, int64 tick, int id, intptr_t data) {
  178. struct map_session_data *sd;
  179. struct elemental_data *ed;
  180. if( (sd = map->id2sd(id)) == NULL )
  181. return 1;
  182. if( (ed = sd->ed) == NULL )
  183. return 1;
  184. if( ed->summon_timer != tid ) {
  185. ShowError("elemental_summon_end_timer %d != %d.\n", ed->summon_timer, tid);
  186. return 0;
  187. }
  188. ed->summon_timer = INVALID_TIMER;
  189. elemental->delete(ed, 0); // Elemental's summon time is over.
  190. return 0;
  191. }
  192. void elemental_summon_stop(struct elemental_data *ed) {
  193. nullpo_retv(ed);
  194. if( ed->summon_timer != INVALID_TIMER )
  195. timer->delete(ed->summon_timer, elemental->summon_end_timer);
  196. ed->summon_timer = INVALID_TIMER;
  197. }
  198. int elemental_delete(struct elemental_data *ed, int reply) {
  199. struct map_session_data *sd;
  200. nullpo_ret(ed);
  201. sd = ed->master;
  202. ed->elemental.life_time = 0;
  203. elemental->clean_effect(ed);
  204. elemental->summon_stop(ed);
  205. if( !sd )
  206. return unit->free(&ed->bl, 0);
  207. sd->ed = NULL;
  208. sd->status.ele_id = 0;
  209. if( !ed->bl.prev )
  210. return unit->free(&ed->bl, 0);
  211. return unit->remove_map(&ed->bl, 0, ALC_MARK);
  212. }
  213. void elemental_summon_init(struct elemental_data *ed) {
  214. nullpo_retv(ed);
  215. if (ed->summon_timer == INVALID_TIMER)
  216. ed->summon_timer = timer->add(timer->gettick() + ed->elemental.life_time, elemental->summon_end_timer, ed->master->bl.id, 0);
  217. ed->regen.state.block = 0;
  218. }
  219. int elemental_data_received(struct s_elemental *ele, bool flag) {
  220. struct map_session_data *sd;
  221. struct elemental_data *ed;
  222. struct s_elemental_db *db;
  223. int i;
  224. nullpo_ret(ele);
  225. i = elemental->search_index(ele->class_);
  226. if( (sd = map->charid2sd(ele->char_id)) == NULL )
  227. return 0;
  228. if( !flag || i < 0 ) { // Not created - loaded - DB info
  229. sd->status.ele_id = 0;
  230. return 0;
  231. }
  232. db = &elemental->db[i];
  233. if( !sd->ed ) {
  234. // Initialize it after first summon.
  235. CREATE(ed, struct elemental_data, 1);
  236. ed->bl.type = BL_ELEM;
  237. ed->bl.id = npc->get_new_npc_id();
  238. sd->ed = ed;
  239. ed->master = sd;
  240. ed->db = db;
  241. memcpy(&ed->elemental, ele, sizeof(struct s_elemental));
  242. status->set_viewdata(&ed->bl, ed->elemental.class_);
  243. ed->vd->head_mid = 10; // Why?
  244. status->change_init(&ed->bl);
  245. unit->dataset(&ed->bl);
  246. ed->ud.dir = sd->ud.dir;
  247. ed->bl.m = sd->bl.m;
  248. ed->bl.x = sd->bl.x;
  249. ed->bl.y = sd->bl.y;
  250. unit->calc_pos(&ed->bl, sd->bl.x, sd->bl.y, sd->ud.dir);
  251. ed->bl.x = ed->ud.to_x;
  252. ed->bl.y = ed->ud.to_y;
  253. map->addiddb(&ed->bl);
  254. status_calc_elemental(ed,SCO_FIRST);
  255. ed->last_spdrain_time = ed->last_thinktime = timer->gettick();
  256. ed->summon_timer = INVALID_TIMER;
  257. elemental->summon_init(ed);
  258. } else {
  259. memcpy(&sd->ed->elemental, ele, sizeof(struct s_elemental));
  260. ed = sd->ed;
  261. }
  262. sd->status.ele_id = ele->elemental_id;
  263. if( ed->bl.prev == NULL && sd->bl.prev != NULL ) {
  264. map->addblock(&ed->bl);
  265. clif->spawn(&ed->bl);
  266. clif->elemental_info(sd);
  267. clif->elemental_updatestatus(sd,SP_HP);
  268. clif->hpmeter_single(sd->fd,ed->bl.id,ed->battle_status.hp,ed->battle_status.max_hp);
  269. clif->elemental_updatestatus(sd,SP_SP);
  270. }
  271. return 1;
  272. }
  273. int elemental_clean_single_effect(struct elemental_data *ed, uint16 skill_id) {
  274. struct block_list *bl;
  275. sc_type type = status->skill2sc(skill_id);
  276. nullpo_ret(ed);
  277. bl = battle->get_master(&ed->bl);
  278. if( type ) {
  279. switch( type ) {
  280. // Just remove status change.
  281. case SC_PYROTECHNIC_OPTION:
  282. case SC_HEATER_OPTION:
  283. case SC_TROPIC_OPTION:
  284. case SC_FIRE_CLOAK_OPTION:
  285. case SC_AQUAPLAY_OPTION:
  286. case SC_WATER_SCREEN_OPTION:
  287. case SC_COOLER_OPTION:
  288. case SC_CHILLY_AIR_OPTION:
  289. case SC_GUST_OPTION:
  290. case SC_WIND_STEP_OPTION:
  291. case SC_BLAST_OPTION:
  292. case SC_WATER_DROP_OPTION:
  293. case SC_WIND_CURTAIN_OPTION:
  294. case SC_WILD_STORM_OPTION:
  295. case SC_PETROLOGY_OPTION:
  296. case SC_SOLID_SKIN_OPTION:
  297. case SC_CURSED_SOIL_OPTION:
  298. case SC_STONE_SHIELD_OPTION:
  299. case SC_UPHEAVAL_OPTION:
  300. case SC_CIRCLE_OF_FIRE_OPTION:
  301. case SC_TIDAL_WEAPON_OPTION:
  302. if( bl ) status_change_end(bl,type,INVALID_TIMER); // Master
  303. status_change_end(&ed->bl,type-1,INVALID_TIMER); // Elemental Spirit
  304. break;
  305. case SC_ZEPHYR:
  306. if( bl ) status_change_end(bl,type,INVALID_TIMER);
  307. break;
  308. default:
  309. ShowWarning("Invalid SC=%d in elemental_clean_single_effect\n",type);
  310. break;
  311. }
  312. }
  313. return 1;
  314. }
  315. int elemental_clean_effect(struct elemental_data *ed) {
  316. struct map_session_data *sd;
  317. nullpo_ret(ed);
  318. // Elemental side
  319. status_change_end(&ed->bl, SC_TROPIC, INVALID_TIMER);
  320. status_change_end(&ed->bl, SC_HEATER, INVALID_TIMER);
  321. status_change_end(&ed->bl, SC_AQUAPLAY, INVALID_TIMER);
  322. status_change_end(&ed->bl, SC_COOLER, INVALID_TIMER);
  323. status_change_end(&ed->bl, SC_CHILLY_AIR, INVALID_TIMER);
  324. status_change_end(&ed->bl, SC_PYROTECHNIC, INVALID_TIMER);
  325. status_change_end(&ed->bl, SC_FIRE_CLOAK, INVALID_TIMER);
  326. status_change_end(&ed->bl, SC_WATER_DROP, INVALID_TIMER);
  327. status_change_end(&ed->bl, SC_WATER_SCREEN, INVALID_TIMER);
  328. status_change_end(&ed->bl, SC_GUST, INVALID_TIMER);
  329. status_change_end(&ed->bl, SC_WIND_STEP, INVALID_TIMER);
  330. status_change_end(&ed->bl, SC_BLAST, INVALID_TIMER);
  331. status_change_end(&ed->bl, SC_WIND_CURTAIN, INVALID_TIMER);
  332. status_change_end(&ed->bl, SC_WILD_STORM, INVALID_TIMER);
  333. status_change_end(&ed->bl, SC_PETROLOGY, INVALID_TIMER);
  334. status_change_end(&ed->bl, SC_SOLID_SKIN, INVALID_TIMER);
  335. status_change_end(&ed->bl, SC_CURSED_SOIL, INVALID_TIMER);
  336. status_change_end(&ed->bl, SC_STONE_SHIELD, INVALID_TIMER);
  337. status_change_end(&ed->bl, SC_UPHEAVAL, INVALID_TIMER);
  338. status_change_end(&ed->bl, SC_CIRCLE_OF_FIRE, INVALID_TIMER);
  339. status_change_end(&ed->bl, SC_TIDAL_WEAPON, INVALID_TIMER);
  340. if( (sd = ed->master) == NULL )
  341. return 0;
  342. // Master side
  343. status_change_end(&sd->bl, SC_TROPIC_OPTION, INVALID_TIMER);
  344. status_change_end(&sd->bl, SC_HEATER_OPTION, INVALID_TIMER);
  345. status_change_end(&sd->bl, SC_AQUAPLAY_OPTION, INVALID_TIMER);
  346. status_change_end(&sd->bl, SC_COOLER_OPTION, INVALID_TIMER);
  347. status_change_end(&sd->bl, SC_CHILLY_AIR_OPTION, INVALID_TIMER);
  348. status_change_end(&sd->bl, SC_PYROTECHNIC_OPTION, INVALID_TIMER);
  349. status_change_end(&sd->bl, SC_FIRE_CLOAK_OPTION, INVALID_TIMER);
  350. status_change_end(&sd->bl, SC_WATER_DROP_OPTION, INVALID_TIMER);
  351. status_change_end(&sd->bl, SC_WATER_SCREEN_OPTION, INVALID_TIMER);
  352. status_change_end(&sd->bl, SC_GUST_OPTION, INVALID_TIMER);
  353. status_change_end(&sd->bl, SC_WIND_STEP_OPTION, INVALID_TIMER);
  354. status_change_end(&sd->bl, SC_BLAST_OPTION, INVALID_TIMER);
  355. status_change_end(&sd->bl, SC_WATER_DROP_OPTION, INVALID_TIMER);
  356. status_change_end(&sd->bl, SC_WIND_CURTAIN_OPTION, INVALID_TIMER);
  357. status_change_end(&sd->bl, SC_WILD_STORM_OPTION, INVALID_TIMER);
  358. status_change_end(&sd->bl, SC_ZEPHYR, INVALID_TIMER);
  359. status_change_end(&sd->bl, SC_WIND_STEP_OPTION, INVALID_TIMER);
  360. status_change_end(&sd->bl, SC_PETROLOGY_OPTION, INVALID_TIMER);
  361. status_change_end(&sd->bl, SC_SOLID_SKIN_OPTION, INVALID_TIMER);
  362. status_change_end(&sd->bl, SC_CURSED_SOIL_OPTION, INVALID_TIMER);
  363. status_change_end(&sd->bl, SC_STONE_SHIELD_OPTION, INVALID_TIMER);
  364. status_change_end(&sd->bl, SC_UPHEAVAL_OPTION, INVALID_TIMER);
  365. status_change_end(&sd->bl, SC_CIRCLE_OF_FIRE_OPTION, INVALID_TIMER);
  366. status_change_end(&sd->bl, SC_TIDAL_WEAPON_OPTION, INVALID_TIMER);
  367. return 1;
  368. }
  369. int elemental_action(struct elemental_data *ed, struct block_list *bl, int64 tick) {
  370. struct skill_condition req;
  371. uint16 skill_id, skill_lv;
  372. int i;
  373. nullpo_ret(ed);
  374. nullpo_ret(bl);
  375. if( !ed->master )
  376. return 0;
  377. if( ed->target_id )
  378. elemental->unlocktarget(ed); // Remove previous target.
  379. ARR_FIND(0, MAX_ELESKILLTREE, i, ed->db->skill[i].id && (ed->db->skill[i].mode&EL_SKILLMODE_AGGRESSIVE));
  380. if( i == MAX_ELESKILLTREE )
  381. return 0;
  382. skill_id = ed->db->skill[i].id;
  383. skill_lv = ed->db->skill[i].lv;
  384. if( elemental->skillnotok(skill_id, ed) )
  385. return 0;
  386. if( ed->ud.skilltimer != INVALID_TIMER )
  387. return 0;
  388. else if( DIFF_TICK(tick, ed->ud.canact_tick) < 0 )
  389. return 0;
  390. ed->target_id = ed->ud.skilltarget = bl->id; // Set new target
  391. ed->last_thinktime = tick;
  392. // Not in skill range.
  393. if( !battle->check_range(&ed->bl,bl,skill->get_range(skill_id,skill_lv)) ) {
  394. // Try to walk to the target.
  395. if( !unit->walktobl(&ed->bl, bl, skill->get_range(skill_id,skill_lv), 2) )
  396. elemental->unlocktarget(ed);
  397. else {
  398. // Walking, waiting to be in range. Client don't handle it, then we must handle it here.
  399. int walk_dist = distance_bl(&ed->bl,bl) - skill->get_range(skill_id,skill_lv);
  400. ed->ud.skill_id = skill_id;
  401. ed->ud.skill_lv = skill_lv;
  402. if( skill->get_inf(skill_id) & INF_GROUND_SKILL )
  403. ed->ud.skilltimer = timer->add(tick+(int64)status->get_speed(&ed->bl)*walk_dist, skill->castend_pos, ed->bl.id, 0);
  404. else
  405. ed->ud.skilltimer = timer->add(tick+(int64)status->get_speed(&ed->bl)*walk_dist, skill->castend_id, ed->bl.id, 0);
  406. }
  407. return 1;
  408. }
  409. req = elemental->skill_get_requirements(skill_id, skill_lv);
  410. if(req.hp || req.sp){
  411. struct map_session_data *sd = BL_CAST(BL_PC, battle->get_master(&ed->bl));
  412. if( sd ){
  413. if( sd->skill_id_old != SO_EL_ACTION && //regardless of remaining HP/SP it can be cast
  414. (status_get_hp(&ed->bl) < req.hp || status_get_sp(&ed->bl) < req.sp) )
  415. return 1;
  416. else
  417. status_zap(&ed->bl, req.hp, req.sp);
  418. }
  419. }
  420. //Otherwise, just cast the skill.
  421. if( skill->get_inf(skill_id) & INF_GROUND_SKILL )
  422. unit->skilluse_pos(&ed->bl, bl->x, bl->y, skill_id, skill_lv);
  423. else
  424. unit->skilluse_id(&ed->bl, bl->id, skill_id, skill_lv);
  425. // Reset target.
  426. ed->target_id = 0;
  427. return 1;
  428. }
  429. /*===============================================================
  430. * Action that elemental perform after changing mode.
  431. * Activates one of the skills of the new mode.
  432. *-------------------------------------------------------------*/
  433. int elemental_change_mode_ack(struct elemental_data *ed, int mode) {
  434. struct block_list *bl = &ed->master->bl;
  435. uint16 skill_id, skill_lv;
  436. int i;
  437. nullpo_ret(ed);
  438. if( !bl )
  439. return 0;
  440. // Select a skill.
  441. ARR_FIND(0, MAX_ELESKILLTREE, i, ed->db->skill[i].id && (ed->db->skill[i].mode&mode));
  442. if( i == MAX_ELESKILLTREE )
  443. return 0;
  444. skill_id = ed->db->skill[i].id;
  445. skill_lv = ed->db->skill[i].lv;
  446. if( elemental->skillnotok(skill_id, ed) )
  447. return 0;
  448. if( ed->ud.skilltimer != INVALID_TIMER )
  449. return 0;
  450. else if( DIFF_TICK(timer->gettick(), ed->ud.canact_tick) < 0 )
  451. return 0;
  452. ed->target_id = bl->id; // Set new target
  453. ed->last_thinktime = timer->gettick();
  454. if( skill->get_inf(skill_id) & INF_GROUND_SKILL )
  455. unit->skilluse_pos(&ed->bl, bl->x, bl->y, skill_id, skill_lv);
  456. else
  457. unit->skilluse_id(&ed->bl,bl->id,skill_id,skill_lv);
  458. ed->target_id = 0; // Reset target after casting the skill to avoid continuous attack.
  459. return 1;
  460. }
  461. /*===============================================================
  462. * Change elemental mode.
  463. *-------------------------------------------------------------*/
  464. int elemental_change_mode(struct elemental_data *ed, int mode) {
  465. nullpo_ret(ed);
  466. // Remove target
  467. elemental->unlocktarget(ed);
  468. // Removes the effects of the previous mode.
  469. if(ed->elemental.mode != mode ) elemental->clean_effect(ed);
  470. ed->battle_status.mode = ed->elemental.mode = mode;
  471. // Normalize elemental mode to elemental skill mode.
  472. if( mode == EL_MODE_AGGRESSIVE ) mode = EL_SKILLMODE_AGGRESSIVE; // Aggressive spirit mode -> Aggressive spirit skill.
  473. else if( mode == EL_MODE_ASSIST ) mode = EL_SKILLMODE_ASSIST; // Assist spirit mode -> Assist spirit skill.
  474. else mode = EL_SKILLMODE_PASIVE; // Passive spirit mode -> Passive spirit skill.
  475. // Use a skill immediately after every change mode.
  476. if( mode != EL_SKILLMODE_AGGRESSIVE )
  477. elemental->change_mode_ack(ed,mode);
  478. return 1;
  479. }
  480. void elemental_heal(struct elemental_data *ed, int hp, int sp) {
  481. nullpo_retv(ed);
  482. if( hp )
  483. clif->elemental_updatestatus(ed->master, SP_HP);
  484. if( sp )
  485. clif->elemental_updatestatus(ed->master, SP_SP);
  486. }
  487. int elemental_dead(struct elemental_data *ed) {
  488. elemental->delete(ed, 1);
  489. return 0;
  490. }
  491. int elemental_unlocktarget(struct elemental_data *ed) {
  492. nullpo_ret(ed);
  493. ed->target_id = 0;
  494. elemental_stop_attack(ed);
  495. elemental_stop_walking(ed, STOPWALKING_FLAG_FIXPOS);
  496. return 0;
  497. }
  498. int elemental_skillnotok(uint16 skill_id, struct elemental_data *ed) {
  499. int idx = skill->get_index(skill_id);
  500. nullpo_retr(1,ed);
  501. if (idx == 0)
  502. return 1; // invalid skill id
  503. return skill->not_ok(skill_id, ed->master);
  504. }
  505. struct skill_condition elemental_skill_get_requirements(uint16 skill_id, uint16 skill_lv){
  506. struct skill_condition req;
  507. int idx = skill->get_index(skill_id);
  508. memset(&req,0,sizeof(req));
  509. if( idx == 0 ) // invalid skill id
  510. return req;
  511. if( skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL )
  512. return req;
  513. req.hp = skill->dbs->db[idx].hp[skill_lv-1];
  514. req.sp = skill->dbs->db[idx].sp[skill_lv-1];
  515. return req;
  516. }
  517. int elemental_set_target( struct map_session_data *sd, struct block_list *bl ) {
  518. struct elemental_data *ed;
  519. nullpo_ret(sd);
  520. ed = sd->ed;
  521. nullpo_ret(ed);
  522. nullpo_ret(bl);
  523. if( ed->bl.m != bl->m || !check_distance_bl(&ed->bl, bl, ed->db->range2) )
  524. return 0;
  525. if( !status->check_skilluse(&ed->bl, bl, 0, 0) )
  526. return 0;
  527. if( ed->target_id == 0 )
  528. ed->target_id = bl->id;
  529. return 1;
  530. }
  531. int elemental_ai_sub_timer_activesearch(struct block_list *bl, va_list ap) {
  532. struct elemental_data *ed;
  533. struct block_list **target;
  534. int dist;
  535. nullpo_ret(bl);
  536. ed = va_arg(ap,struct elemental_data *);
  537. nullpo_ret(ed);
  538. target = va_arg(ap,struct block_list**);
  539. nullpo_ret(target);
  540. //If can't seek yet, not an enemy, or you can't attack it, skip.
  541. if( (*target) == bl || !status->check_skilluse(&ed->bl, bl, 0, 0) )
  542. return 0;
  543. if( battle->check_target(&ed->bl,bl,BCT_ENEMY) <= 0 )
  544. return 0;
  545. switch( bl->type ) {
  546. case BL_PC:
  547. if( !map_flag_vs(ed->bl.m) )
  548. return 0;
  549. /* Fall through */
  550. default:
  551. dist = distance_bl(&ed->bl, bl);
  552. if( ((*target) == NULL || !check_distance_bl(&ed->bl, *target, dist)) && battle->check_range(&ed->bl,bl,ed->db->range2) ) { //Pick closest target?
  553. (*target) = bl;
  554. ed->target_id = bl->id;
  555. ed->min_chase = dist + ed->db->range3;
  556. if( ed->min_chase > AREA_SIZE )
  557. ed->min_chase = AREA_SIZE;
  558. return 1;
  559. }
  560. break;
  561. }
  562. return 0;
  563. }
  564. int elemental_ai_sub_timer(struct elemental_data *ed, struct map_session_data *sd, int64 tick) {
  565. struct block_list *target = NULL;
  566. int master_dist, view_range, mode;
  567. nullpo_ret(ed);
  568. nullpo_ret(sd);
  569. if( ed->bl.prev == NULL || sd == NULL || sd->bl.prev == NULL )
  570. return 0;
  571. // Check if caster can sustain the summoned elemental
  572. if( DIFF_TICK(tick,ed->last_spdrain_time) >= 10000 ){// Drain SP every 10 seconds
  573. int sp = 5;
  574. switch (ed->vd->class_) {
  575. case ELEID_EL_AGNI_M:
  576. case ELEID_EL_AQUA_M:
  577. case ELEID_EL_VENTUS_M:
  578. case ELEID_EL_TERA_M:
  579. sp = 8;
  580. break;
  581. case ELEID_EL_AGNI_L:
  582. case ELEID_EL_AQUA_L:
  583. case ELEID_EL_VENTUS_L:
  584. case ELEID_EL_TERA_L:
  585. sp = 11;
  586. break;
  587. }
  588. if( status_get_sp(&sd->bl) < sp ){ // Can't sustain delete it.
  589. elemental->delete(sd->ed,0);
  590. return 0;
  591. }
  592. status_zap(&sd->bl,0,sp);
  593. ed->last_spdrain_time = tick;
  594. }
  595. if( DIFF_TICK(tick,ed->last_thinktime) < MIN_ELETHINKTIME )
  596. return 0;
  597. ed->last_thinktime = tick;
  598. if( ed->ud.skilltimer != INVALID_TIMER )
  599. return 0;
  600. if( ed->ud.walktimer != INVALID_TIMER && ed->ud.walkpath.path_pos <= 2 )
  601. return 0; //No thinking when you just started to walk.
  602. if(ed->ud.walkpath.path_pos < ed->ud.walkpath.path_len && ed->ud.target == sd->bl.id)
  603. return 0; //No thinking until be near the master.
  604. if( ed->sc.count && ed->sc.data[SC_BLIND] )
  605. view_range = 3;
  606. else
  607. view_range = ed->db->range2;
  608. mode = status_get_mode(&ed->bl);
  609. master_dist = distance_bl(&sd->bl, &ed->bl);
  610. if( master_dist > AREA_SIZE ) {
  611. // Master out of vision range.
  612. elemental->unlocktarget(ed);
  613. unit->warp(&ed->bl,sd->bl.m,sd->bl.x,sd->bl.y,CLR_TELEPORT);
  614. clif->elemental_updatestatus(sd,SP_HP);
  615. clif->elemental_updatestatus(sd,SP_SP);
  616. return 0;
  617. } else if( master_dist > MAX_ELEDISTANCE ) {
  618. // Master too far, chase.
  619. short x = sd->bl.x, y = sd->bl.y;
  620. if( ed->target_id )
  621. elemental->unlocktarget(ed);
  622. if( ed->ud.walktimer != INVALID_TIMER && ed->ud.target == sd->bl.id )
  623. return 0; //Already walking to him
  624. if( DIFF_TICK(tick, ed->ud.canmove_tick) < 0 )
  625. return 0; //Can't move yet.
  626. if( map->search_freecell(&ed->bl, sd->bl.m, &x, &y, MIN_ELEDISTANCE, MIN_ELEDISTANCE, 1)
  627. && unit->walktoxy(&ed->bl, x, y, 0) )
  628. return 0;
  629. }
  630. if( mode == EL_MODE_AGGRESSIVE ) {
  631. target = map->id2bl(ed->ud.target);
  632. if( !target )
  633. map->foreachinrange(elemental->ai_sub_timer_activesearch, &ed->bl, view_range, BL_CHAR, ed, &target, status_get_mode(&ed->bl));
  634. if( !target ) { //No targets available.
  635. elemental->unlocktarget(ed);
  636. return 1;
  637. }
  638. if( battle->check_range(&ed->bl,target,view_range) && rnd()%100 < 2 ) { // 2% chance to cast attack skill.
  639. if( elemental->action(ed,target,tick) )
  640. return 1;
  641. }
  642. //Attempt to attack.
  643. //At this point we know the target is attackable, we just gotta check if the range matches.
  644. if( ed->ud.target == target->id && ed->ud.attacktimer != INVALID_TIMER ) //Already locked.
  645. return 1;
  646. if( battle->check_range(&ed->bl, target, ed->base_status.rhw.range) ) {//Target within range, engage
  647. unit->attack(&ed->bl,target->id,1);
  648. return 1;
  649. }
  650. //Follow up if possible.
  651. if( !unit->walktobl(&ed->bl, target, ed->base_status.rhw.range, 2) )
  652. elemental->unlocktarget(ed);
  653. }
  654. return 0;
  655. }
  656. int elemental_ai_sub_foreachclient(struct map_session_data *sd, va_list ap) {
  657. int64 tick = va_arg(ap,int64);
  658. nullpo_ret(sd);
  659. if(sd->status.ele_id && sd->ed)
  660. elemental->ai_sub_timer(sd->ed,sd,tick);
  661. return 0;
  662. }
  663. int elemental_ai_timer(int tid, int64 tick, int id, intptr_t data) {
  664. map->foreachpc(elemental->ai_sub_foreachclient,tick);
  665. return 0;
  666. }
  667. int read_elementaldb(void) {
  668. FILE *fp;
  669. char line[1024], *p;
  670. char *str[26];
  671. int i, j = 0, k = 0, ele;
  672. struct s_elemental_db *db;
  673. struct status_data *estatus;
  674. sprintf(line, "%s/%s", map->db_path, "elemental_db.txt");
  675. if( core->runflag == MAPSERVER_ST_RUNNING ) //only necessary after we're up
  676. memset(elemental->db,0,sizeof(elemental->db));
  677. fp = fopen(line, "r");
  678. if( !fp ) {
  679. ShowError("read_elementaldb : can't read elemental_db.txt\n");
  680. return -1;
  681. }
  682. while( fgets(line, sizeof(line), fp) && j < MAX_ELEMENTAL_CLASS ) {
  683. k++;
  684. if( line[0] == '/' && line[1] == '/' )
  685. continue;
  686. if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r')
  687. continue;
  688. i = 0;
  689. p = strtok(line, ",");
  690. while( p != NULL && i < 26 ) {
  691. str[i++] = p;
  692. p = strtok(NULL, ",");
  693. }
  694. if( i < 26 ) {
  695. ShowError("read_elementaldb : Incorrect number of columns at elemental_db.txt line %d.\n", k);
  696. continue;
  697. }
  698. db = &elemental->db[j];
  699. db->class_ = atoi(str[0]);
  700. safestrncpy(db->sprite, str[1], NAME_LENGTH);
  701. safestrncpy(db->name, str[2], NAME_LENGTH);
  702. db->lv = atoi(str[3]);
  703. estatus = &db->status;
  704. db->vd.class_ = db->class_;
  705. estatus->max_hp = atoi(str[4]);
  706. estatus->max_sp = atoi(str[5]);
  707. estatus->rhw.range = atoi(str[6]);
  708. estatus->rhw.atk = atoi(str[7]);
  709. estatus->rhw.atk2 = atoi(str[8]);
  710. estatus->def = atoi(str[9]);
  711. estatus->mdef = atoi(str[10]);
  712. estatus->str = atoi(str[11]);
  713. estatus->agi = atoi(str[12]);
  714. estatus->vit = atoi(str[13]);
  715. estatus->int_ = atoi(str[14]);
  716. estatus->dex = atoi(str[15]);
  717. estatus->luk = atoi(str[16]);
  718. db->range2 = atoi(str[17]);
  719. db->range3 = atoi(str[18]);
  720. estatus->size = atoi(str[19]);
  721. estatus->race = atoi(str[20]);
  722. ele = atoi(str[21]);
  723. estatus->def_ele = ele%10;
  724. estatus->ele_lv = ele/20;
  725. if( estatus->def_ele >= ELE_MAX ) {
  726. ShowWarning("Elemental %d has invalid element type %d (max element is %d)\n", db->class_, estatus->def_ele, ELE_MAX - 1);
  727. estatus->def_ele = ELE_NEUTRAL;
  728. }
  729. if( estatus->ele_lv < 1 || estatus->ele_lv > 4 ) {
  730. ShowWarning("Elemental %d has invalid element level %d (max is 4)\n", db->class_, estatus->ele_lv);
  731. estatus->ele_lv = 1;
  732. }
  733. estatus->aspd_rate = 1000;
  734. estatus->speed = atoi(str[22]);
  735. estatus->adelay = atoi(str[23]);
  736. estatus->amotion = atoi(str[24]);
  737. estatus->dmotion = atoi(str[25]);
  738. j++;
  739. }
  740. fclose(fp);
  741. ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' elementals in '"CL_WHITE"db/elemental_db.txt"CL_RESET"'.\n",j);
  742. return 0;
  743. }
  744. int read_elemental_skilldb(void) {
  745. FILE *fp;
  746. char line[1024], *p;
  747. char *str[4];
  748. struct s_elemental_db *db;
  749. int i, j = 0, k = 0, class_;
  750. uint16 skill_id, skill_lv;
  751. int skillmode;
  752. sprintf(line, "%s/%s", map->db_path, "elemental_skill_db.txt");
  753. fp = fopen(line, "r");
  754. if( !fp ) {
  755. ShowError("read_elemental_skilldb : can't read elemental_skill_db.txt\n");
  756. return -1;
  757. }
  758. while( fgets(line, sizeof(line), fp) ) {
  759. k++;
  760. if( line[0] == '/' && line[1] == '/' )
  761. continue;
  762. if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r')
  763. continue;
  764. i = 0;
  765. p = strtok(line, ",");
  766. while( p != NULL && i < 4 ) {
  767. str[i++] = p;
  768. p = strtok(NULL, ",");
  769. }
  770. if( i < 4 ) {
  771. ShowError("read_elemental_skilldb : Incorrect number of columns at elemental_skill_db.txt line %d.\n", k);
  772. continue;
  773. }
  774. class_ = atoi(str[0]);
  775. ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, class_ == elemental->db[i].class_);
  776. if( i == MAX_ELEMENTAL_CLASS ) {
  777. ShowError("read_elemental_skilldb : Class not found in elemental_db for skill entry, line %d.\n", k);
  778. continue;
  779. }
  780. skill_id = atoi(str[1]);
  781. if( skill_id < EL_SKILLBASE || skill_id >= EL_SKILLBASE + MAX_ELEMENTALSKILL ) {
  782. ShowError("read_elemental_skilldb : Skill out of range, line %d.\n", k);
  783. continue;
  784. }
  785. db = &elemental->db[i];
  786. skill_lv = atoi(str[2]);
  787. skillmode = atoi(str[3]);
  788. if( skillmode < EL_SKILLMODE_PASIVE || skillmode > EL_SKILLMODE_AGGRESSIVE ) {
  789. ShowError("read_elemental_skilldb : Skillmode out of range, line %d.\n",k);
  790. continue;
  791. }
  792. ARR_FIND( 0, MAX_ELESKILLTREE, i, db->skill[i].id == 0 || db->skill[i].id == skill_id );
  793. if( i == MAX_ELESKILLTREE ) {
  794. ShowWarning("Unable to load skill %d into Elemental %d's tree. Maximum number of skills per elemental has been reached.\n", skill_id, class_);
  795. continue;
  796. }
  797. db->skill[i].id = skill_id;
  798. db->skill[i].lv = skill_lv;
  799. db->skill[i].mode = skillmode;
  800. j++;
  801. }
  802. fclose(fp);
  803. ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"db/elemental_skill_db.txt"CL_RESET"'.\n",j);
  804. return 0;
  805. }
  806. void reload_elementaldb(void) {
  807. elemental->read_db();
  808. elemental->reload_skilldb();
  809. }
  810. void reload_elemental_skilldb(void) {
  811. elemental->read_skilldb();
  812. }
  813. int do_init_elemental(bool minimal) {
  814. if (minimal)
  815. return 0;
  816. elemental->read_db();
  817. elemental->read_skilldb();
  818. timer->add_func_list(elemental->ai_timer,"elemental_ai_timer");
  819. timer->add_interval(timer->gettick()+MIN_ELETHINKTIME,elemental->ai_timer,0,0,MIN_ELETHINKTIME);
  820. return 0;
  821. }
  822. void do_final_elemental(void) {
  823. return;
  824. }
  825. /*=====================================
  826. * Default Functions : elemental.h
  827. * Generated by HerculesInterfaceMaker
  828. * created by Susu
  829. *-------------------------------------*/
  830. void elemental_defaults(void) {
  831. elemental = &elemental_s;
  832. /* */
  833. elemental->init = do_init_elemental;
  834. elemental->final = do_final_elemental;
  835. /* */
  836. memset(elemental->db,0,sizeof(elemental->db));
  837. /* funcs */
  838. elemental->class = elemental_class;
  839. elemental->get_viewdata = elemental_get_viewdata;
  840. elemental->create = elemental_create;
  841. elemental->data_received = elemental_data_received;
  842. elemental->save = elemental_save;
  843. elemental->change_mode_ack = elemental_change_mode_ack;
  844. elemental->change_mode = elemental_change_mode;
  845. elemental->heal = elemental_heal;
  846. elemental->dead = elemental_dead;
  847. elemental->delete = elemental_delete;
  848. elemental->summon_stop = elemental_summon_stop;
  849. elemental->get_lifetime = elemental_get_lifetime;
  850. elemental->unlocktarget = elemental_unlocktarget;
  851. elemental->skillnotok = elemental_skillnotok;
  852. elemental->set_target = elemental_set_target;
  853. elemental->clean_single_effect = elemental_clean_single_effect;
  854. elemental->clean_effect = elemental_clean_effect;
  855. elemental->action = elemental_action;
  856. elemental->skill_get_requirements = elemental_skill_get_requirements;
  857. elemental->read_skilldb = read_elemental_skilldb;
  858. elemental->reload_db = reload_elementaldb;
  859. elemental->reload_skilldb = reload_elemental_skilldb;
  860. elemental->search_index = elemental_search_index;
  861. elemental->summon_init = elemental_summon_init;
  862. elemental->summon_end_timer = elemental_summon_end_timer;
  863. elemental->ai_sub_timer_activesearch = elemental_ai_sub_timer_activesearch;
  864. elemental->ai_sub_timer = elemental_ai_sub_timer;
  865. elemental->ai_sub_foreachclient = elemental_ai_sub_foreachclient;
  866. elemental->ai_timer = elemental_ai_timer;
  867. elemental->read_db = read_elementaldb;
  868. }