/** * Make pet use attack skill. * @param pd : pet requesting * @param target_id : ID of target * @author [Skotlex] */ int pet_attackskill(struct pet_data *pd, int target_id) { if (!battle_config.pet_status_support || !pd->a_skill || (battle_config.pet_equip_required && !pd->pet.equip)) return 0; if (DIFF_TICK(pd->ud.canact_tick, gettick()) > 0) return 0; if (rnd()%100 < (pd->a_skill->rate +pd->pet.intimate*pd->a_skill->bonusrate/1000)) { // Skotlex: Use pet's skill int inf; struct block_list *bl; bl = map_id2bl(target_id); if(bl == NULL || pd->bl.m != bl->m || bl->prev == NULL || status_isdead(bl) || !check_distance_bl(&pd->bl, bl, pd->db->range3)) return 0; inf = skill_get_inf(pd->a_skill->id); if (inf & INF_GROUND_SKILL) unit_skilluse_pos(&pd->bl, bl->x, bl->y, pd->a_skill->id, pd->a_skill->lv); else //Offensive self skill? Could be stuff like GX. unit_skilluse_id(&pd->bl,(inf&INF_SELF_SKILL?pd->bl.id:bl->id), pd->a_skill->id, pd->a_skill->lv); return 1; //Skill invoked. } return 0; }
/*=============================================================== * Action that elemental perform after changing mode. * Activates one of the skills of the new mode. *-------------------------------------------------------------*/ int elemental_change_mode_ack(struct elemental_data *ed, int mode) { struct block_list *bl = &ed->master->bl; short skillnum, skilllv; int i; nullpo_ret(ed); if( !bl ) return 0; // Select a skill. ARR_FIND(0, MAX_ELESKILLTREE, i, ed->db->skill[i].id && (ed->db->skill[i].mode&mode)); 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(gettick(), ed->ud.canact_tick) < 0 ) return 0; ed->target_id = bl->id; // Set new target ed->last_thinktime = gettick(); 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); ed->target_id = 0; // Reset target after casting the skill to avoid continious attack. return 1; }
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; }