int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned int tick) { struct skill_condition req; uint16 skill_id, skill_lv; int i; nullpo_ret(ed); nullpo_ret(bl); if( !ed->master ) return 0; if( ed->target_id ) elemental_unlocktarget(ed); // Remove previous target. ARR_FIND(0, MAX_ELESKILLTREE, i, ed->db->skill[i].id && (ed->db->skill[i].mode&EL_SKILLMODE_AGGRESSIVE)); if( i == MAX_ELESKILLTREE ) return 0; skill_id = ed->db->skill[i].id; skill_lv = ed->db->skill[i].lv; if( elemental_skillnotok(skill_id, ed) ) return 0; if( ed->ud.skilltimer != INVALID_TIMER ) return 0; else if( DIFF_TICK(tick, ed->ud.canact_tick) < 0 ) return 0; ed->target_id = ed->ud.skilltarget = bl->id; // Set new target ed->last_thinktime = tick; // Not in skill range. if( !battle_check_range(&ed->bl,bl,skill_get_range(skill_id,skill_lv)) ) { // Try to walk to the target. if( !unit_walktobl(&ed->bl, bl, skill_get_range(skill_id,skill_lv), 2) ) elemental_unlocktarget(ed); else { // Walking, waiting to be in range. Client don't handle it, then we must handle it here. int walk_dist = distance_bl(&ed->bl,bl) - skill_get_range(skill_id,skill_lv); ed->ud.skill_id = skill_id; ed->ud.skill_lv = skill_lv; if( skill_get_inf(skill_id) & INF_GROUND_SKILL ) ed->ud.skilltimer = add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill_castend_pos, ed->bl.id, 0 ); else ed->ud.skilltimer = add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill_castend_id, ed->bl.id, 0 ); } return 1; } req = elemental_skill_get_requirements(skill_id, skill_lv); if(req.hp || req.sp){ struct map_session_data *sd = BL_CAST(BL_PC, battle_get_master(&ed->bl)); if( sd ){ if( sd->skill_id_old != SO_EL_ACTION && //regardless of remaining HP/SP it can be cast (status_get_hp(&ed->bl) < req.hp || status_get_sp(&ed->bl) < req.sp) ) return 1; else status_zap(&ed->bl, req.hp, req.sp); } } //Otherwise, just cast the skill. if( skill_get_inf(skill_id) & INF_GROUND_SKILL ) unit_skilluse_pos(&ed->bl, bl->x, bl->y, skill_id, skill_lv); else unit_skilluse_id(&ed->bl, bl->id, skill_id, skill_lv); // Reset target. ed->target_id = 0; return 1; }
int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned int tick) { short skillnum, skilllv; int i; nullpo_ret(ed); nullpo_ret(bl); if( !ed->master ) return 0; if( ed->target_id ) elemental_unlocktarget(ed); // Remove previous target. ARR_FIND(0, MAX_ELESKILLTREE, i, ed->db->skill[i].id && (ed->db->skill[i].mode&EL_SKILLMODE_AGGRESSIVE)); if( i == MAX_ELESKILLTREE ) return 0; skillnum = ed->db->skill[i].id; skilllv = ed->db->skill[i].lv; if( elemental_skillnotok(skillnum, ed) ) return 0; if( ed->ud.skilltimer != -1 ) return 0; else if( DIFF_TICK(tick, ed->ud.canact_tick) < 0 ) return 0; ed->target_id = ed->ud.skilltarget = bl->id; // Set new target ed->last_thinktime = tick; // Not in skill range. if( !battle_check_range(&ed->bl,bl,skill_get_range(skillnum,skilllv)) ) { // Try to walk to the target. if( !unit_walktobl(&ed->bl, bl, skill_get_range(skillnum,skilllv), 2) ) elemental_unlocktarget(ed); else { // Walking, waiting to be in range. Client don't handle it, then we must handle it here. int walk_dist = distance_bl(&ed->bl,bl) - skill_get_range(skillnum,skilllv); ed->ud.skillid = skillnum; ed->ud.skilllv = skilllv; if( skill_get_inf(skillnum) & INF_GROUND_SKILL ) ed->ud.skilltimer = add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill_castend_pos, ed->bl.id, 0 ); else ed->ud.skilltimer = add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill_castend_id, ed->bl.id, 0 ); } return 1; } //Otherwise, just cast the skill. if( skill_get_inf(skillnum) & INF_GROUND_SKILL ) unit_skilluse_pos(&ed->bl, bl->x, bl->y, skillnum, skilllv); else unit_skilluse_id(&ed->bl, bl->id, skillnum, skilllv); // Reset target. ed->target_id = 0; return 1; }