diff options
author | L0neW0lf.eAthena <L0neW0lf.eAthena@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2011-10-26 19:44:18 +0000 |
---|---|---|
committer | L0neW0lf.eAthena <L0neW0lf.eAthena@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2011-10-26 19:44:18 +0000 |
commit | b6620108c8dc2b0e394462a7d32cc77a446dddee (patch) | |
tree | 15769dda2b1454cda132c9b2409237a63bc975b9 | |
parent | 8c95a8ceb2891c898b80df3ce002351f5a89dd03 (diff) | |
download | hercules-b6620108c8dc2b0e394462a7d32cc77a446dddee.tar.gz hercules-b6620108c8dc2b0e394462a7d32cc77a446dddee.tar.bz2 hercules-b6620108c8dc2b0e394462a7d32cc77a446dddee.tar.xz hercules-b6620108c8dc2b0e394462a7d32cc77a446dddee.zip |
* Implemented first version of rebalanced Rune Knight skills.
* Implemented the rebalancing of most Archbishop skills.
* As a result, merged r14979 from trunk. (act/notify packet update)
* Added pc_isUseitem_check_runeskill care of Meyrawr (blocks rune usage based on skill delay.)
* Added more status effects that do NOT save on log out. A whole slew of them.
* Now only level 11 Dec. AGI will take the new config settings into account.
* Fixed Level 11 Dec. AGI duration faux pas, where it was multiplying it by 100.
* Added script command: setdragon: See documentation for details.
* Added script command: successruneuse: Will return 0 or 1. Handles runestone backfire effects.
* Modified script command: produce, now accepts <item id> as a second parameter.
* Corrected message that is displayed when attempting to generate items when that item has a limit.
* GM Item commands will no longer display 'Item created' messages on failure.
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/branches/renewal@14983 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r-- | Changelog-Renewal.txt | 13 | ||||
-rw-r--r-- | conf/battle/items.conf | 8 | ||||
-rw-r--r-- | src/char/char.c | 2 | ||||
-rw-r--r-- | src/char_sql/char.c | 2 | ||||
-rw-r--r-- | src/map/atcommand.c | 6 | ||||
-rw-r--r-- | src/map/battle.c | 204 | ||||
-rw-r--r-- | src/map/battle.h | 2 | ||||
-rw-r--r-- | src/map/clif.c | 73 | ||||
-rw-r--r-- | src/map/clif.h | 3 | ||||
-rw-r--r-- | src/map/map.c | 54 | ||||
-rw-r--r-- | src/map/mob.c | 2 | ||||
-rw-r--r-- | src/map/pc.c | 82 | ||||
-rw-r--r-- | src/map/pc.h | 7 | ||||
-rw-r--r-- | src/map/script.c | 134 | ||||
-rw-r--r-- | src/map/skill.c | 276 | ||||
-rw-r--r-- | src/map/status.c | 235 | ||||
-rw-r--r-- | src/map/status.h | 39 | ||||
-rw-r--r-- | src/map/unit.c | 2 |
18 files changed, 1029 insertions, 115 deletions
diff --git a/Changelog-Renewal.txt b/Changelog-Renewal.txt index 97cd2639c..2efabfd33 100644 --- a/Changelog-Renewal.txt +++ b/Changelog-Renewal.txt @@ -1,5 +1,18 @@ Date Added +2011/10/26 + * Rev. 14982 Implemented first version of rebalanced Rune Knight skills. [L0ne_W0lf] + * Implemented the rebalancing of most Archbishop skills. + * As a result, merged r14979 from trunk. (act/notify packet update) + * Added pc_isUseitem_check_runeskill care of Meyrawr (blocks rune usage based on skill delay.) + * Added more status effects that do NOT save on log out. A whole slew of them. + * Now only level 11 Dec. AGI will take the new config settings into account. + * Fixed Level 11 Dec. AGI duration faux pas, where it was multiplying it by 100. + * Added script command: setdragon: See documentation for details. + * Added script command: successruneuse: Will return 0 or 1. Handles runestone backfire effects. + * Modified script command: produce, now accepts <item id> as a second parameter. + * Corrected message that is displayed when attempting to generate items when that item has a limit. + * GM Item commands will no longer display 'Item created' messages on failure. 2011/10/07 * Merged changes from trunk [14895:14966/trunk]. [Ai4rei] 2011/09/30 diff --git a/conf/battle/items.conf b/conf/battle/items.conf index 9dc7ca314..200241ca6 100644 --- a/conf/battle/items.conf +++ b/conf/battle/items.conf @@ -87,3 +87,11 @@ gtb_sc_immunity: 50 // NOTE: Different cards that grant the same skill will both // always work independently of each other regardless of setting. autospell_stacking: no + +// Rune consumption is blocked by the skill's cooldown (note 1) +rune_block_by_skill: yes + +// Rune consumption is blocked by previously activated status effect (Note 1) +// associated with the skill the rune stone being used would cast. +// ie: if SC_REFRESH is active, then the Nosiege Runestone is unuseable. +rune_block_by_status: no diff --git a/src/char/char.c b/src/char/char.c index dfcbc9230..0f23744c0 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -1828,7 +1828,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; WBUFW(buf,52) = p->class_; WBUFW(buf,54) = p->hair; - WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!? + WBUFW(buf,56) = p->option&0x7E80020 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!? WBUFW(buf,58) = p->base_level; WBUFW(buf,60) = min(p->skill_point, INT16_MAX); WBUFW(buf,62) = p->head_bottom; diff --git a/src/char_sql/char.c b/src/char_sql/char.c index 0654be60a..30800d95b 100644 --- a/src/char_sql/char.c +++ b/src/char_sql/char.c @@ -1626,7 +1626,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; WBUFW(buf,52) = p->class_; WBUFW(buf,54) = p->hair; - WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!? + WBUFW(buf,56) = p->option&0x7E80020 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!? WBUFW(buf,58) = p->base_level; WBUFW(buf,60) = min(p->skill_point, INT16_MAX); WBUFW(buf,62) = p->head_bottom; diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 5ccf14ea2..b1a395afa 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -1710,7 +1710,8 @@ ACMD_FUNC(item) if(log_config.enable_logs&0x400) log_pick_pc(sd, "A", item_id, number, NULL); - clif_displaymessage(fd, msg_txt(18)); // Item created. + if (!flag) + clif_displaymessage(fd, msg_txt(18)); // Item created. return 0; } @@ -1785,7 +1786,8 @@ ACMD_FUNC(item2) if(log_config.enable_logs&0x400) log_pick_pc(sd, "A", item_tmp.nameid, number, &item_tmp); - clif_displaymessage(fd, msg_txt(18)); // Item created. + if (!flag) + clif_displaymessage(fd, msg_txt(18)); // Item created. } else { clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. return -1; diff --git a/src/map/battle.c b/src/map/battle.c index b0e42a7c7..f338a50bb 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -361,7 +361,26 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag clif_skill_nodamage(bl, bl, LK_PARRYING, sce->val1,1); return 0; } - + + if((sce=sc->data[SC_MILLENNIUMSHIELD]) && damage > 0) { + if(sce->val2 > 0) + { + sce->val3 -= damage; + if( sce->val3 <= 0 ) + { // Reduce remaining shields and create new one. + sc_start(bl,SC_STUN,15,0,1000); + sce->val3 = 1000; + sce->val2--; + if( sd ) + clif_millenniumshield(sd,sce->val2); + } + + damage = 0; // Nullify damage even if shield is destroyed. + } + if(sce->val2 <= 0) + status_change_end(bl, SC_MILLENNIUMSHIELD, INVALID_TIMER); + } + if(sc->data[SC_DODGE] && !sc->opt1 && (flag&BF_LONG || sc->data[SC_SPURT]) && rand()%100 < 20) { @@ -415,7 +434,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag } //Finally damage reductions.... - if( sc->data[SC_ASSUMPTIO] ) + if( sc->data[SC_ASSUMPTIO] && skill_num != RK_DRAGONBREATH ) { if( map_flag_vs(bl->m) ) damage = damage*2/3; //Receive 66% damage @@ -428,10 +447,11 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag damage=damage*(100-sc->data[SC_DEFENDER]->val2)/100; if(sc->data[SC_ADJUSTMENT] && - (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) + (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON) && + skill_num != RK_DRAGONBREATH) damage -= 20*damage/100; - if(sc->data[SC_FOGWALL]) { + if(sc->data[SC_FOGWALL] && skill_num != RK_DRAGONBREATH) { if(flag&BF_SKILL) //25% reduction damage -= 25*damage/100; else if ((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) @@ -493,7 +513,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag //Finally Kyrie because it may, or not, reduce damage to 0. if((sce = sc->data[SC_KYRIE]) && damage > 0){ sce->val2-=damage; - if(flag&BF_WEAPON || skill_num == TF_THROWSTONE){ + if(flag&BF_WEAPON || skill_num == TF_THROWSTONE || skill_num == RK_DRAGONBREATH){ if(sce->val2>=0) damage=0; else @@ -503,6 +523,13 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag status_change_end(bl, SC_KYRIE, INVALID_TIMER); } + if((sce = sc->data[SC_STONEHARDSKIN]) && damage > 0) + { + sce->val2-=damage; // Reduce Stone Skin's HP by damage taken. + if( sce->val2 <= 0 ) + status_change_end(bl, SC_STONEHARDSKIN, INVALID_TIMER); + } + if (!damage) return 0; //Probably not the most correct place, but it'll do here @@ -601,6 +628,7 @@ int battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int dam case PA_PRESSURE: case HW_GRAVITATION: case NJ_ZENYNAGE: + case RK_DRAGONBREATH: break; default: if( flag&BF_SKILL ) @@ -662,6 +690,7 @@ int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int dama case PA_PRESSURE: case HW_GRAVITATION: case NJ_ZENYNAGE: + case RK_DRAGONBREATH: break; default: if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex] @@ -743,10 +772,13 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int case W_1HSPEAR: case W_2HSPEAR: if((skill = pc_checkskill(sd,KN_SPEARMASTERY)) > 0) { - if(!pc_isriding(sd)) + if(!pc_isriding(sd) && !pc_isdragon(sd)) damage += (skill * 4); else damage += (skill * 5); + // increase damage by level of KN_SPEARMASTERY * 10 + if (pc_checkskill(sd,RK_DRAGONTRAINING) > 0) + damage += (skill * 10); } break; case W_1HAXE: @@ -990,7 +1022,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo wd.type=0; //Normal attack wd.div_=skill_num?skill_get_num(skill_num,skill_lv):1; wd.amotion=(skill_num && skill_get_inf(skill_num)&INF_GROUND_SKILL)?0:sstatus->amotion; //Amotion should be 0 for ground skills. - if(skill_num == KN_AUTOCOUNTER) + if(skill_num == KN_AUTOCOUNTER || skill_num == RK_DEATHBOUND) wd.amotion >>= 1; wd.dmotion=tstatus->dmotion; wd.blewcount=skill_get_blewcount(skill_num,skill_lv); @@ -1063,6 +1095,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo break; case KN_AUTOCOUNTER: + case RK_DEATHBOUND: wd.flag=(wd.flag&~BF_SKILLMASK)|BF_NORMAL; break; @@ -1403,6 +1436,15 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if( (i = party_foreachsamemap(party_sub_count, sd, 0)) > 1 ) // exclude the player himself [Inkfish] ATK_ADDRATE(2*skill*i); } + if(sd->status.party_id && sc && sc->data[SC_FIGHTINGSPIRIT]) + { + i = party_foreachsamemap(party_sub_count, sd, 0); + if( (sc->data[SC_FIGHTINGSPIRIT]->val2) > 0){ + ATK_ADDRATE(7*i); //Caster gets full effect. + }else{ + ATK_ADDRATE(7*i/4); //Party members get 1/4. + } + } } break; } //End default case @@ -1725,6 +1767,62 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case NPC_VAMPIRE_GIFT: skillratio += ((skill_lv-1)%5+1)*100; break; + case RK_SONICWAVE: + skillratio += ((skill_lv + 5) * 100) * (1 + (status_get_lv(src) -100) / 200); + break; + case RK_HUNDREDSPEAR: + { + int weight = 1, dmg = 0; + if (sd) { + short index = sd->equip_index[EQI_HAND_R]; + + if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON) + weight = sd->inventory_data[index]->weight; //80% of weight + } + + dmg = (600 + (skill_lv * 80) + (1000 - (weight>1000?1000:weight)) * ((1 + status_get_lv(src) - 100) / 200)); + + if(sd) // Add clashing spiral bonus damage (Skill level * 50% damage) + dmg += pc_checkskill(sd,LK_SPIRALPIERCE) * (dmg * 50 /100); + + skillratio = dmg; + break; + } + case RK_WINDCUTTER: + skillratio += ((skill_lv + 2) * 50) * status_get_lv(src) / 100; + break; + case RK_IGNITIONBREAK: + { + int dmg = 300; // Base maximum damage at less than 3 cells. + i = distance_bl(src,target); + if( i > 7 ) + dmg -= 100; // Greather than 7 cells. (200 damage) + else if( i > 3 ) + dmg -= 50; // Greater than 3 cells, less than 7. (250 damage) + + dmg = (dmg * skill_lv) * (1+ (status_get_lv(src) - 100) / 120); + + // Elemental check, +100% damage if your element is fire. + if( sstatus->rhw.ele == ELE_FIRE ) + dmg += skill_lv * 100 / 100; + + skillratio = dmg; + break; + } + case RK_CRUSHSTRIKE: + if(sd) + { + short index = sd->equip_index[EQI_HAND_R]; + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) + skillratio = (sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6) * 100) + sd->inventory_data[index]->atk + sd->inventory_data[index]->weight; + } + break; + case RK_STORMBLAST: + skillratio = ((sd?pc_checkskill(sd,RK_RUNEMASTERY):1) + (sstatus->int_ / 8)) * 100; + break; + case RK_PHANTOMTHRUST: + skillratio = ((skill_lv * 50) + (sd?pc_checkskill(sd,KN_SPEARMASTERY):0) * 10) * status_get_lv(src) / 150; + break; case AB_DUPLELIGHT_MELEE: skillratio += 10 * skill_lv; break; @@ -2302,18 +2400,50 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo wd.damage += md.damage; } - //SG_FUSION hp penalty [Komurka] - if (sc && sc->data[SC_FUSION]) - { - int hp= sstatus->max_hp; - if (sd && tsd) { - hp = 8*hp/100; - if (100*sstatus->hp <= 20*sstatus->max_hp) - hp = sstatus->hp; - } else - hp = 2*hp/100; //2% hp loss per hit - status_zap(src, hp, 0); - } + if ( sc ) + { // I don't see the point in repeating the SC check now that there are more things that use it. [L0ne_W0lf] + if (sc->data[SC_FUSION]) + { //SG_FUSION hp penalty [Komurka] + int hp= sstatus->max_hp; + if (sd && tsd) { + hp = 8*hp/100; + if (100*sstatus->hp <= 20*sstatus->max_hp) + hp = sstatus->hp; + } else + hp = 2*hp/100; //2% hp loss per hit + status_zap(src, hp, 0); + } + + if(sc->data[SC_ENCHANTBLADE] && !skill_num && wd.flag&BF_SHORT ) + { + if (tsc && tsc->data[SC_SAFETYWALL]) + ; // Although this is suposed to be considered a magic atttack, Safety Wall still blocks it? May be impemented wrong. + else + { + struct Damage ebd = battle_calc_attack(BF_MAGIC,src,target,RK_ENCHANTBLADE,sc->data[SC_ENCHANTBLADE]->val1,wd.flag); + wd.damage += (sc->data[SC_ENCHANTBLADE]->val1 * 20 + 100) * (status_get_lv(src) / 150) + sstatus->int_ + ebd.damage; + } + } + + if(sc->data[SC_GIANTGROWTH] && !skill_num ) + { + int rate = battle_config.equip_natural_break_rate; + rate += 10; + skill_break_equip(src, EQP_WEAPON, rate, BCT_SELF); + if( rand() % 100 <= 10 ) + ATK_RATE(300); + } + + if(sc->data[SC_STONEHARDSKIN] && !skill_num) + { // SC_STRIPWEAPON will reduce damage by 25% so piggyback off that since there is no offensive status for this. + int rate = battle_config.equip_natural_break_rate; + rate += 300; //chance to break gear, or reduce attack by 25% in hte case of monsters. + if( sd ) + skill_break_equip(src,EQP_WEAPON,rate,BCT_ENEMY); + if (!sd && !(status_get_mode(src)&MD_BOSS)) + status_change_start(src,SC_STRIPWEAPON,rate,0,0,0,0,10000,0); + } + } return wd; } @@ -2526,17 +2656,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list skillratio += 100 +100*skill_lv +100*(skill_lv/2); break; case AB_JUDEX: - skillratio += ((skill_lv < 5)?180 + 20 * skill_lv:300); // Possible RE-Formula - if( status_get_lv(src) >= 100 ) - skillratio = skillratio * status_get_lv(src) / 100; + skillratio += ((skill_lv * 20) + 300) * status_get_lv(src) / 100; break; case AB_ADORAMUS: - skillratio += 100 * (skill_lv + 5); - if( status_get_lv(src) >= 100 ) - skillratio = skillratio * status_get_lv(src) / 100; + skillratio += ((skill_lv * 100) + 500) * status_get_lv(src) / 100; break; case AB_DUPLELIGHT_MAGIC: - skillratio += 100 + 20 * skill_lv; + skillratio = 200 + 20 * skill_lv; break; } @@ -2830,6 +2956,8 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * case NPC_EVILLAND: md.damage = skill_calc_heal(src,target,skill_num,skill_lv,false); break; + case RK_DRAGONBREATH: + md.damage = (sstatus->hp / 50 + sstatus->max_sp / 4) * (skill_lv * status_get_lv(src)/150) * (95 + 5 * (sd?pc_checkskill(sd,RK_DRAGONTRAINING):10)) / 100; } if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets @@ -3198,7 +3326,19 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t skill_addtimerskill(src,tick+status_get_adelay(src) / 2,target->id,0,0,AB_DUPLELIGHT_MAGIC,skilllv,BF_MAGIC,flag); } - rdamage = battle_calc_return_damage(target, damage, wd.flag); + if(tsc && tsc->data[SC_DEATHBOUND] && !is_boss(src) && map_check_dir(map_calc_dir(src,target->x,target->y),unit_getdir(target))) + { + int skilllv = tsc->data[SC_DEATHBOUND]->val1; + clif_skill_damage(src,src, tick, 0, 0, 0, 0, RK_DEATHBOUND,-1, 1); + rdamage = wd.damage * ((500 + 100*skilllv) / 100); + wd.damage = rdamage * 30 / 100; + status_zap(target, wd.damage, 0); + skill_blown(src, src, skill_get_blewcount(RK_DEATHBOUND,skilllv), unit_getdir(src), 0); + status_change_end(target,SC_DEATHBOUND,INVALID_TIMER); + } + else + rdamage = battle_calc_return_damage(target, damage, wd.flag); + if( rdamage > 0 ) { rdelay = clif_damage(src, src, tick, wd.amotion, sstatus->dmotion, rdamage, 1, 4, 0); @@ -3259,6 +3399,11 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } } } + if (sc && sc->data[SC_CRUSHSTRIKE]) + { + skill_castend_damage_id(src, target, RK_CRUSHSTRIKE, 1, tick, flag); + status_change_end(src,SC_CRUSHSTRIKE, INVALID_TIMER); + } if (sd) { if (wd.flag & BF_WEAPON && src != target && damage > 0) { if (battle_config.left_cardfix_to_right) @@ -4055,10 +4200,13 @@ static const struct _battle_data { { "bg_magic_attack_damage_rate", &battle_config.bg_magic_damage_rate, 60, 0, INT_MAX, }, { "bg_misc_attack_damage_rate", &battle_config.bg_misc_damage_rate, 60, 0, INT_MAX, }, { "bg_flee_penalty", &battle_config.bg_flee_penalty, 20, 0, INT_MAX, }, -//MVP Decrease AGI +// MVP Decrease AGI { "max_decagi_lv", &battle_config.max_decagi_lv, 11, 1, INT_MAX, }, { "max_decagi_dur", &battle_config.max_decagi_dur, 120000, 1, INT_MAX, }, { "max_decagi", &battle_config.max_decagi, 50, 0, INT_MAX, }, +// Third jobs + { "rune_block_by_skill", &battle_config.rune_block_by_skill, 1, 0, 1, }, + { "rune_block_by_status", &battle_config.rune_block_by_status, 0, 0, 1, }, }; diff --git a/src/map/battle.h b/src/map/battle.h index 08a2a46f4..7570f77b7 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -499,6 +499,8 @@ extern struct Battle_Config int max_decagi_lv; int max_decagi_dur; int max_decagi; + int rune_block_by_skill; + int rune_block_by_status; } battle_config; void do_init_battle(void); diff --git a/src/map/clif.c b/src/map/clif.c index db34d30ae..a8cfa48cd 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1193,6 +1193,8 @@ int clif_spawn(struct block_list *bl) clif_specialeffect(bl,421,AREA); if( sd->bg_id && map[sd->bl.m].flag.battleground ) clif_sendbgemblem_area(sd); + if(sd->sc.data[SC_MILLENNIUMSHIELD] && sd->sc.data[SC_MILLENNIUMSHIELD]->val2 > 0) // Ensure that we have shields to display. + clif_millenniumshield(sd,sd->sc.data[SC_MILLENNIUMSHIELD]->val2); } break; case BL_MOB: @@ -3819,8 +3821,8 @@ static int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int da /*========================================== * Sends a 'damage' packet (src performs action on dst) - * R 008a <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.W <div>.W <type>.B <damage2>.W - * R 02e1 <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.L <div>.W <type>.B <damage2>.L + * R 008a <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.W <div>.W <type>.B <damage2>.W (ZC_NOTIFY_ACT) + * R 02e1 <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.L <div>.W <type>.B <damage2>.L (ZC_NOTIFY_ACT2) * * type=00 damage [param1: total damage, param2: div, param3: assassin dual-wield damage] * type=01 pick up item @@ -3834,8 +3836,13 @@ static int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int da *------------------------------------------*/ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tick, int sdelay, int ddelay, int damage, int div, int type, int damage2) { - unsigned char buf[256]; + unsigned char buf[33]; struct status_change *sc; +#if PACKETVER < 20071113 + const int cmd = 0x8a; +#else + const int cmd = 0x2e1; +#endif nullpo_ret(src); nullpo_ret(dst); @@ -3849,12 +3856,13 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic } } - WBUFW(buf,0)=0x8a; + WBUFW(buf,0)=cmd; WBUFL(buf,2)=src->id; WBUFL(buf,6)=dst->id; WBUFL(buf,10)=tick; WBUFL(buf,14)=sdelay; WBUFL(buf,18)=ddelay; +#if PACKETVER < 20071113 if (battle_config.hide_woe_damage && map_flag_gvg(src->m)) { WBUFW(buf,22)=damage?div:0; WBUFW(buf,27)=damage2?div:0; @@ -3864,20 +3872,35 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic } WBUFW(buf,24)=div; WBUFB(buf,26)=type; +#else + if (battle_config.hide_woe_damage && map_flag_gvg(src->m)) { + WBUFL(buf,22)=damage?div:0; + WBUFL(buf,29)=damage2?div:0; + } else { + WBUFL(buf,22)=damage; + WBUFL(buf,29)=damage2; + } + WBUFW(buf,26)=div; + WBUFB(buf,28)=type; +#endif if(disguised(dst)) { - clif_send(buf,packet_len(0x8a),dst,AREA_WOS); + clif_send(buf,packet_len(cmd),dst,AREA_WOS); WBUFL(buf,6) = -dst->id; - clif_send(buf,packet_len(0x8a),dst,SELF); + clif_send(buf,packet_len(cmd),dst,SELF); } else - clif_send(buf,packet_len(0x8a),dst,AREA); + clif_send(buf,packet_len(cmd),dst,AREA); if(disguised(src)) { WBUFL(buf,2) = -src->id; if (disguised(dst)) WBUFL(buf,6) = dst->id; if(damage > 0) WBUFW(buf,22) = -1; +#if PACKETVER < 20071113 if(damage2 > 0) WBUFW(buf,27) = -1; - clif_send(buf,packet_len(0x8a),src,SELF); +#else + if(damage2 > 0) WBUFW(buf,29) = -1; +#endif + clif_send(buf,packet_len(cmd),src,SELF); } //Return adjusted can't walk delay for further processing. return clif_calc_walkdelay(dst,ddelay,type,damage+damage2,div); @@ -8688,6 +8711,9 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if (sd->sc.option&OPTION_RIDING) clif_status_load(&sd->bl, SI_RIDING, 1); + if (sd->sc.option&OPTION_DRAGON) + clif_status_load(&sd->bl, SI_RIDING, 1); + if(sd->status.manner < 0) sc_start(&sd->bl,SC_NOCHAT,100,0,0); @@ -8906,7 +8932,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) return; } - if (sd->sc.opt1 && sd->sc.opt1 == OPT1_STONEWAIT) + if (sd->sc.opt1 && (sd->sc.opt1 == OPT1_STONEWAIT || sd->sc.opt1 == OPT1_BURNING)) ; //You CAN walk on this OPT1 value. else if( sd->progressbar.npc_id ) clif_progressbar_abort(sd); @@ -9156,7 +9182,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, if (sd->sc.count && (sd->sc.data[SC_TRICKDEAD] || sd->sc.data[SC_AUTOCOUNTER] || - sd->sc.data[SC_BLADESTOP])) + sd->sc.data[SC_BLADESTOP] || + sd->sc.data[SC_DEATHBOUND])) return; pc_stop_walking(sd, 1); @@ -9202,7 +9229,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, return; } - if (sd->ud.skilltimer != INVALID_TIMER || sd->sc.opt1) + if (sd->ud.skilltimer != INVALID_TIMER || (sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING)) break; if (sd->sc.count && ( @@ -9498,6 +9525,7 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd) if (sd->sc.count && ( sd->sc.data[SC_AUTOCOUNTER] || sd->sc.data[SC_BLADESTOP] || + sd->sc.data[SC_DEATHBOUND] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM) )) break; @@ -9524,7 +9552,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) return; } - if (sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT) + if (sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING) return; //This flag enables you to use items while in an NPC. [Skotlex] @@ -9563,7 +9591,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd) if(sd->npc_id) { if (sd->npc_id != sd->npc_item_flag) return; - } else if (sd->state.storage_flag || sd->sc.opt1) + } else if (sd->state.storage_flag || (sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING)) ; //You can equip/unequip stuff while storage is open/under status changes else if (pc_cant_act(sd)) return; @@ -9919,7 +9947,7 @@ void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd) void clif_parse_RemoveOption(int fd,struct map_session_data *sd) { //Can only remove Cart/Riding/Falcon. - pc_setoption(sd,sd->sc.option&~(OPTION_CART|OPTION_RIDING|OPTION_FALCON)); + pc_setoption(sd,sd->sc.option&~(OPTION_CART|OPTION_RIDING|OPTION_FALCON|OPTION_DRAGON)); } /*========================================== @@ -14785,6 +14813,19 @@ void clif_search_store_info_click_ack(struct map_session_data* sd, short x, shor WFIFOSET(fd,packet_len(0x83d)); } +// Correct packet for RK_MILLENIUMSHIELD. Shows spirit spheres. +void clif_millenniumshield(struct map_session_data *sd, int num) +{ +#if PACKETVER >= 20081217 + unsigned char buf[10]; + + WBUFW(buf,0)=0x440; + WBUFL(buf,2)=sd->bl.id; + WBUFW(buf,6)=num; + WBUFW(buf,8)=0; + clif_send(buf,packet_len(0x440),&sd->bl,AREA); +#endif +} /// Parse function for packet debugging void clif_parse_debug(int fd,struct map_session_data *sd) @@ -15088,7 +15129,7 @@ static int packetdb_readdb(void) //#0x02C0 0, 0, 0, 0, 0, 30, 30, 0, 0, 3, 0, 65, 4, 71, 10, 0, 0, 0, 0, 0, 29, 0, 6, -1, 10, 10, 3, 0, -1, 32, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 59, 60, 8, + 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 59, 60, 8, 10, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //#0x0300 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -15116,7 +15157,7 @@ static int packetdb_readdb(void) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 25, //#0x0440 - 0, 4, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, 4, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/src/map/clif.h b/src/map/clif.h index 620ba0668..9d1207901 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -626,4 +626,7 @@ void clif_search_store_info_failed(struct map_session_data* sd, unsigned char re void clif_open_search_store_info(struct map_session_data* sd); void clif_search_store_info_click_ack(struct map_session_data* sd, short x, short y); +// Third jobs +void clif_millenniumshield(struct map_session_data *sd, int num); + #endif /* _CLIF_H_ */ diff --git a/src/map/map.c b/src/map/map.c index 39077de6c..a4b419f65 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1584,6 +1584,9 @@ int map_quit(struct map_session_data *sd) status_change_end(&sd->bl, SC_WEIGHT50, INVALID_TIMER); status_change_end(&sd->bl, SC_WEIGHT90, INVALID_TIMER); if (battle_config.debuff_on_logout&1) { + status_change_end(&sd->bl, SC_DECREASEAGI, INVALID_TIMER); + status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER); + status_change_end(&sd->bl, SC_AETERNA, INVALID_TIMER); status_change_end(&sd->bl, SC_ORCISH, INVALID_TIMER); status_change_end(&sd->bl, SC_STRIPWEAPON, INVALID_TIMER); status_change_end(&sd->bl, SC_STRIPARMOR, INVALID_TIMER); @@ -1591,6 +1594,8 @@ int map_quit(struct map_session_data *sd) status_change_end(&sd->bl, SC_STRIPHELM, INVALID_TIMER); status_change_end(&sd->bl, SC_EXTREMITYFIST, INVALID_TIMER); status_change_end(&sd->bl, SC_EXPLOSIONSPIRITS, INVALID_TIMER); + status_change_end(&sd->bl, SC_JOINTBEAT, INVALID_TIMER); + status_change_end(&sd->bl, SC_MINDBREAKER, INVALID_TIMER); if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4) status_change_end(&sd->bl, SC_REGENERATION, INVALID_TIMER); //TO-DO Probably there are way more NPC_type negative status that are removed @@ -1601,12 +1606,61 @@ int map_quit(struct map_session_data *sd) } if (battle_config.debuff_on_logout&2) { + status_change_end(&sd->bl, SC_MAGNIFICAT, INVALID_TIMER); status_change_end(&sd->bl, SC_MAXIMIZEPOWER, INVALID_TIMER); status_change_end(&sd->bl, SC_MAXOVERTHRUST, INVALID_TIMER); + status_change_end(&sd->bl, SC_AURABLADE, INVALID_TIMER); + status_change_end(&sd->bl, SC_PARRYING, INVALID_TIMER); + status_change_end(&sd->bl, SC_CONCENTRATION, INVALID_TIMER); + status_change_end(&sd->bl, SC_TENSIONRELAX, INVALID_TIMER); + status_change_end(&sd->bl, SC_MAGICPOWER, INVALID_TIMER); + status_change_end(&sd->bl, SC_EDP, INVALID_TIMER); + status_change_end(&sd->bl, SC_TRUESIGHT, INVALID_TIMER); + status_change_end(&sd->bl, SC_WINDWALK, INVALID_TIMER); + status_change_end(&sd->bl, SC_MELTDOWN, INVALID_TIMER); + status_change_end(&sd->bl, SC_CARTBOOST, INVALID_TIMER); + status_change_end(&sd->bl, SC_MEMORIZE, INVALID_TIMER); + status_change_end(&sd->bl, SC_DEVOTION, INVALID_TIMER); + status_change_end(&sd->bl, SC_SACRIFICE, INVALID_TIMER); status_change_end(&sd->bl, SC_STEELBODY, INVALID_TIMER); status_change_end(&sd->bl, SC_PRESERVE, INVALID_TIMER); status_change_end(&sd->bl, SC_KAAHI, INVALID_TIMER); + status_change_end(&sd->bl, SC_KAUPE, INVALID_TIMER); + status_change_end(&sd->bl, SC_DOUBLECAST, INVALID_TIMER); + status_change_end(&sd->bl, SC_SHRINK, INVALID_TIMER); + status_change_end(&sd->bl, SC_SIGHTBLASTER, INVALID_TIMER); status_change_end(&sd->bl, SC_SPIRIT, INVALID_TIMER); + status_change_end(&sd->bl, SC_KAITE, INVALID_TIMER); + status_change_end(&sd->bl, SC_UTSUSEMI, INVALID_TIMER); + status_change_end(&sd->bl, SC_BUNSINJYUTSU, INVALID_TIMER); + status_change_end(&sd->bl, SC_SUITON, INVALID_TIMER); + // Third jobs + status_change_end(&sd->bl, SC_MILLENNIUMSHIELD, INVALID_TIMER); + status_change_end(&sd->bl, SC_DEATHBOUND, INVALID_TIMER); + status_change_end(&sd->bl, SC_REFRESH, INVALID_TIMER); + status_change_end(&sd->bl, SC_STONEHARDSKIN, INVALID_TIMER); + //status_change_end(&sd->bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + //status_change_end(&sd->bl, SC_HALLUCINATIONWALK_POSTDELAY, INVALID_TIMER); + //status_change_end(&sd->bl, SC_WEAPONBLOCKING_POSTDELAY, INVALID_TIMER); + //status_change_end(&sd->bl, SC_ROLLINGCUTTER, INVALID_TIMER); + //status_change_end(&sd->bl, SC_ELECTRICSHOCKER, INVALID_TIMER); + //status_change_end(&sd->bl, SC_WUGDASH, INVALID_TIMER); + //status_change_end(&sd->bl, SC_WUGBITE, INVALID_TIMER); + //status_change_end(&sd->bl, SC_CAMOUFLAGE, INVALID_TIMER); + //status_change_end(&sd->bl, SC_MAGNETICFIELD, INVALID_TIMER); + //status_change_end(&sd->bl, SC_NEUTRALBARRIER, INVALID_TIMER); + //status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER); + //status_change_end(&sd->bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER); + //status_change_end(&sd->bl, SC_SHADOWFORM, INVALID_TIMER); + //status_change_end(&sd->bl, SC_INVISIBILITY, INVALID_TIMER); + //status_change_end(&sd->bl, SC_RAISINGDRAGON, INVALID_TIMER); + //status_change_end(&sd->bl, SC_NOEQUIPACCESSARY, INVALID_TIMER); + //status_change_end(&sd->bl, SC_MANHOLE, INVALID_TIMER); + //status_change_end(&sd->bl, SC_PROPERTYWALK, INVALID_TIMER); + //status_change_end(&sd->bl, SC_DEEP_SLEEP, INVALID_TIMER); + //status_change_end(&sd->bl, SC_WARMER, INVALID_TIMER); + //status_change_end(&sd->bl, SC_GN_TRAINING_SWORD, INVALID_TIMER); + //status_change_end(&sd->bl, SC_GN_REMODELING_CART, INVALID_TIMER); } } diff --git a/src/map/mob.c b/src/map/mob.c index 5272b17e8..49ca6eb23 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1311,7 +1311,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) return false; // Abnormalities - if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->sc.data[SC_BLADESTOP]) + if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT && md->sc.opt1 != OPT1_BURNING) || md->sc.data[SC_BLADESTOP]) { //Should reset targets. md->target_id = md->attacked_id = 0; return false; diff --git a/src/map/pc.c b/src/map/pc.c index ff775be07..440c684f4 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -395,7 +395,7 @@ int pc_makesavestatus(struct map_session_data *sd) //Only copy the Cart/Peco/Falcon options, the rest are handled via //status change load/saving. [Skotlex] - sd->status.option = sd->sc.option&(OPTION_CART|OPTION_FALCON|OPTION_RIDING); + sd->status.option = sd->sc.option&(OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON); if (sd->sc.data[SC_JAILED]) { //When Jailed, do not move last point. @@ -3414,7 +3414,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount) if( data->stack.inventory && amount > data->stack.amount ) {// item stack limitation - return 5; + return 7; } w = data->weight*amount; @@ -3694,7 +3694,6 @@ int pc_isUseitem(struct map_session_data *sd,int n) if( nameid == 12243 && sd->md->db->lv < 80 ) return 0; break; - case 12213: //Neuralizer if( !map[sd->bl.m].flag.reset ) return 0; @@ -3704,6 +3703,9 @@ int pc_isUseitem(struct map_session_data *sd,int n) if( nameid >= 12153 && nameid <= 12182 && sd->md != NULL ) return 0; // Mercenary Scrolls + if (nameid >= 12725 && nameid <= 12733 && !pc_isUseitem_check_runeskill(sd, sd->status.inventory[n].nameid) ) + return 0; + //added item_noequip.txt items check by Maya&[Lupus] if ( (!map_flag_vs(sd->bl.m) && item->flag.no_equip&1) || // Normal @@ -3742,6 +3744,45 @@ int pc_isUseitem(struct map_session_data *sd,int n) return 1; } + +int pc_isUseitem_check_runeskill(TBL_PC *sd, int nameid) +{ + struct { + int runeid; + int skillid; + } rune2skill_table[] = { + { 12725, RK_REFRESH }, + { 12726, RK_CRUSHSTRIKE }, + { 12727, RK_MILLENNIUMSHIELD }, + { 12728, RK_VITALITYACTIVATION }, + { 12729, RK_FIGHTINGSPIRIT }, + { 12730, RK_ABUNDANCE }, + { 12731, RK_GIANTGROWTH }, + { 12732, RK_STORMBLAST }, + { 12733, RK_STONEHARDSKIN }, + }; + + int i; + int skillid; + + nullpo_retr(0, sd); + + ARR_FIND(0, ARRAYLENGTH(rune2skill_table), i, rune2skill_table[i].runeid == nameid); + if ( i == ARRAYLENGTH(rune2skill_table) ) { + ShowError("pc_isUseitem_check_runeskill: rune %d skill not found.\n", nameid); + return 0; + } + + skillid = rune2skill_table[i].skillid; + if ( battle_config.rune_block_by_skill && skillnotok(skillid, sd) ) + return 0; + if ( battle_config.rune_block_by_status && status_skill2sc(skillid) != SC_NONE && sd->sc.data[status_skill2sc(skillid)] ) + return 0; + + return 1; +} + + /*========================================== * ƒAƒCƒeƒ€‚ðŽg‚¤ *------------------------------------------*/ @@ -5748,6 +5789,8 @@ int pc_resetskill(struct map_session_data* sd, int flag) i &= ~OPTION_CART; if( i&OPTION_FALCON && pc_checkskill(sd, HT_FALCON) ) i &= ~OPTION_FALCON; + if( i&OPTION_DRAGON && pc_checkskill(sd, KN_RIDING) ) //RK_DRAGONTRAINING not needed for riding (bug?), assuming KN_RIDING is. + i&=~OPTION_DRAGON; if( i != sd->sc.option ) pc_setoption(sd, i); @@ -6522,6 +6565,13 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) sp -= sp * sd->sc.data[SC_CRITICALWOUND]->val2 / 100; } + if (sd->sc.data[SC_VITALITYACTIVATION]) + { + hp += hp * sd->sc.data[SC_VITALITYACTIVATION]->val2 / 100; //HP +50% + sp -= sp * sd->sc.data[SC_VITALITYACTIVATION]->val3 / 100; //SP -50% + } + + return status_heal(&sd->bl, hp, sp, 1); } @@ -6676,6 +6726,8 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) i&=~OPTION_CART; if(i&OPTION_FALCON && !pc_checkskill(sd, HT_FALCON)) i&=~OPTION_FALCON; + if(i&OPTION_DRAGON && !pc_checkskill(sd, KN_RIDING)) //RK_DRAGONTRAINING not needed for riding (bug?), assuming KN_RIDING is. + i&=~OPTION_DRAGON; if(i != sd->sc.option) pc_setoption(sd, i); @@ -6804,12 +6856,16 @@ int pc_setoption(struct map_session_data *sd,int type) sd->sc.option=type; clif_changeoption(&sd->bl); - if (type&OPTION_RIDING && !(p_type&OPTION_RIDING) && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN) + if (((type&OPTION_RIDING && !(p_type&OPTION_RIDING)) // Knight and Crusader/Royal Guard + || (type&OPTION_DRAGON && !(p_type&OPTION_DRAGON))) // Rune Knight Dragon + && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN) { //We are going to mount. [Skotlex] clif_status_load(&sd->bl,SI_RIDING,1); status_calc_pc(sd,0); //Mounting/Umounting affects walk and attack speeds. } - else if (!(type&OPTION_RIDING) && p_type&OPTION_RIDING && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN) + else if (((!(type&OPTION_RIDING) && p_type&OPTION_RIDING) //Knight and Crusader/Royal Guard + || (!(type&OPTION_DRAGON) && p_type&OPTION_DRAGON)) // Rune Knight Dragon + && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN) { //We are going to dismount. clif_status_load(&sd->bl,SI_RIDING,0); status_calc_pc(sd,0); //Mounting/Umounting affects walk and attack speeds. @@ -6927,6 +6983,22 @@ int pc_setriding(TBL_PC* sd, int flag) } /*========================================== + * Enable Riding Dragons for Rune Knight class. + *------------------------------------------*/ +int pc_setdragon(TBL_PC* sd, int flag, int color) +{ + int dragon[5] = {OPTION_DRAGON1,OPTION_DRAGON2,OPTION_DRAGON3,OPTION_DRAGON4,OPTION_DRAGON5}; + + if( flag ){ + if( pc_checkskill(sd,KN_RIDING) > 0 ) //Possible to rent dragons without RK_DRAGONTRAINING; Source, iRO. (Bug?) + pc_setoption(sd, sd->sc.option|dragon[color]); + } else if( pc_isdragon(sd) ){ + pc_setoption(sd, sd->sc.option&~OPTION_DRAGON); + } + + return 0; +} +/*========================================== * ƒAƒCƒeƒ€ƒhƒƒbƒv‰Â•s‰Â”»’è *------------------------------------------*/ int pc_candrop(struct map_session_data *sd,struct item *item) diff --git a/src/map/pc.h b/src/map/pc.h index a49c4628e..4619af878 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -420,6 +420,8 @@ struct map_session_data { unsigned int bg_id; unsigned short user_font; + int produce_itemusedid; //used to determine the type of item used when creating items via script. + // temporary debugging of bug #3504 const char* delunit_prevfile; int delunit_prevline; @@ -526,7 +528,7 @@ enum equip_index { #define pc_issit(sd) ( (sd)->vd.dead_sit == 2 ) #define pc_isidle(sd) ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share ) #define pc_istrading(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading ) -#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || (sd)->sc.opt1 || (sd)->state.trading || (sd)->state.storage_flag ) +#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag ) #define pc_setdir(sd,b,h) ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) ) #define pc_setchatid(sd,n) ( (sd)->chatID = n ) #define pc_ishiding(sd) ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) ) @@ -539,6 +541,7 @@ enum equip_index { #define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle_config.natural_heal_weight_rate ) #define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 ) #define pc_maxparameter(sd) ( ((sd)->class_&JOBL_3 ? ((sd)->class_&JOBL_BABY ? battle_config.max_baby_third_parameter : battle_config.max_third_parameter) : ((sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter)) ) +#define pc_isdragon(sd) ( (sd)->sc.option&OPTION_DRAGON ) #define pc_stop_walking(sd, type) unit_stop_walking(&(sd)->bl, type) #define pc_stop_attack(sd) unit_stop_attack(&(sd)->bl) @@ -664,6 +667,7 @@ int pc_equipitem(struct map_session_data*,int,int); int pc_unequipitem(struct map_session_data*,int,int); int pc_checkitem(struct map_session_data*); int pc_useitem(struct map_session_data*,int); +int pc_isUseitem_check_runeskill(TBL_PC *sd, int nameid); int pc_skillatk_bonus(struct map_session_data *sd, int skill_num); int pc_skillheal_bonus(struct map_session_data *sd, int skill_num); @@ -682,6 +686,7 @@ int pc_setfalcon(struct map_session_data* sd, int flag); int pc_setriding(struct map_session_data* sd, int flag); int pc_changelook(struct map_session_data *,int,int); int pc_equiplookall(struct map_session_data *sd); +int pc_setdragon(struct map_session_data* sd, int flag, int color); int pc_readparam(struct map_session_data*,int); int pc_setparam(struct map_session_data*,int,int); diff --git a/src/map/script.c b/src/map/script.c index 881d2f082..0f3c09e1e 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -7426,7 +7426,7 @@ BUILDIN_FUNC(setoption) flag = script_getnum(st,3); else if( !option ){// Request to remove everything. flag = 0; - option = OPTION_CART|OPTION_FALCON|OPTION_RIDING; + option = OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON; } if( flag ){// Add option if( option&OPTION_WEDDING && !battle_config.wedding_modifydisplay ) @@ -7542,7 +7542,7 @@ BUILDIN_FUNC(checkriding) if( sd == NULL ) return 0;// no player attached, report source - if( pc_isriding(sd) ) + if( pc_isriding(sd) || pc_isdragon(sd) ) script_pushint(st, 1); else script_pushint(st, 0); @@ -7571,6 +7571,31 @@ BUILDIN_FUNC(setriding) return 0; } +/// Sets if the player is riding a dragon. +/// <flag> defaults to 1 +/// <color> defaults to 0 +/// +/// setdragon <flag>{,<color>}; +/// setdragon <flag>; +/// setdragon; +BUILDIN_FUNC(setdragon) +{ + int flag = 1, color = 0; + TBL_PC* sd; + + sd = script_rid2sd(st); + if( sd == NULL ) + return 0;// no player attached, report source + + if( script_hasdata(st,2) ) + flag = script_getnum(st,2); + if( script_hasdata(st,3) ) + color = cap_value(script_getnum(st,3),0,4); + + pc_setdragon(sd, flag, color); + return 0; +} + /// Sets the save point of the player. /// /// save "<map name>",<x>,<y> @@ -7762,6 +7787,28 @@ BUILDIN_FUNC(produce) sd = script_rid2sd(st); if( sd == NULL ) return 0; + + if( script_hasdata(st,3) ) + { // only used with Rune Knights RK_RUNEMASTERY as part of the calculation. + struct item_data* id = NULL; + struct script_data* data; + + data = script_getdata(st,3); + get_val(st, data); + + if( data_isstring(data) ) + id = itemdb_searchname(conv_str(st, data)); + else + id = itemdb_exists(conv_num(st, data)); + + if( id == NULL ) + { + ShowError("buildin_produce: Invalid item '%s'.\n", script_getstr(st,3)); + return 1; + } + else + sd->produce_itemusedid = id->nameid; + } trigger=script_getnum(st,2); clif_skill_produce_mix_list(sd, trigger); @@ -14945,6 +14992,85 @@ BUILDIN_FUNC(searchstores) return 0; } +/// Returns the successful use of a Rune Knight Runestone. +/// +/// SuccessRuneUse() +/// +BUILDIN_FUNC(successruneuse) +{ + struct item_data* id = NULL; + struct map_session_data* sd; + struct script_data* data; + + if( ( sd = script_rid2sd(st) ) == NULL ) + return 0; // no player attached, report source + + data = script_getdata(st,2); + get_val(st, data); // convert into value in case of a variable + + if( data_isstring(data) ) + id = itemdb_searchname(conv_str(st, data)); + else + id = itemdb_exists(conv_num(st, data)); + + if( id == NULL ) + { + ShowError("buildin_successruneuse: Invalid item '%s'.\n", script_getstr(st,2)); + script_pushint(st,0); + return 1; + } + + if( (sd->class_&~(JOBL_UPPER|JOBL_BABY)) == MAPID_RUNE_KNIGHT ) + { + int skilllv = pc_checkskill(sd,RK_RUNEMASTERY); + int i = (sd->status.dex + sd->status.luk ) / 20 + (skilllv?55+skilllv:0) + 30; + + if (rand() % 100 < i) + script_pushint(st, 1); + else + { + script_pushint(st, 0); + + i = rand() % 100; // reroll for fail effects + if( i < 3 ) + { + long damage = (1000 * id->weight) - (sd->battle_status.mdef + sd->battle_status.mdef2); + clif_damage(&sd->bl, &sd->bl, gettick(), 0, 0, damage, 0, 0, 0); + status_damage(&sd->bl, &sd->bl, damage, 0, 0, 0); + } + else if( i < 13 ) + { // Random status effect + struct { + sc_type type; + int duration; + } effects[] = { + { SC_FREEZE, 30000 }, + { SC_STUN, 5000 }, + { SC_SLEEP, 20000 }, + { SC_SILENCE, 20000 }, + { SC_BLIND, 20000 }, + }; + i = rand()%ARRAYLENGTH(effects); // redesignate i to random status effect+duration. + sc_start(&sd->bl, effects[i].type, 100, 1, effects[i].duration); + } + else if( i < 15 ) + pc_randomwarp(sd, CLR_TELEPORT); + else if( i < 18 ) + ; // Unknown effect, however weight of the item used is taken into account. + else if( i < 19 ) + { + if (!status_isimmune(&sd->bl)) + status_percent_heal(&sd->bl, 100, 100); + } + else if( i >= 20 ) + ; // Unknown effect + } + } + else + script_pushint(st, 0); + + return 0; +} // declarations that were supposed to be exported from npc_chat.c #ifdef PCRE_SUPPORT @@ -15054,6 +15180,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(setfalcon,"?"), BUILDIN_DEF(checkfalcon,""), BUILDIN_DEF(setriding,"?"), + BUILDIN_DEF(setdragon,"??"), BUILDIN_DEF(checkriding,""), BUILDIN_DEF2(savepoint,"save","sii"), BUILDIN_DEF(savepoint,"sii"), @@ -15063,7 +15190,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(openstorage,""), BUILDIN_DEF(guildopenstorage,""), BUILDIN_DEF(itemskill,"vi"), - BUILDIN_DEF(produce,"i"), + BUILDIN_DEF(produce,"i?"), BUILDIN_DEF(cooking,"i"), BUILDIN_DEF(monster,"siisii?"), BUILDIN_DEF(getmobdrops,"i"), @@ -15310,6 +15437,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(pushpc,"ii"), BUILDIN_DEF(buyingstore,"i"), BUILDIN_DEF(searchstores,"ii"), + BUILDIN_DEF(successruneuse,"?"), // WoE SE BUILDIN_DEF(agitstart2,""), BUILDIN_DEF(agitend2,""), diff --git a/src/map/skill.c b/src/map/skill.c index 976f50bd4..26d812d86 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -311,7 +311,7 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, int skill // Calculate base heal rate hp = ( ( ( status_get_lv(src) + status_get_int(src) ) / 5) * 30 ) * skill / 10; - // Increment skill and status based modifiers + // Increment heal by skill/type modifiers if( sd && ((skill = pc_checkskill(sd, HP_MEDITATIO)) > 0) ) mod += skill * 2; else if( src->type == BL_HOM && (skill = merc_hom_checkskill(((TBL_HOM*)src), HLIF_BRAIN)) > 0 ) @@ -319,7 +319,7 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, int skill break; } - // Increment skill and status based modifiers + // Increment heal by item-based modifiers if( sd && (skill = pc_skillheal_bonus(sd, skill_id)) ) mod += skill; if( tsd && (skill = pc_skillheal2_bonus(tsd, skill_id)) ) @@ -332,8 +332,8 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, int skill mod -= sc->data[SC_CRITICALWOUND]->val2; if( sc->data[SC_INCHEALRATE] && skill_id != NPC_EVILLAND && skill_id != BA_APPLEIDUN ) mod += sc->data[SC_INCHEALRATE]->val1; // Only affects Heal, Sanctuary and PotionPitcher.(like bHealPower) [Inkfish] -// if( sc->data[SC_VITALITYACTIVATION] && heal && skill_id != BA_APPLEIDUN ) -// mod += sc->data[SC_VITALITYACTIVATION]->val2; + if( sc->data[SC_VITALITYACTIVATION] && heal && skill_id != BA_APPLEIDUN ) + mod += sc->data[SC_VITALITYACTIVATION]->val2; } // Adjust the HP recovered rate by adding all of the modifiers together. @@ -981,9 +981,19 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int case NPC_CRITICALWOUND: sc_start(bl,SC_CRITICALWOUND,100,skilllv,skill_get_time2(skillid,skilllv)); break; + case RK_WINDCUTTER: + sc_start(bl,SC_FEAR,3+2*skilllv,skilllv,skill_get_time(skillid,skilllv)); + break; + case RK_DRAGONBREATH: + sc_start4(bl,SC_BURNING,15,skilllv,src->id,0,0,skill_get_time(skillid,skilllv)); + break; case AB_ADORAMUS: - sc_start(bl, SC_BLIND, 100, skilllv, skill_get_time(skillid, skilllv)); - sc_start(bl, SC_ADORAMUS, 100, skilllv, skill_get_time2(skillid, skilllv)); + if ( sd ) + { + int rate = (skilllv*4) + sd->status.job_level / 2; + sc_start(bl, SC_BLIND, rate, skilllv, skill_get_time(skillid, skilllv)); + sc_start(bl, SC_ADORAMUS, rate, skilllv, skill_get_time2(skillid, skilllv)); + } break; } @@ -1734,8 +1744,19 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if( damage > 0 && dmg.flag&BF_WEAPON && src != bl && ( src == dsrc || ( dsrc->type == BL_SKILL && ( skillid == SG_SUN_WARM || skillid == SG_MOON_WARM || skillid == SG_STAR_WARM ) ) ) && skillid != WS_CARTTERMINATION ) - rdamage = battle_calc_return_damage(bl, damage, dmg.flag); - + { + if( sc && sc->data[SC_DEATHBOUND] && !is_boss(bl) && map_check_dir(map_calc_dir(src,bl->x,bl->y),unit_getdir(bl))) + { + int skilllv = sc->data[SC_DEATHBOUND]->val1; + clif_skill_damage(src,src, tick, 0, 0, 0, 0, RK_DEATHBOUND,-1, 1); + rdamage = damage * ((500 + 100*skilllv) / 100); + damage = rdamage * 70 / 100; + skill_blown(src, src, skill_get_blewcount(skillid,skilllv), unit_getdir(src), 0); + status_change_end(dsrc,SC_DEATHBOUND,INVALID_TIMER); + } + else + rdamage = battle_calc_return_damage(bl, damage, dmg.flag); + } //Skill hit type type=(skillid==0)?5:skill_get_hit(skillid); @@ -1851,6 +1872,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case NPC_CRITICALSLASH: case TF_DOUBLE: case GS_CHAINACTION: + case RK_DEATHBOUND: dmg.dmotion = clif_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,dmg.type,dmg.damage2); break; @@ -1994,6 +2016,9 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds skill_additional_effect(bl, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); } + if( damage > 0 && skillid == RK_CRUSHSTRIKE ) + skill_break_equip(src,EQP_WEAPON,2000,BCT_SELF); + if (!(flag&2) && ( skillid == MG_COLDBOLT || skillid == MG_FIREBOLT || skillid == MG_LIGHTNINGBOLT @@ -2402,6 +2427,16 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) } } break; + case RK_HUNDREDSPEAR: + if(src->type == BL_PC) + { + int skill_lv = pc_checkskill((struct map_session_data *)src,KN_SPEARBOOMERANG); + if(skill_lv > 0) + skill_attack(BF_WEAPON,src,src,target,KN_SPEARBOOMERANG,skill_lv,tick,skl->flag); + } + else + skill_attack(BF_WEAPON,src,src,target,KN_SPEARBOOMERANG,1,tick,skl->flag); + break; default: skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); break; @@ -2625,6 +2660,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NPC_BLEEDING: case NPC_CRITICALWOUND: case NPC_HELLPOWER: + case RK_SONICWAVE: + case RK_WINDCUTTER: case AB_DUPLELIGHT_MELEE: skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); break; @@ -3068,6 +3105,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NPC_SMOKING: case GS_FLING: case NJ_ZENYNAGE: + case RK_DRAGONBREATH: skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag); break; @@ -3124,6 +3162,18 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int status_change_end(src, SC_HIDING, INVALID_TIMER); skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); break; + + case RK_HUNDREDSPEAR: + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + if(rand()%100 < (10 + 3*skilllv)) { + skill_blown(src,bl,6,-1,0); + skill_addtimerskill(src,tick+800,bl->id,0,0,skillid,skilllv,BF_WEAPON,flag); + } + break; + case RK_CRUSHSTRIKE: + if( sd ) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + break; case 0: if(sd) { if (flag & 3){ @@ -3371,9 +3421,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case AL_DECAGI: case MER_DECAGI: - if (skilllv >= battle_config.max_decagi_lv) + if (skilllv = battle_config.max_decagi_lv) clif_skill_nodamage (src, bl, skillid, skilllv, - sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), (battle_config.max_decagi - 2), (battle_config.max_decagi_dur * 100))); + sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), (battle_config.max_decagi - 2), battle_config.max_decagi_dur)); else clif_skill_nodamage (src, bl, skillid, skilllv, sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), skilllv, skill_get_time(skillid,skilllv))); @@ -3729,6 +3779,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case ST_PRESERVE: case NPC_INVINCIBLE: case NPC_INVINCIBLEOFF: + case RK_DEATHBOUND: + case RK_MILLENNIUMSHIELD: + case RK_CRUSHSTRIKE: + case RK_GIANTGROWTH: + case RK_STONEHARDSKIN: + case RK_VITALITYACTIVATION: + case RK_ABUNDANCE: case AB_RENOVATIO: case AB_EXPIATIO: case AB_DUPLELIGHT: @@ -4099,6 +4156,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case BS_ADRENALINE2: case BS_WEAPONPERFECT: case BS_OVERTHRUST: + case RK_FIGHTINGSPIRIT: //Splash range in skill_db is 0, should be map-wide according to party_foreachsamemap if (sd == NULL || sd->status.party_id == 0 || (flag & 1)) { clif_skill_nodamage(bl,bl,skillid,skilllv, sc_start2(bl,type,100,skilllv,(src == bl)? 1:0,skill_get_time(skillid,skilllv))); @@ -5743,6 +5801,74 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_skill_nodamage(src, bl, skillid, skilllv, buyingstore_setup(sd, MAX_BUYINGSTORE_SLOTS)); } break; + case RK_ENCHANTBLADE: + i = status_get_int(src) + status_get_lv(src) / 10; + clif_skill_nodamage(src,bl,skillid,skilllv, + sc_start(bl,type,100,i,skill_get_time(skillid,skilllv))); + break; + case RK_IGNITIONBREAK: + if(flag&1) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + else + { + clif_skill_nodamage(src,bl,skillid,skilllv,1); + map_foreachinrange(skill_area_sub, bl, + skill_get_splash(skillid, skilllv),BL_CHAR, + src,skillid,skilllv,tick, flag|BCT_ENEMY|1, + skill_castend_nodamage_id); + } + break; + case RK_DRAGONHOWLING: + if(flag&1) + sc_start(bl,SC_FEAR,50 + skilllv * 6,skilllv,skill_get_time2(skillid,skilllv)); + else + { + clif_skill_nodamage(src,bl,skillid,skilllv,1); + map_foreachinrange(skill_area_sub, bl, + skill_get_splash(skillid, skilllv),BL_CHAR, + src,skillid,skilllv,tick, flag|BCT_ENEMY|1, + skill_castend_nodamage_id); + } + break; + case RK_REFRESH: + { + int heal = sstatus->max_hp * 25 / 100; + status_heal(bl,heal,0,0); + clif_skill_nodamage(src,bl,skillid,skilllv, + sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); + status_change_clear_buffs(bl,6); + } + break; + case RK_STORMBLAST: + if( flag&1 ) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + else + { + clif_skill_nodamage(src,bl,skillid,skilllv,1); + map_foreachinrange(skill_area_sub, bl, + skill_get_splash(skillid, skilllv),BL_CHAR, + src,skillid,skilllv,tick, flag|BCT_ENEMY|1, + skill_castend_nodamage_id); + } + break; + case RK_PHANTOMTHRUST: + if(battle_check_target(src,bl,BCT_ENEMY) > 0 || battle_check_target(src,bl,BCT_PARTY) > 0) + { + if(!map[bl->m].flag.gvg && !map[bl->m].flag.battleground && !(status_get_mode(bl)&MD_BOSS)) + { + int x = 0, y = 0; + if(bl->x > src->x) x = 1; + else if(bl->x < src->x) x = -1; + if(bl->y >= src->y) y = 1; + else if(bl->y < src->y) y = -1; + unit_movepos(bl, src->x+x, src->y+y, 1, 0); + clif_slide(bl,src->x+x, src->y+y); + } + clif_skill_nodamage(src,bl,skillid,skilllv,1); + if (battle_check_target(src,bl,BCT_ENEMY) > 0 ) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + } + break; case AB_ANCILLA: if(sd) { if (skill_produce_mix(sd, skillid, 12333, 0, 0, 0, 1)) @@ -5774,6 +5900,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in int heal = skill_calc_heal(src, bl, AL_HEAL, lv, true); if( status_isimmune(bl) ) heal = 0; + + if( sd->status.party_id && (i = party_foreachsamemap(party_sub_count, sd, 0)) > 1 ) + heal += ((heal / 100) * (i * 10) / 4); + clif_skill_nodamage(bl, bl, skillid, heal, 1); status_heal(bl, heal, 0, 0); } @@ -5786,15 +5916,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in { if( dstsd && dstsd->special_state.no_magic_damage ) break; - clif_skill_nodamage(bl, bl, skillid, skilllv, - sc_start4(bl, type, 100, skilllv, 0, 0, 1, skill_get_time(skillid, skilllv))); + + if ( sd && sd->status.party_id && (i = party_foreachsamemap(party_sub_count, sd, 0)) > 0) + { + clif_skill_nodamage(bl, bl, skillid, skilllv, + sc_start4(bl, type, 100, skilllv, 0, 0, i, skill_get_time(skillid, skilllv))); + } } else party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); break; case AB_ORATIO: if (flag&1) - sc_start(bl, type, 40+skilllv*5, skilllv, skill_get_time(skillid, skilllv)); + sc_start(bl, type, 40+5*skilllv, skilllv, skill_get_time(skillid, skilllv)); else { clif_skill_nodamage(src, bl, skillid, skilllv, 1); @@ -5808,30 +5942,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case AB_LAUDARAMUS: if( (flag&1) || sd == NULL || sd->status.party_id == 0 ) { - if( tsc && (rand()%100 < 30+5*skilllv) ) + if( tsc && (rand()%100 < 40+10*skilllv) ) { switch(skillid) { case AB_LAUDAAGNUS: - if( tsc->data[SC_STONE] || tsc->data[SC_FREEZE] || tsc->data[SC_BLIND] ) + if( tsc->data[SC_STONE] || tsc->data[SC_FREEZE] || tsc->data[SC_BLIND] ) //TODO: Freezing, Crystallization and Burning { status_change_end(bl, SC_STONE, INVALID_TIMER); status_change_end(bl, SC_FREEZE, INVALID_TIMER); status_change_end(bl, SC_BLIND, INVALID_TIMER); } + else + clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv))); break; case AB_LAUDARAMUS: - if( tsc->data[SC_STUN] || tsc->data[SC_SLEEP] || tsc->data[SC_SILENCE] ) + if( tsc->data[SC_STUN] || tsc->data[SC_SLEEP] || tsc->data[SC_SILENCE] ) // TODO: Howling of Mandragora, and Deep Sleep { status_change_end(bl, SC_STUN, INVALID_TIMER); status_change_end(bl, SC_SLEEP, INVALID_TIMER); status_change_end(bl, SC_SILENCE, INVALID_TIMER); } + else + clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv))); break; } } - clif_skill_nodamage(bl, bl, skillid, skilllv, - sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv))); } else if( sd ) party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), @@ -5839,7 +5975,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case AB_CLEARANCE: clif_skill_nodamage(src,bl,skillid,skilllv,1); - if( rand()%100 >= 50+10*skilllv ) + if( rand()%100 >= 60+10*skilllv ) { if (sd) clif_skill_fail(sd,skillid,0,0); @@ -5903,7 +6039,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case SC_ASSNCROS: case SC_POEMBRAGI: case SC_APPLEIDUN: case SC_HUMMING: case SC_DONTFORGETME: case SC_FORTUNE: case SC_SERVICE4U: case SC_PARTYFLEE: /*case SC_ANGEL_PROTECT:*/ - case SC_EPICLESIS: + case SC_EPICLESIS: case SC_DEATHBOUND: case SC_FIGHTINGSPIRIT: + case SC_ABUNDANCE: case SC_MILLENNIUMSHIELD: // not implemented //case SC_BUCHEDENOEL: case SC_POPECOOKIE: //case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: case SC_MINOR_BBQ: @@ -6801,6 +6938,23 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk } break; + case RK_WINDCUTTER: + i = skill_get_splash(skillid, skilllv); + clif_skill_damage(src, src, tick, 0, 0, -1, 1, skillid, -1, 0); + map_foreachinarea(skill_area_sub, + src->m,x-i,y-i,x+i,y+i,(BL_CHAR|BL_SKILL), + src,skillid,skilllv,tick,flag|BCT_ENEMY|1, + skill_castend_damage_id); + break; + + case RK_DRAGONBREATH: + i = skill_get_splash(skillid, skilllv); + map_foreachinarea(skill_area_sub, + src->m,x-i,y-i,x+i,y+i,(BL_CHAR|BL_SKILL), + src,skillid,skilllv,tick,flag|BCT_ENEMY|1, + skill_castend_damage_id); + break; + case AB_EPICLESIS: if( skill_unitsetting(src, skillid, skilllv, x, y, 0) ) { @@ -6862,7 +7016,8 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char sd->sc.data[SC_DANCING] || sd->sc.data[SC_BERSERK] || sd->sc.data[SC_BASILICA] || - sd->sc.data[SC_MARIONETTE] + sd->sc.data[SC_MARIONETTE] || + sd->sc.data[SC_DEATHBOUND] )) { skill_failed(sd); return 0; @@ -8960,13 +9115,13 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh clif_skill_fail(sd,skill,0,0); return 0; break; -/* case ST_DRAGON: if(!pc_isdragon(sd)) { clif_skill_fail(sd,skill,25,0); return 0; } break; +/* case ST_WARG: if(!pc_iswarg(sd)) { clif_skill_fail(sd,skill,0,0); @@ -11274,12 +11429,32 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in } } + if(skill_id == RK_RUNEMASTERY) + { // Now we figure out how many runes we're going to make. :3 + int skill_lv = pc_checkskill(sd,skill_id); + if( skill_lv > 4 && skill_lv < 10) // level 5~9 can make 1~2 runes + qty=(rand()%2)+1; + else if( skill_lv == 10 ) // Level 10 can make 1~3 runes + qty=(rand()%3)+1; + + // Check to see if the amount of runes will exceed 20. + i = pc_search_inventory(sd,nameid); + if( i >= 0 && sd->status.inventory[i].amount+qty > 20 ) // Cancel creation if created stones will exceed 20. + { + clif_msg(sd,0x61b); + return 0; + } + } + for(i=0;i<MAX_PRODUCE_RESOURCE;i++){ int j,id,x; if( (id=skill_produce_db[idx].mat_id[i]) <= 0 ) continue; num++; - x=qty*skill_produce_db[idx].mat_amount[i]; + if (skill_id == RK_RUNEMASTERY) + x=skill_produce_db[idx].mat_amount[i]; // RK_RUNEMASTERY only uses one set of required items, even if making more than 1 item + else + x=qty*skill_produce_db[idx].mat_amount[i]; do{ int y=0; j = pc_search_inventory(sd,id); @@ -11372,8 +11547,57 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in make_per = make_per * battle_config.pp_rate / 100; break; case SA_CREATECON: // Elemental Converter Creation + case AB_ANCILLA: // Ancilla Creation make_per = 100000; // should be 100% success rate break; + case RK_RUNEMASTERY: //Information from iROWiki and RuneItemInfo.lua + { + int skill_lv = pc_checkskill(sd,skill_id); + + make_per = 5100 + 20 * skill_lv; // Base chance. + + //Take stats into account before applying non-modified values. + make_per += (status->dex / 30 + status->luk / 10) + sd->status.job_level / 10 * 100; + + switch(sd->produce_itemusedid) + { // Add success rate based on what type of stone is used. + case 12737: + make_per += 200; break; + case 12734: + make_per += 500; break; + case 12738: + make_per += 800; break; + case 12735: + make_per += 1100; break; + case 12736: + make_per += 1400; break; + default: + break; + } + sd->produce_itemusedid = 0; + + switch(nameid) + { // Reduce success rate based on what rank stone we're making. + case 12727: // Runstone_Verkana + make_per -= 2000; // S Class + break; + case 12725: // Runstone_Nosiege + case 12730: // Runstone_Urj + make_per -= 1500; // A Rank + break; + case 12728: // Runstone_Isia + case 12732: // Runstone_Pertz + make_per -= 1000; // B Rank + break; + case 12726: // Runstone_Rhydo + case 12729: // Runstone_Asir + case 12731: // Runstone_Turisus + case 12733: // Runstone_Hagalas + make_per -= 500; // C Rank + break; + } + break; + } default: if (sd->menuskill_id == AM_PHARMACY && sd->menuskill_val > 10 && sd->menuskill_val <= 20) @@ -11412,7 +11636,6 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in if(make_per < 1) make_per = 1; - if(rand()%10000 < make_per || qty > 1){ //Success, or crafting multiple items. struct item tmp_item; memset(&tmp_item,0,sizeof(tmp_item)); @@ -11512,6 +11735,7 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in case AM_TWILIGHT2: case AM_TWILIGHT3: case ASC_CDP: + case RK_RUNEMASTERY: clif_produceeffect(sd,2,nameid); clif_misceffect(&sd->bl,5); break; @@ -11565,6 +11789,10 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in clif_produceeffect(sd,1,nameid); clif_misceffect(&sd->bl,2); break; + case RK_RUNEMASTERY: + clif_produceeffect(sd,3,nameid); + clif_misceffect(&sd->bl,6); + break; default: if( skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20 ) { //Cooking items. diff --git a/src/map/status.c b/src/map/status.c index cf3d17228..f704ee0d6 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -413,6 +413,17 @@ void initChangeTables(void) add_sc( SA_ELEMENTGROUND , SC_ELEMENTALCHANGE ); add_sc( SA_ELEMENTWIND , SC_ELEMENTALCHANGE ); + set_sc( RK_ENCHANTBLADE , SC_ENCHANTBLADE , SI_ENCHANTBLADE , SCB_NONE ); + set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SI_DEATHBOUND , SCB_NONE ); + set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_BLANK , SCB_NONE ); + set_sc( RK_CRUSHSTRIKE , SC_CRUSHSTRIKE , SI_CRUSHSTRIKE , SCB_NONE ); + set_sc( RK_REFRESH , SC_REFRESH , SI_REFRESH , SCB_NONE ); + set_sc( RK_GIANTGROWTH , SC_GIANTGROWTH , SI_GIANTGROWTH , SCB_STR ); + set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SI_STONEHARDSKIN , SCB_DEF2|SCB_MDEF2 ); + set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION , SI_VITALITYACTIVATION , SCB_REGEN ); + set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SI_FIGHTINGSPIRIT , SCB_ASPD ); + set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SI_ABUNDANCE , SCB_NONE ); + set_sc( AB_ADORAMUS , SC_ADORAMUS , SI_ADORAMUS , SCB_AGI|SCB_SPEED ); add_sc( AB_CLEMENTIA , SC_BLESSING ); add_sc( AB_CANTO , SC_INCREASEAGI ); @@ -503,7 +514,7 @@ void initChangeTables(void) StatusIconChangeTable[SC_SPL_DEF] = SI_SPL_DEF; StatusIconChangeTable[SC_MANU_MATK] = SI_MANU_MATK; StatusIconChangeTable[SC_SPL_MATK] = SI_SPL_MATK; - //StatusIconChangeTable[SC_MOVHASTE_INFINITY] = SI_MOVHASTE_INFINITY; // Causes client to crash when mousing over state icon? + //Cash Items StatusIconChangeTable[SC_FOOD_STR_CASH] = SI_FOOD_STR_CASH; StatusIconChangeTable[SC_FOOD_AGI_CASH] = SI_FOOD_AGI_CASH; @@ -575,7 +586,7 @@ void initChangeTables(void) StatusChangeFlagTable[SC_SPCOST_RATE] |= SCB_ALL; StatusChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED; StatusChangeFlagTable[SC_ITEMSCRIPT] |= SCB_ALL; - //StatusChangeFlagTable[SC_MOVHASTE_INFINITY] = SCB_SPEED; + StatusChangeFlagTable[SC_FEAR] |= SCB_HIT|SCB_FLEE; // Cash Items StatusChangeFlagTable[SC_FOOD_STR_CASH] = SCB_STR; @@ -906,6 +917,9 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag) } if(sp) { + if (sc && sc->data[SC_BERSERK] && sc->data[SC_ABUNDANCE]) // SP does not regenerate during Frenzy. + sp = 0; + if((unsigned int)sp > status->max_sp - status->sp) sp = status->max_sp - status->sp; } @@ -1758,7 +1772,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100; sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100; sd->regen.state.block = 0; - sd->fixedcastrate=0; + sd->fixedcastrate=100; sd->weapon_matk = 0; sd->equipment_matk = 0; @@ -1804,7 +1818,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first) status->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK); status->size = (sd->class_&JOBL_BABY)?0:1; - if (battle_config.character_size && pc_isriding(sd)) { //[Lupus] + if (battle_config.character_size && (pc_isriding(sd) || pc_isdragon(sd))) { //[Lupus] if (sd->class_&JOBL_BABY) { if (battle_config.character_size&2) status->size++; @@ -2089,7 +2103,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->left_weapon.atkmods[1] = atkmods[1][sd->weapontype2]; sd->left_weapon.atkmods[2] = atkmods[2][sd->weapontype2]; - if(pc_isriding(sd) && + if((pc_isriding(sd) || pc_isdragon(sd)) && (sd->status.weapon==W_1HSPEAR || sd->status.weapon==W_2HSPEAR)) { //When Riding with spear, damage modifier to mid-class becomes //same as versus large size. @@ -2348,7 +2362,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first) status->aspd_rate -= ((skill+1)/2) * 10; if(pc_isriding(sd)) status->aspd_rate += 500-100*pc_checkskill(sd,KN_CAVALIERMASTERY); - + if(pc_isdragon(sd)) + status->aspd_rate += 750-75*pc_checkskill(sd,RK_DRAGONTRAINING); // Officiak is rumoured to be 75+5*skilllv...giving you 125% ASPD? status->adelay = 2*status->amotion; @@ -2366,6 +2381,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->max_weight += 2000*skill; if(pc_isriding(sd) && pc_checkskill(sd,KN_RIDING)>0) sd->max_weight += 10000; + if(pc_isdragon(sd) && (skill=pc_checkskill(sd,RK_DRAGONTRAINING))>0) + sd->max_weight += 5000+2000*skill; //+200 weight per level of RK_DRAGINTRAINING if(sc->data[SC_KNOWLEDGE]) sd->max_weight += sd->max_weight*sc->data[SC_KNOWLEDGE]->val1/10; if((skill=pc_checkskill(sd,ALL_INCCARRY))>0) @@ -2775,6 +2792,8 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str } else regen->flag&=~sce->val4; //Remove regen as specified by val4 } + if( sc->data[SC_VITALITYACTIVATION] ) + regen->flag &=~RGN_SP; } /// Recalculates parts of an object's battle status according to the specified flags. @@ -3324,6 +3343,8 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang str += ((sc->data[SC_MARIONETTE2]->val3)>>16)&0xFF; if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && str < 50) str = 50; + if(sc->data[SC_GIANTGROWTH]) + str += 30; return (unsigned short)cap_value(str,0,USHRT_MAX); } @@ -3658,6 +3679,8 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change hit += 20; // RockmanEXE; changed based on updated [Reddozen] if(sc->data[SC_MERC_HITUP]) hit += sc->data[SC_MERC_HITUP]->val2; + if(sc->data[SC_FEAR]) + hit -= hit * 20/100; return (short)cap_value(hit,1,SHRT_MAX); } @@ -3707,6 +3730,8 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change flee += sc->data[SC_PARTYFLEE]->val1 * 10; if(sc->data[SC_MERC_FLEEUP]) flee += sc->data[SC_MERC_FLEEUP]->val2; + if(sc->data[SC_FEAR]) + flee -= flee * 20/100; return (short)cap_value(flee,1,SHRT_MAX); } @@ -3795,6 +3820,8 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change + def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST ? 25 : 0 ) / 100; if(sc->data[SC_FLING]) def2 -= def2 * (sc->data[SC_FLING]->val3)/100; + if (sc->data[SC_STONEHARDSKIN]) + def2 += sc->data[SC_STONEHARDSKIN]->val3; return (short)cap_value(def2,1,SHRT_MAX); } @@ -3835,6 +3862,8 @@ static signed short status_calc_mdef2(struct block_list *bl, struct status_chang return 0; if(sc->data[SC_MINDBREAKER]) mdef2 -= mdef2 * sc->data[SC_MINDBREAKER]->val3/100; + if (sc->data[SC_STONEHARDSKIN]) + mdef2 += sc->data[SC_STONEHARDSKIN]->val3; return (short)cap_value(mdef2,1,SHRT_MAX); } @@ -3864,6 +3893,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha else if( sd && pc_isriding(sd) ) val = 25; + if( sd && pc_isdragon(sd) ) + val = 25; speed_rate -= val; } @@ -3946,8 +3977,6 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, 10 * sc->data[SC_AVOID]->val1 ); if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) val = max( val, 75 ); - //if( sc->data[SC_MOVHASTE_INFINITY] ) - // val = max( val, 25 ); //FIXME: official items use a single bonus for this [ultramage] if( sc->data[SC_SPEEDUP0] ) // temporary item-based speedup @@ -4078,6 +4107,9 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * if( sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE ) aspd_rate += 100; } + if(sc->data[SC_FIGHTINGSPIRIT]) + aspd_rate -= sc->data[SC_FIGHTINGSPIRIT]->val3; + return (short)cap_value(aspd_rate,0,SHRT_MAX); } @@ -4857,6 +4889,34 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( !sc ) return 0; //Unable to receive status changes + if( sc->data[SC_REFRESH] ) + { + if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX && type != SC_STUN ) // Immune to all common status ailments except stun (iROWiki) + return 0; + switch( type ) + { + case SC_FEAR: + case SC_BURNING: + // Not implemented yet. (kRO 3-x balance update) + //case SC_POISONINGWEAPON: + //case SC_TOXIN: + //case SC_PARALYSE: + //case SC_VENOMBLEED: + //case SC_MAGICMUSHROOM: + //case SC_DEATHHURT: + //case SC_PYREXIA: + //case SC_OBLIVIONCURSE: + //case SC_LEECHESEND: + //case SC_FROSTMISTY: + //case SC_MARSHOFABYSS: + //case SC_DEEP_SLEEP: + //case SC_COLD: + //case SC_FREEZE_SP: + //case SC_MANDRAGORA: + return 0; + } + } + if( status_isdead(bl) ) return 0; @@ -4887,6 +4947,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val return 0; case SC_SLEEP: case SC_STUN: + case SC_BURNING: if (sc->opt1) return 0; //Cannot override other opt1 status changes. [Skotlex] break; @@ -5251,6 +5312,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_FOOD_LUK_CASH: status_change_end(bl, SC_LUKFOOD, INVALID_TIMER); break; + case SC_FIGHTINGSPIRIT: + if (sc->data[SC_FIGHTINGSPIRIT]) + status_change_end(bl, SC_FIGHTINGSPIRIT, INVALID_TIMER); + break; } //Check for overlapping fails @@ -5290,6 +5355,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_MARIONETTE2: case SC_NOCHAT: case SC_CHANGE: //Otherwise your Hp/Sp would get refilled while still within effect of the last invocation. + case SC_FEAR: + case SC_BURNING: return 0; case SC_COMBO: case SC_DANCING: @@ -5399,12 +5466,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_KYRIE: val2 = status->max_hp * (val1 * 2 + 10) / 100; //%Max HP to absorb - // val4 determines if status is casued by Kyrie or Praefatio, - // as Praefatio blocks more hits than Kyrie Elesion. - if( !val4 ) //== PR_KYRIE + // val4 holds current about of party memebers when casting AB_PRAEFATIO, + // as Praefatio's barrier has more health and blocks more hits than Kyrie Elesion. + if( val4 < 1 ) //== PR_KYRIE val3 = (val1 / 2 + 5); - else //== AB_PRAEFATIO + else + { //== AB_PRAEFATIO + val2 += val4 * 2; //Increase barrier strength per party member. val3 = 6 + val1; + } if( sd ) val1 = min(val1,pc_checkskill(sd,PR_KYRIE)); // use skill level to determine barrier health. break; @@ -6143,6 +6213,34 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_KAIZEL: val2 = 10*val1; //% of life to be revived with break; + case SC_MILLENNIUMSHIELD: + val2 = (rand()%100<20) ? 4 : ((rand()%100<30) ? 3 : ((rand()%100<50) ? 2 : 0)); // 20% for 4, 30% for 3, 50% for 2 + val3 = 1000; // Initial Sheild health. (Additional sheilds health are set in battle.c when shield is broken.) + if( sd && val2 > 0) + clif_millenniumshield(sd,val2); + break; + case SC_STONEHARDSKIN: + val2 = (status->hp * 20 / 100); + if( val2 > 0 ) + status_heal(bl, -val2, 0, 0); // Reduce health by 20% + if ( sd ) + val3 = (sd->status.job_level * pc_checkskill(sd,RK_RUNEMASTERY)) / 4; + break; + case SC_VITALITYACTIVATION: + val2 = 50; // Increase HP recovery effects by 50% + val3 = 50; // Reduce SP recovery effects by 50% + break; + case SC_FIGHTINGSPIRIT: // attack is handled in battle.c + //val2 holds the source of the skill (1 = caster, 0 = party member.) + //official ASPD bonus appears to be (Rune Mastery Level / 10 x 4). + val3 = 10 * (sd?pc_checkskill(sd,RK_RUNEMASTERY):1); //Kind of dirty means to implement 4aspd increase. + break; + case SC_ABUNDANCE: + val3 = tick / 10000; + if(val3 < 1) + val3 = 1; + tick = 10000; + break; case SC_EPICLESIS: val2 = 5 * val1; // % HP gained * level of Epiclesis cast. break; @@ -6161,13 +6259,24 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 5*val1; // DEF reduced by 5*Skill Level percent. break; case SC_DUPLELIGHT: - val2 = 10+val1*2; //Chance of MELEE proc - val3 = 10+val1*2; //Chance of MAGIC proc + val2 = 10+2*val1; //Chance of MELEE proc + val3 = 10+2*val1; //Chance of MAGIC proc break; case SC_AB_SECRAMENT: val2 = 10*val1; //Fixed cast time reduced by 10*Skill Level break; + case SC_FEAR: + if (tick < 2000) + val3 = 2000; + else + val3 = tick - 2000; + tick = 2000; + break; + case SC_BURNING: + val4 = tick/2000; + tick = 3000; + break; // case SC_ARMOR_ELEMENT: // case SC_ARMOR_RESIST: // Mod your resistance against elements: @@ -6232,6 +6341,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_STUN: case SC_SLEEP: case SC_STONE: + case SC_BURNING: if (sd && pc_issit(sd)) //Avoid sprite sync problems. pc_setstand(sd); case SC_TRICKDEAD: @@ -6246,6 +6356,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_CLOSECONFINE2: case SC_ANKLE: case SC_SPIDERWEB: + case SC_FEAR: unit_stop_walking(bl,1); break; case SC_HIDING: @@ -6265,10 +6376,11 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val switch(type) { //OPT1 - case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break; - case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break; - case SC_STUN: sc->opt1 = OPT1_STUN; break; - case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break; + case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break; + case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break; + case SC_STUN: sc->opt1 = OPT1_STUN; break; + case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break; + case SC_BURNING: sc->opt1 = OPT1_BURNING; break; //OPT2 case SC_POISON: sc->opt2 |= OPT2_POISON; break; case SC_CURSE: sc->opt2 |= OPT2_CURSE; break; @@ -6278,6 +6390,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_ANGELUS: sc->opt2 |= OPT2_ANGELUS; break; case SC_BLEEDING: sc->opt2 |= OPT2_BLEEDING; break; case SC_DPOISON: sc->opt2 |= OPT2_DPOISON; break; + case SC_FEAR: sc->opt2 |= OPT2_FEAR; break; //OPT3 case SC_TWOHANDQUICKEN: case SC_ONEHAND: @@ -6612,7 +6725,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const return 0; if (tid == INVALID_TIMER) { - if( (type == SC_ENDURE /*|| type == SC_MOVHASTE_INFINITY*/ ) && sce->val4 ) + if( (type == SC_ENDURE) && sce->val4 ) //Do not end infinite endure or speed adjustment. return 0; if (sce->timer != INVALID_TIMER) //Could be a SC with infinite duration @@ -6943,6 +7056,10 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const status_change_end(tbl, SC_STOP, INVALID_TIMER); } break; + case SC_MILLENNIUMSHIELD: + if ( sd ) + clif_millenniumshield(sd,0); + break; } opt_flag = 1; @@ -6951,6 +7068,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_FREEZE: case SC_STUN: case SC_SLEEP: + case SC_BURNING: sc->opt1 = 0; break; @@ -6966,6 +7084,9 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_SIGNUMCRUCIS: sc->opt2 &= ~OPT2_SIGNUMCRUCIS; break; + case SC_FEAR: + sc->opt2 &= ~OPT2_FEAR; + break; case SC_HIDING: sc->option &= ~OPTION_HIDE; @@ -7495,8 +7616,24 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; } break; + case SC_ABUNDANCE: + if((--sce->val3) > 0) + { + int sp = 60; + if(sd) { + if( sd->status.sp < sd->status.max_sp ) + { + if( sd->status.sp + sp > sd->status.max_sp ) //No overhealing SP. + sp = sd->status.max_sp - sd->status.sp; + clif_heal(sd->fd,SP_SP,sp); + status_heal(bl, 0, sp, 0); + } + } + sc_timer_next(10000+tick, status_change_timer, bl->id, data); + } + break; case SC_RENOVATIO: - if((--sc->data[type]->val2) > 0) { + if((--sce->val2) > 0) { int heal = status->max_hp * 3 / 100; if( status->hp + heal > status->max_hp ) heal = status->max_hp - status->hp; @@ -7509,6 +7646,31 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; } break; + case SC_FEAR: + if(sce->val3 > 0) + { + sc_timer_next(sce->val3+tick, status_change_timer, bl->id, data); + sce->val3 = 0; + } + break; + case SC_BURNING: + if(--(sce->val4) >= 0) + { + int flag, hp = 0; + struct block_list *src = map_id2bl(sce->val2); + + hp = 1000+(status->max_hp*3 /100); + map_freeblock_lock(); + clif_damage(bl,bl,tick,status->amotion,0,hp,1,9,0); + status_damage(src, bl, hp, 0, 0, 1); + + flag = !sc->data[type]; + map_freeblock_unlock(); + if(!flag) + sc_timer_next( 3000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; } // default for all non-handled control paths is to end the status @@ -7569,7 +7731,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) /*========================================== * Clears buffs/debuffs of a character. - * type&1 -> buffs, type&2 -> debuffs + * type&1 -> buffs, type&2 -> debuffs, type&4 -> sc_refresh *------------------------------------------*/ int status_change_clear_buffs (struct block_list* bl, int type) { @@ -7628,6 +7790,13 @@ int status_change_clear_buffs (struct block_list* bl, int type) case SC_EXPBOOST: case SC_JEXPBOOST: case SC_ITEMBOOST: + case SC_GIANTGROWTH: + case SC_REFRESH: + case SC_STONEHARDSKIN: + case SC_VITALITYACTIVATION: + case SC_FIGHTINGSPIRIT: + case SC_ABUNDANCE: + case SC_MILLENNIUMSHIELD: continue; //Debuffs that can be removed. @@ -7644,9 +7813,33 @@ int status_change_clear_buffs (struct block_list* bl, int type) case SC_STRIPSHIELD: case SC_STRIPARMOR: case SC_STRIPHELM: + //Cannot be removed by Refresh. + if (type&4) + continue; case SC_ADORAMUS: if (!(type&2)) continue; + + //Debuffs that can be removed by Refresh.. + case SC_FEAR: + case SC_BURNING: + //case SC_POISONINGWEAPON: + //case SC_TOXIN: + //case SC_PARALYSE: + //case SC_VENOMBLEED: + //case SC_MAGICMUSHROOM: + //case SC_DEATHHURT: + //case SC_PYREXIA: + //case SC_OBLIVIONCURSE: + //case SC_LEECHESEND: + //case SC_FROSTMISTY: + //case SC_MARSHOFABYSS: + //case SC_DEEP_SLEEP: + //case SC_COLD: + //case SC_FREEZE_SP: + //case SC_MANDRAGORA: + if (!(type&4)) + continue; break; //The rest are buffs that can be removed. case SC_BERSERK: diff --git a/src/map/status.h b/src/map/status.h index 27c3e1782..033e7ca38 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -330,11 +330,21 @@ typedef enum sc_type { SC_FOOD_DEX_CASH, SC_FOOD_INT_CASH, SC_FOOD_LUK_CASH, - //SC_MOVHASTE_INFINITY, - SC_PARTYFLEE = 310, - //SC_ENDURE_MDEF, //311 - + SC_PARTYFLEE, + // Third Jobs - Maintaining SI order for SCs. + SC_FEAR, // 310, + SC_BURNING, + SC_ENCHANTBLADE, + SC_DEATHBOUND, + SC_REFRESH, + SC_GIANTGROWTH, //315 + SC_STONEHARDSKIN, + SC_VITALITYACTIVATION, + SC_FIGHTINGSPIRIT, + SC_ABUNDANCE, + SC_MILLENNIUMSHIELD, // 320 + // SC_EPICLESIS = 325, SC_ORATIO, SC_LAUDAAGNUS, @@ -344,7 +354,11 @@ typedef enum sc_type { SC_DUPLELIGHT, SC_ADORAMUS = 380, SC_AB_SECRAMENT = 451, + +// SC_ALL_RIDING = 472, + SC_CRUSHSTRIKE = 599, + SC_MAX, //Automatically updated max, used in for's to check we are within bounds. } sc_type; @@ -666,8 +680,7 @@ enum si_type { SI_CASH_PLUSONLYJOBEXP = 312, SI_PARTYFLEE = 313, // SI_ANGEL_PROTECT = 314, -/* - SI_ENDURE_MDEF = 315, +// SI_ENDURE_MDEF = 315, SI_ENCHANTBLADE = 316, SI_DEATHBOUND = 317, SI_REFRESH = 318, @@ -676,12 +689,11 @@ enum si_type { SI_VITALITYACTIVATION = 321, SI_FIGHTINGSPIRIT = 322, SI_ABUNDANCE = 323, - SI_REUSE_MILLENNIUMSHIELD = 324, - SI_REUSE_CRUSHSTRIKE = 325, - SI_REUSE_REFRESH = 326, - SI_REUSE_STORMBLAST = 327, - SI_VENOMIMPRESS = 328, -*/ +// SI_REUSE_MILLENNIUMSHIELD = 324, +// SI_REUSE_CRUSHSTRIKE = 325, +// SI_REUSE_REFRESH = 326, +// SI_REUSE_STORMBLAST = 327, +// SI_VENOMIMPRESS = 328, SI_EPICLESIS = 329, SI_ORATIO = 330, SI_LAUDAAGNUS = 331, @@ -973,7 +985,9 @@ enum si_type { SI_BEER_BOTTLE_CAP = 617, SI_OVERLAPEXPUP = 618, SI_PC_IZ_DUN05 = 619, +*/ SI_CRUSHSTRIKE = 620, +/* SI_MONSTER_TRANSFORM = 621, SI_SIT = 622, SI_ONAIR = 623, @@ -1111,6 +1125,7 @@ enum { OPTION_DRAGON3 = 0x01000000, OPTION_DRAGON4 = 0x02000000, OPTION_DRAGON5 = 0x04000000, + OPTION_ALL_RIDING= 0x08000000, // compound constants OPTION_CART = OPTION_CART1|OPTION_CART2|OPTION_CART3|OPTION_CART4|OPTION_CART5, OPTION_DRAGON = OPTION_DRAGON1|OPTION_DRAGON2|OPTION_DRAGON3|OPTION_DRAGON4|OPTION_DRAGON5, diff --git a/src/map/unit.c b/src/map/unit.c index c8b0e0d26..b51e2602d 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -837,6 +837,8 @@ int unit_can_move(struct block_list *bl) sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1)) || sc->data[SC_MADNESSCANCEL] || (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF) + || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val3 > 0) + || sc->data[SC_DEATHBOUND] )) return 0; } |