summaryrefslogtreecommitdiff
path: root/src/map/battle.c
diff options
context:
space:
mode:
authorshennetsind <shennetsind@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-04-20 18:05:14 +0000
committershennetsind <shennetsind@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-04-20 18:05:14 +0000
commit92249d9f8e219916670589ba6c5f9fce47808ed8 (patch)
tree0d1b0aa06c3490b3dbf7140bebd8bda126bfd65e /src/map/battle.c
parent1b3bd9ff1725a68d66fd4015c60d6fe28e4b2334 (diff)
downloadhercules-92249d9f8e219916670589ba6c5f9fce47808ed8.tar.gz
hercules-92249d9f8e219916670589ba6c5f9fce47808ed8.tar.bz2
hercules-92249d9f8e219916670589ba6c5f9fce47808ed8.tar.xz
hercules-92249d9f8e219916670589ba6c5f9fce47808ed8.zip
Initial support for Genetic, Sorcerer and Elemental Summons. Special Thanks to 3CeAM for the base.
Notice this revision onwards requires you to update your char sql table and add the elemental sql table (check sql-files/upgrade_svn15885_log.sql) If you step by any bugs, let us know at http://rathena.org/board/tracker/ Thank you very much. ARRIBA ARRIBA. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15885 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/map/battle.c')
-rw-r--r--src/map/battle.c252
1 files changed, 215 insertions, 37 deletions
diff --git a/src/map/battle.c b/src/map/battle.c
index 48f8e1cab..cea562661 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -18,6 +18,7 @@
#include "skill.h"
#include "homunculus.h"
#include "mercenary.h"
+#include "elemental.h"
#include "mob.h"
#include "itemdb.h"
#include "clif.h"
@@ -103,6 +104,7 @@ int battle_gettarget(struct block_list* bl)
case BL_PET: return ((struct pet_data*)bl)->target_id;
case BL_HOM: return ((struct homun_data*)bl)->ud.target;
case BL_MER: return ((struct mercenary_data*)bl)->ud.target;
+ case BL_ELEM: return ((struct elemental_data*)bl)->ud.target;
}
return 0;
}
@@ -299,8 +301,7 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag
}
ratio = attr_fix_table[def_lv-1][atk_elem][def_type];
- if (sc && sc->count)
- {
+ if (sc && sc->count) {
if(sc->data[SC_VOLCANO] && atk_elem == ELE_FIRE)
ratio += enchant_eff[sc->data[SC_VOLCANO]->val1-1];
if(sc->data[SC_VIOLENTGALE] && atk_elem == ELE_WIND)
@@ -308,8 +309,27 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag
if(sc->data[SC_DELUGE] && atk_elem == ELE_WATER)
ratio += enchant_eff[sc->data[SC_DELUGE]->val1-1];
}
- if( atk_elem == ELE_FIRE && tsc && tsc->count && tsc->data[SC_SPIDERWEB] )
- {
+ if( target && target->type == BL_SKILL ) {
+ if( atk_elem == ELE_FIRE && battle_getcurrentskill(target) == GN_WALLOFTHORN ) {
+ struct skill_unit *su = (struct skill_unit*)target;
+ struct skill_unit_group *sg;
+ struct block_list *src;
+ int x,y;
+
+ if( !su || !su->alive || (sg = su->group) == NULL || !sg || sg->val3 == -1 ||
+ (src = map_id2bl(su->val2)) == NULL || status_isdead(src) )
+ return 0;
+
+ if( sg->unit_id != UNT_FIREWALL ) {
+ x = sg->val3 >> 16;
+ y = sg->val3 & 0xffff;
+ skill_unitsetting(src,su->group->skill_id,su->group->skill_lv,x,y,1);
+ sg->val3 = -1;
+ sg->limit = DIFF_TICK(gettick(),sg->tick)+300;
+ }
+ }
+ }
+ if( atk_elem == ELE_FIRE && tsc && tsc->count && tsc->data[SC_SPIDERWEB] ){
tsc->data[SC_SPIDERWEB]->val1 = 0; // free to move now
if( tsc->data[SC_SPIDERWEB]->val2-- > 0 )
damage <<= 1; // double damage
@@ -932,6 +952,8 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int
case W_DAGGER:
if((skill = pc_checkskill(sd,SM_SWORD)) > 0)
damage += (skill * 4);
+ if((skill = pc_checkskill(sd,GN_TRAINING_SWORD)) > 0)
+ damage += skill * 10;
break;
case W_2HSWORD:
#ifdef RENEWAL
@@ -1486,15 +1508,27 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if(sd && pc_checkskill(sd,AS_SONICACCEL)>0)
hitrate += hitrate * 50 / 100;
break;
+ case MC_CARTREVOLUTION:
+ case GN_CART_TORNADO:
+ case GN_CARTCANNON:
+ if( sd && pc_checkskill(sd, GN_REMODELING_CART) )
+ hitrate += pc_checkskill(sd, GN_REMODELING_CART) * 4;
+ break;
case GC_VENOMPRESSURE:
hitrate += 10 + 4 * skill_lv;
break;
}
- // Weaponry Research hidden bonus
- if (sd && (skill = pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0)
- hitrate += hitrate * ( 2 * skill ) / 100;
-
+ if( sd ) {
+ // Weaponry Research hidden bonus
+ if ((skill = pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0)
+ hitrate += hitrate * ( 2 * skill ) / 100;
+
+ if( (sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DAGGER) &&
+ (skill = pc_checkskill(sd, GN_TRAINING_SWORD))>0 )
+ hitrate += 3 * skill;
+ }
+
hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate);
if(rnd()%100 >= hitrate)
@@ -2238,6 +2272,76 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
case WM_SOUND_OF_DESTRUCTION:
skillratio += 400;
break;
+ case GN_CART_TORNADO:
+ if( sd )
+ skillratio += 50 * skill_lv + pc_checkskill(sd, GN_REMODELING_CART) * 100 - 100;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ if( sc && sc->data[SC_GN_CARTBOOST] )
+ skillratio += 10 * sc->data[SC_GN_CARTBOOST]->val1;
+ break;
+ case GN_CARTCANNON:
+ if( sd ) skillratio += 250 + 50 * skill_lv + pc_checkskill(sd, GN_REMODELING_CART) * (sstatus->int_ / 2);
+ if( sc && sc->data[SC_GN_CARTBOOST] )
+ skillratio += 10 * sc->data[SC_GN_CARTBOOST]->val1;
+ break;
+ case GN_SPORE_EXPLOSION:
+ skillratio += 200 + 100 * skill_lv;
+ break;
+ case GN_CRAZYWEED_ATK:
+ skillratio += 400 + 100 * skill_lv;
+ break;
+ case GN_SLINGITEM_RANGEMELEEATK:
+ if( sd ) {
+ switch( sd->itemid ) {
+ case 13260: // Apple Bomob
+ case 13261: // Coconut Bomb
+ case 13262: // Melon Bomb
+ case 13263: // Pinapple Bomb
+ skillratio += 400; // Unconfirded
+ break;
+ case 13264: // Banana Bomb 2000%
+ skillratio += 1900;
+ break;
+ case 13265: skillratio -= 75; break; // Black Lump 25%
+ case 13266: skillratio -= 25; break; // Hard Black Lump 75%
+ case 13267: skillratio += 100; break; // Extremely Hard Black Lump 200%
+ }
+ } else
+ skillratio += 300; // Bombs
+ break;
+ case SO_VARETYR_SPEAR: //Assumed Formula.
+ skillratio += -100 + 200 * ( sd ? pc_checkskill(sd, SA_LIGHTNINGLOADER) : 1 );
+ if( sc && sc->data[SC_BLAST_OPTION] )
+ skillratio += skillratio * sc->data[SC_BLAST_OPTION]->val2 / 100;
+ break;
+ // Physical Elemantal Spirits Attack Skills
+ case EL_CIRCLE_OF_FIRE:
+ case EL_FIRE_BOMB_ATK:
+ case EL_STONE_RAIN:
+ skillratio += 200;
+ break;
+ case EL_FIRE_WAVE_ATK:
+ skillratio += 500;
+ break;
+ case EL_TIDAL_WEAPON:
+ skillratio += 1400;
+ break;
+ case EL_WIND_SLASH:
+ skillratio += 100;
+ break;
+ case EL_HURRICANE:
+ skillratio += 600;
+ break;
+ case EL_TYPOON_MIS:
+ case EL_WATER_SCREW_ATK:
+ skillratio += 900;
+ break;
+ case EL_STONE_HAMMER:
+ skillratio += 400;
+ break;
+ case EL_ROCK_CRUSHER:
+ skillratio += 700;
+ break;
}
ATK_RATE(skillratio);
@@ -2920,7 +3024,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int mflag)
{
int i, nk;
- short s_ele;
+ short s_ele = 0;
unsigned int skillratio = 100; //Skill dmg modifiers.
struct map_session_data *sd, *tsd;
@@ -2954,16 +3058,38 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
sd = BL_CAST(BL_PC, src);
tsd = BL_CAST(BL_PC, target);
- //Initialize variables that will be used afterwards
- s_ele = skill_get_ele(skill_num, skill_lv);
-
- if (s_ele == -1) // pl=-1 : the skill takes the weapon's element
- s_ele = sstatus->rhw.ele;
- else if (s_ele == -2) //Use status element
- s_ele = status_get_attack_sc_element(src,status_get_sc(src));
- else if( s_ele == -3 ) //Use random element
- s_ele = rnd()%ELE_MAX;
-
+ if( skill_num == SO_PSYCHIC_WAVE ) {
+ struct status_change *sc = status_get_sc(src);
+ if( sc && sc->count && ( sc->data[SC_HEATER_OPTION] || sc->data[SC_COOLER_OPTION] ||
+ sc->data[SC_BLAST_OPTION] || sc->data[SC_CURSED_SOIL_OPTION] ) ) {
+ if( sc->data[SC_HEATER_OPTION] ) s_ele = sc->data[SC_HEATER_OPTION]->val4;
+ else if( sc->data[SC_COOLER_OPTION] ) s_ele = sc->data[SC_COOLER_OPTION]->val4;
+ else if( sc->data[SC_BLAST_OPTION] ) s_ele = sc->data[SC_BLAST_OPTION]->val3;
+ else if( sc->data[SC_CURSED_SOIL_OPTION] ) s_ele = sc->data[SC_CURSED_SOIL_OPTION]->val4;
+ } else {
+ //#HALP# I didn't get a clue on how to do this without unnecessary adding a overhead of status_change on every call while this is a per-skill case.
+ //, - so i duplicated this code. make yourself comfortable to fix if you have any better ideas.
+ //Initialize variables that will be used afterwards
+ s_ele = skill_get_ele(skill_num, skill_lv);
+
+ if (s_ele == -1) // pl=-1 : the skill takes the weapon's element
+ s_ele = sstatus->rhw.ele;
+ else if (s_ele == -2) //Use status element
+ s_ele = status_get_attack_sc_element(src,status_get_sc(src));
+ else if( s_ele == -3 ) //Use random element
+ s_ele = rnd()%ELE_MAX;
+ }
+ } else {
+ //Initialize variables that will be used afterwards
+ s_ele = skill_get_ele(skill_num, skill_lv);
+
+ if (s_ele == -1) // pl=-1 : the skill takes the weapon's element
+ s_ele = sstatus->rhw.ele;
+ else if (s_ele == -2) //Use status element
+ s_ele = status_get_attack_sc_element(src,status_get_sc(src));
+ else if( s_ele == -3 ) //Use random element
+ s_ele = rnd()%ELE_MAX;
+ }
//Set miscellaneous data that needs be filled
if(sd) {
sd->state.arrow_atk = 0;
@@ -3334,6 +3460,24 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
else
skillratio += 110 + 20 * skill_lv;
break;
+ // Magical Elemental Spirits Attack Skills
+ case EL_FIRE_MANTLE:
+ case EL_WATER_SCREW:
+ skillratio += 900;
+ break;
+ case EL_FIRE_ARROW:
+ case EL_ROCK_CRUSHER_ATK:
+ skillratio += 200;
+ break;
+ case EL_FIRE_BOMB:
+ case EL_ICE_NEEDLE:
+ case EL_HURRICANE_ATK:
+ skillratio += 400;
+ break;
+ case EL_FIRE_WAVE:
+ case EL_TYPOON_MIS_ATK:
+ skillratio += 1100;
+ break;
}
@@ -3493,6 +3637,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
ad.damage=battle_calc_gvg_damage(src,target,ad.damage,ad.div_,skill_num,skill_lv,ad.flag);
else if( map[target->m].flag.battleground )
ad.damage=battle_calc_bg_damage(src,target,ad.damage,ad.div_,skill_num,skill_lv,ad.flag);
+
+
+ if( skill_num == SO_VARETYR_SPEAR ) { // Physical damage.
+ struct Damage wd = battle_calc_weapon_attack(src,target,skill_num,skill_lv,mflag);
+ ad.damage += wd.damage;
+ }
+
return ad;
}
@@ -3675,7 +3826,15 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
if (sd) md.damage = md.damage + status_get_hp(src);
status_set_sp(src, 0, 0);
break;
-
+ case GN_THORNS_TRAP:
+ md.damage = 100 + 200 * skill_lv + sstatus->int_;
+ break;
+ case GN_BLOOD_SUCKER:
+ md.damage = 200 + 100 * skill_lv + sstatus->int_;
+ break;
+ case GN_HELLS_PLANT_ATK:
+ md.damage = sstatus->int_ * 4 * skill_lv * (10 / (10 - pc_checkskill(sd,AM_CANNIBALIZE)));//Need accurate official formula. [Rytech]
+ break;
}
if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets
@@ -4168,24 +4327,38 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
map_freeblock_lock();
battle_delay_damage(tick, wd.amotion, src, target, wd.flag, 0, 0, damage, wd.dmg_lv, wd.dmotion);
-
- if( tsc && tsc->data[SC_DEVOTION] )
- {
- struct status_change_entry *sce = tsc->data[SC_DEVOTION];
- struct block_list *d_bl = map_id2bl(sce->val1);
-
- if( d_bl && (
- (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == target->id) ||
- (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id)
- ) && check_distance_bl(target, d_bl, sce->val3) )
- {
- clif_damage(d_bl, d_bl, gettick(), 0, 0, damage, 0, 0, 0);
- status_fix_damage(NULL, d_bl, damage, 0);
- }
- else
- status_change_end(target, SC_DEVOTION, INVALID_TIMER);
+ if( tsc ) {
+ if( tsc->data[SC_DEVOTION] ) {
+ struct status_change_entry *sce = tsc->data[SC_DEVOTION];
+ struct block_list *d_bl = map_id2bl(sce->val1);
+
+ if( d_bl && (
+ (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == target->id) ||
+ (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id)
+ ) && check_distance_bl(target, d_bl, sce->val3) )
+ {
+ clif_damage(d_bl, d_bl, gettick(), 0, 0, damage, 0, 0, 0);
+ status_fix_damage(NULL, d_bl, damage, 0);
+ }
+ else
+ status_change_end(target, SC_DEVOTION, INVALID_TIMER);
+ } else if( tsc->data[SC_CIRCLE_OF_FIRE_OPTION] && (wd.flag&BF_SHORT) && target->type == BL_PC ) {
+ struct elemental_data *ed = ((TBL_PC*)target)->ed;
+ if( ed ) {
+ clif_skill_damage(&ed->bl, target, tick, status_get_amotion(src), 0, -30000, 1, EL_CIRCLE_OF_FIRE, tsc->data[SC_CIRCLE_OF_FIRE_OPTION]->val1, 6);
+ skill_attack(BF_MAGIC,&ed->bl,&ed->bl,src,EL_CIRCLE_OF_FIRE,tsc->data[SC_CIRCLE_OF_FIRE_OPTION]->val1,tick,wd.flag);
+ }
+ } else if( tsc->data[SC_WATER_SCREEN_OPTION] && tsc->data[SC_WATER_SCREEN_OPTION]->val1 ) {
+ struct block_list *e_bl = map_id2bl(tsc->data[SC_WATER_SCREEN_OPTION]->val1);
+ if( e_bl && !status_isdead(e_bl) ) {
+ clif_damage(e_bl,e_bl,tick,wd.amotion,wd.dmotion,damage,wd.div_,wd.type,wd.damage2);
+ status_damage(target,e_bl,damage,0,0,0);
+ // Just show damage in target.
+ clif_damage(src, target, tick, wd.amotion, wd.dmotion, damage, wd.div_, wd.type, wd.damage2 );
+ return ATK_NONE;
+ }
+ }
}
-
if (sc && sc->data[SC_AUTOSPELL] && rnd()%100 < sc->data[SC_AUTOSPELL]->val4) {
int sp = 0;
int skillid = sc->data[SC_AUTOSPELL]->val2;
@@ -4314,6 +4487,10 @@ struct block_list* battle_get_master(struct block_list *src)
if (((TBL_MER*)src)->master)
src = (struct block_list*)((TBL_MER*)src)->master;
break;
+ case BL_ELEM:
+ if (((TBL_ELEM*)src)->master)
+ src = (struct block_list*)((TBL_ELEM*)src)->master;
+ break;
case BL_SKILL:
if (((TBL_SKILL*)src)->group && ((TBL_SKILL*)src)->group->src_id)
src = map_id2bl(((TBL_SKILL*)src)->group->src_id);
@@ -4409,6 +4586,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
//Valid targets with no special checks here.
case BL_MER:
case BL_HOM:
+ case BL_ELEM:
break;
//All else not specified is an invalid target.
default: