From 5cc9f30cbe8c57a97e58a5a3b5387622e4304873 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Fri, 17 Feb 2012 15:33:13 +0000 Subject: Initial support for Shadow Chaser and a few adjustments here and there. - credits to 3ceam for the base - should you step by any bugs let us know, http://rathena.org/board/tracker git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15589 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/mmo.h | 2 +- src/map/battle.c | 83 ++++++++++- src/map/clif.c | 32 +++++ src/map/clif.h | 4 + src/map/map.c | 3 + src/map/map.h | 7 +- src/map/pc.c | 24 +++- src/map/pc.h | 4 +- src/map/skill.c | 416 +++++++++++++++++++++++++++++++++++++++---------------- src/map/skill.h | 1 + src/map/status.c | 306 +++++++++++++++++++++++++++++++--------- src/map/status.h | 2 + src/map/unit.c | 9 ++ 13 files changed, 700 insertions(+), 193 deletions(-) (limited to 'src') diff --git a/src/common/mmo.h b/src/common/mmo.h index 40ede7440..6a81407ce 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -45,7 +45,7 @@ // 20111025 - 2011-10-25aRagexeRE+ - 0x6b, 0x6d #ifndef PACKETVER - #define PACKETVER 20110609 + #define PACKETVER 20111116 //#define PACKETVER 20100730 #endif diff --git a/src/map/battle.c b/src/map/battle.c index a7257406e..6672a2b27 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -407,8 +407,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag status_change_end(bl, SC_SAFETYWALL, INVALID_TIMER); } - if( sc->data[SC_PNEUMA] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG ) - { + if( ( sc->data[SC_PNEUMA] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG ) || sc->data[SC__MANHOLE] ) { d->dmg_lv = ATK_BLOCK; return 0; } @@ -614,6 +613,9 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if( sd && (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rnd()%100 < sce->val2 ) pc_addspiritball(sd,skill_get_time(LG_FORCEOFVANGUARD,sce->val1),sce->val3); + + if( sc->data[SC__DEADLYINFECT] && damage > 0 && rand()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) + status_change_spread(bl, src); // Deadly infect attacked side } @@ -648,6 +650,8 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag } if( sc->data[SC_POISONINGWEAPON] && skill_num != GC_VENOMPRESSURE && (flag&BF_WEAPON) && damage > 0 && rnd()%100 < sc->data[SC_POISONINGWEAPON]->val3 ) sc_start(bl,sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,skill_get_time2(GC_POISONINGWEAPON,sc->data[SC_POISONINGWEAPON]->val1)); + if( sc->data[SC__DEADLYINFECT] && damage > 0 && rand()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) + status_change_spread(src, bl); } if (battle_config.pk_mode && sd && bl->type == BL_PC && damage && map[bl->m].flag.pvp) @@ -683,7 +687,44 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if (skill_num) mobskill_event((TBL_MOB*)bl,src,gettick(),MSC_SKILLUSED|(skill_num<<16)); } - + if( sd ) { + if( (sd->sc.option&OPTION_MADOGEAR) && rand()%100 < 50 ) { + short element = skill_get_ele(skill_num, skill_lv); + if( !skill_num || element == -1 ) { //Take weapon's element + struct status_data *sstatus = NULL; + if( src->type == BL_PC && ((TBL_PC*)src)->arrow_ele ) + element = ((TBL_PC*)src)->arrow_ele; + else if( (sstatus = status_get_status_data(src)) ) { + element = sstatus->rhw.ele; + } + } + else if( element == -2 ) //Use enchantment's element + element = status_get_attack_sc_element(src,status_get_sc(src)); + else if( element == -3 ) //Use random element + element = rnd()%ELE_MAX; + if( element == ELE_FIRE || element == ELE_WATER ) + pc_overheat(sd,element == ELE_FIRE ? 1 : -1); + } + } + if( sc && sc->data[SC__SHADOWFORM] ) { + struct block_list *s_bl = map_id2bl(sc->data[SC__SHADOWFORM]->val2); + if( !s_bl ) { // If the shadow form target is not present remove the sc. + status_change_end(bl, SC__SHADOWFORM, -1); + } else if( status_isdead(s_bl) || !battle_check_target(src,s_bl,BCT_ENEMY)) { // If the shadow form target is dead or not your enemy remove the sc in both. + status_change_end(bl, SC__SHADOWFORM, -1); + if( s_bl->type == BL_PC ) + ((TBL_PC*)s_bl)->shadowform_id = 0; + } else { + if( (--sc->data[SC__SHADOWFORM]->val3) < 0 ) { // If you have exceded max hits supported, remove the sc in both. + status_change_end(bl, SC__SHADOWFORM, -1); + if( s_bl->type == BL_PC ) + ((TBL_PC*)s_bl)->shadowform_id = 0; + } else { + status_damage(src, s_bl, damage, 0, clif_damage(s_bl, s_bl, gettick(), 500, 500, damage, -1, 0, 0), 0); + return ATK_NONE; + } + } + } return damage; } @@ -2005,6 +2046,15 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo skillratio += 100 + 100 * skill_lv + sstatus->vit; if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. break; + case SC_FATALMENACE: + skillratio += 100 * skill_lv; + break; + case SC_TRIANGLESHOT: + skillratio += 270 + 30 * skill_lv; + break; + case SC_FEINTBOMB: + skillratio += 100 + 100 * skill_lv; + break; case LG_CANNONSPEAR:// Stimated formula. Still need confirm it. skillratio += -100 + (50 + sstatus->str) * skill_lv; if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. @@ -3982,6 +4032,31 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } } if (sd) { + if( wd.flag&BF_SHORT && sc && sc->data[SC__AUTOSHADOWSPELL] && rand()%100 < sc->data[SC__AUTOSHADOWSPELL]->val3 && + sd->status.skill[sc->data[SC__AUTOSHADOWSPELL]->val1].id != 0 && sd->status.skill[sc->data[SC__AUTOSHADOWSPELL]->val1].flag == 13 ) + { + int r_skill = sd->status.skill[sc->data[SC__AUTOSHADOWSPELL]->val1].id, + r_lv = sc->data[SC__AUTOSHADOWSPELL]->val2; + + if (r_skill != AL_HOLYLIGHT && r_skill != PR_MAGNUS) { + skill_consume_requirement(sd,r_skill,r_lv,3); + switch( skill_get_casttype(r_skill) ) { + case CAST_GROUND: + skill_castend_pos2(src, target->x, target->y, r_skill, r_lv, tick, flag); + break; + case CAST_NODAMAGE: + skill_castend_nodamage_id(src, target, r_skill, r_lv, tick, flag); + break; + case CAST_DAMAGE: + skill_castend_damage_id(src, target, r_skill, r_lv, tick, flag); + break; + } + + sd->ud.canact_tick = tick + skill_delayfix(src, r_skill, r_lv); + clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, r_skill, r_lv), 0, 0, 1); + } + } + if (wd.flag & BF_WEAPON && src != target && damage > 0) { if (battle_config.left_cardfix_to_right) battle_drain(sd, target, wd.damage, wd.damage, tstatus->race, is_boss(target)); @@ -4099,7 +4174,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f switch( target->type ) { // Checks on actual target case BL_PC: - if (((TBL_PC*)target)->invincible_timer != INVALID_TIMER || pc_isinvisible((TBL_PC*)target)) + if (((TBL_PC*)target)->invincible_timer != INVALID_TIMER || pc_isinvisible((TBL_PC*)target) || ((TBL_PC*)target)->sc.data[SC__MANHOLE]) return -1; //Cannot be targeted yet. break; case BL_MOB: diff --git a/src/map/clif.c b/src/map/clif.c index 8203ab7f5..fd0f856e8 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -15722,6 +15722,38 @@ int clif_poison_list(struct map_session_data *sd, int skill_lv) { return 1; } +int clif_autoshadowspell_list(struct map_session_data *sd) { + int fd, i, c; + nullpo_ret(sd); + fd = sd->fd; + if( !fd ) return 0; + + if( sd->menuskill_id == SC_AUTOSHADOWSPELL ) + return 0; + + WFIFOHEAD(fd, 2 * 6 + 4); + WFIFOW(fd,0) = 0x442; + for( i = 0, c = 0; i < MAX_SKILL; i++ ) + if( sd->status.skill[i].flag == 13 && sd->status.skill[i].id > 0 && + sd->status.skill[i].id < GS_GLITTERING && skill_get_type(sd->status.skill[i].id) == BF_MAGIC ) + { // Can't auto cast both Extended class and 3rd class skills. + WFIFOW(fd,8+c*2) = sd->status.skill[i].id; + c++; + } + + if( c > 0 ) { + WFIFOW(fd,2) = 8 + c * 2; + WFIFOL(fd,4) = c; + WFIFOSET(fd,WFIFOW(fd,2)); + sd->menuskill_id = SC_AUTOSHADOWSPELL; + sd->menuskill_val = c; + } else { + status_change_end(&sd->bl,SC_STOP,-1); + clif_skill_fail(sd,SC_AUTOSHADOWSPELL,0x15,0); + } + + return 1; +} /** * Sends a new status without a tick (currently used by the new mounts) **/ diff --git a/src/map/clif.h b/src/map/clif.h index 3994541b5..c03bd388d 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -734,6 +734,10 @@ int clif_magicdecoy_list(struct map_session_data *sd, int skill_lv, short x, sho * Guilotine Cross **/ int clif_poison_list(struct map_session_data *sd, int skill_lv); +/** + * Shadow Chaser + **/ +int clif_autoshadowspell_list(struct map_session_data *sd); /** * [RRInd] for the new mounts **/ diff --git a/src/map/map.c b/src/map/map.c index 4677e8753..b1fa2d132 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2403,6 +2403,8 @@ int map_getcellp(struct map_data* m,int x,int y,cell_chk cellchk) return (cell.novending); case CELL_CHKNOCHAT: return (cell.nochat); + case CELL_CHKMAELSTROM: + return (cell.maelstrom); // special checks case CELL_CHKPASS: @@ -2455,6 +2457,7 @@ void map_setcell(int m, int x, int y, cell_t cell, bool flag) case CELL_LANDPROTECTOR: map[m].cell[j].landprotector = flag; break; case CELL_NOVENDING: map[m].cell[j].novending = flag; break; case CELL_NOCHAT: map[m].cell[j].nochat = flag; break; + case CELL_MAELSTROM: map[m].cell[j].maelstrom = flag; break; default: ShowWarning("map_setcell: invalid cell type '%d'\n", (int)cell); break; diff --git a/src/map/map.h b/src/map/map.h index 97063bfbb..98833fe85 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -400,6 +400,8 @@ typedef enum { CELL_LANDPROTECTOR, CELL_NOVENDING, CELL_NOCHAT, + CELL_MAELSTROM, + } cell_t; // used by map_getcell() @@ -421,6 +423,8 @@ typedef enum { CELL_CHKLANDPROTECTOR, CELL_CHKNOVENDING, CELL_CHKNOCHAT, + CELL_CHKMAELSTROM, + } cell_chk; struct mapcell @@ -437,7 +441,8 @@ struct mapcell basilica : 1, landprotector : 1, novending : 1, - nochat : 1; + nochat : 1, + maelstrom : 1; #ifdef CELL_NOSTACK unsigned char cell_bl; //Holds amount of bls in this cell. diff --git a/src/map/pc.c b/src/map/pc.c index 94d505c15..7d93442cb 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -854,6 +854,8 @@ int pc_isequip(struct map_session_data *sd,int n) return 0; if(item->equip & EQP_HEAD_TOP && sd->sc.data[SC_STRIPHELM]) return 0; + if(item->equip & EQP_ACC && sd->sc.data[SC__STRIPACCESSORY]) + return 0; if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_SUPERNOVICE) { //Spirit of Super Novice equip bonuses. [Skotlex] @@ -1156,7 +1158,16 @@ int pc_reg_received(struct map_session_data *sd) sd->status.skill[sd->cloneskill_id].flag = SKILL_FLAG_PLAGIARIZED; } } - + if ((i = pc_checkskill(sd,SC_REPRODUCE)) > 0) { + sd->reproduceskill_id = pc_readglobalreg(sd,"REPRODUCE_SKILL"); + if( sd->reproduceskill_id > 0) { + sd->status.skill[sd->reproduceskill_id].id = sd->reproduceskill_id; + sd->status.skill[sd->reproduceskill_id].lv = pc_readglobalreg(sd,"REPRODUCE_SKILL_LV"); + if( i < sd->status.skill[sd->reproduceskill_id].lv) + sd->status.skill[sd->reproduceskill_id].lv = i; + sd->status.skill[sd->reproduceskill_id].flag = 13; + } + } //Weird... maybe registries were reloaded? if (sd->state.active) return 0; @@ -6644,6 +6655,17 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) pc_setglobalreg(sd, "CLONE_SKILL", 0); pc_setglobalreg(sd, "CLONE_SKILL_LV", 0); } + if(sd->reproduceskill_id) { + if( sd->status.skill[sd->reproduceskill_id].flag == SKILL_FLAG_PLAGIARIZED ) { + sd->status.skill[sd->reproduceskill_id].id = 0; + sd->status.skill[sd->reproduceskill_id].lv = 0; + sd->status.skill[sd->reproduceskill_id].flag = 0; + clif_deleteskill(sd,sd->reproduceskill_id); + } + sd->reproduceskill_id = 0; + pc_setglobalreg(sd, "REPRODUCE_SKILL",0); + pc_setglobalreg(sd, "REPRODUCE_SKILL_LV",0); + } if ((b_class&&MAPID_UPPERMASK) != (sd->class_&MAPID_UPPERMASK)) { //Things to remove when changing class tree. const int class_ = pc_class2idx(sd->status.class_); diff --git a/src/map/pc.h b/src/map/pc.h index 47d9edead..cb5a0ef77 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -203,7 +203,7 @@ struct map_session_data { short skillid_dance,skilllv_dance; short cook_mastery; // range: [0,1999] [Inkfish] unsigned char blockskill[MAX_SKILL]; - int cloneskill_id; + int cloneskill_id, reproduceskill_id; int menuskill_id, menuskill_val; int invincible_timer; @@ -461,6 +461,8 @@ struct map_session_data { **/ int friend_req; + int shadowform_id; + // temporary debugging of bug #3504 const char* delunit_prevfile; int delunit_prevline; diff --git a/src/map/skill.c b/src/map/skill.c index cdf70d82f..a88927335 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -75,6 +75,9 @@ struct s_skill_db skill_db[MAX_SKILL_DB]; struct s_skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB]; struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB]; struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB]; + +bool skill_reproduce_db[MAX_SKILL_DB]; + //Warlock struct s_skill_spellbook_db { int nameid; @@ -422,6 +425,13 @@ int can_copy (struct map_session_data *sd, int skillid, struct block_list* bl) skillid == MER_INCAGI || skillid == MER_BLESSING)) return 0; + // Couldn't preserve 3rd Class skills except only when using Reproduce skill. [Jobbie] + if( !(sd->sc.data[SC__REPRODUCE]) && (skillid >= RK_ENCHANTBLADE && skillid <= SR_RIDEINLIGHTNING) ) + return 0; + // Reproduce will only copy skills according on the list. [Jobbie] + else if( sd->sc.data[SC__REPRODUCE] && !skill_reproduce_db[skillid] ) + return 0; + return 1; } @@ -485,6 +495,8 @@ int skillnotok (int skillid, struct map_session_data *sd) } return 0; case AL_TELEPORT: + case SC_FATALMENACE: + case SC_DIMENSIONDOOR: if(map[m].flag.noteleport) { clif_skill_teleportmessage(sd,0); return 1; @@ -1802,9 +1814,9 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int lv, int time) { struct status_change *sc; - const int pos[4] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HELM}; - const enum sc_type sc_atk[4] = {SC_STRIPWEAPON, SC_STRIPSHIELD, SC_STRIPARMOR, SC_STRIPHELM}; - const enum sc_type sc_def[4] = {SC_CP_WEAPON, SC_CP_SHIELD, SC_CP_ARMOR, SC_CP_HELM}; + const int pos[5] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HELM, EQP_ACC}; + const enum sc_type sc_atk[5] = {SC_STRIPWEAPON, SC_STRIPSHIELD, SC_STRIPARMOR, SC_STRIPHELM, SC__STRIPACCESSORY}; + const enum sc_type sc_def[5] = {SC_CP_WEAPON, SC_CP_SHIELD, SC_CP_ARMOR, SC_CP_HELM, 0}; int i; if (rnd()%100 >= rate) @@ -2238,25 +2250,46 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if ((tsd->status.skill[copy_skill].id == 0 || tsd->status.skill[copy_skill].flag == SKILL_FLAG_PLAGIARIZED) && can_copy(tsd,copy_skill,bl)) // Split all the check into their own function [Aru] { - int lv = skilllv; - if (tsd->cloneskill_id && tsd->status.skill[tsd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED){ - tsd->status.skill[tsd->cloneskill_id].id = 0; - tsd->status.skill[tsd->cloneskill_id].lv = 0; - tsd->status.skill[tsd->cloneskill_id].flag = 0; - clif_deleteskill(tsd,tsd->cloneskill_id); - } + int lv; + if( sc && sc->data[SC__REPRODUCE] && (lv = sc->data[SC__REPRODUCE]->val1) ) { + //Level dependent and limitation. + lv = min(lv,skill_get_max(copy_skill)); + if( tsd->reproduceskill_id && tsd->status.skill[tsd->reproduceskill_id].flag == 13 ) { + tsd->status.skill[tsd->reproduceskill_id].id = 0; + tsd->status.skill[tsd->reproduceskill_id].lv = 0; + tsd->status.skill[tsd->reproduceskill_id].flag = 0; + clif_deleteskill(tsd,tsd->reproduceskill_id); + } + + tsd->reproduceskill_id = copy_skill; + pc_setglobalreg(tsd, "REPRODUCE_SKILL", copy_skill); + pc_setglobalreg(tsd, "REPRODUCE_SKILL_LV", lv); + + tsd->status.skill[copy_skill].id = copy_skill; + tsd->status.skill[copy_skill].lv = lv; + tsd->status.skill[copy_skill].flag = 13; + clif_addskill(tsd,copy_skill); + } else { + lv = skilllv; + if (tsd->cloneskill_id && tsd->status.skill[tsd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED){ + tsd->status.skill[tsd->cloneskill_id].id = 0; + tsd->status.skill[tsd->cloneskill_id].lv = 0; + tsd->status.skill[tsd->cloneskill_id].flag = 0; + clif_deleteskill(tsd,tsd->cloneskill_id); + } - if ((type = pc_checkskill(tsd,RG_PLAGIARISM)) < lv) - lv = type; + if ((type = pc_checkskill(tsd,RG_PLAGIARISM)) < lv) + lv = type; - tsd->cloneskill_id = copy_skill; - pc_setglobalreg(tsd, "CLONE_SKILL", copy_skill); - pc_setglobalreg(tsd, "CLONE_SKILL_LV", lv); + tsd->cloneskill_id = copy_skill; + pc_setglobalreg(tsd, "CLONE_SKILL", copy_skill); + pc_setglobalreg(tsd, "CLONE_SKILL_LV", lv); - tsd->status.skill[skillid].id = copy_skill; - tsd->status.skill[skillid].lv = lv; - tsd->status.skill[skillid].flag = SKILL_FLAG_PLAGIARIZED; - clif_addskill(tsd,skillid); + tsd->status.skill[skillid].id = copy_skill; + tsd->status.skill[skillid].lv = lv; + tsd->status.skill[skillid].flag = SKILL_FLAG_PLAGIARIZED; + clif_addskill(tsd,skillid); + } } } if( skillid != WZ_SIGHTRASHER && @@ -2303,6 +2336,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case MG_FIREWALL: case WZ_STORMGUST: case PR_SANCTUARY: + case SC_TRIANGLESHOT: case LG_OVERBRAND: direction = unit_getdir(bl);// backwards break; @@ -2348,11 +2382,14 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds } } - if(skillid == RG_INTIMIDATE && damage > 0 && !(tstatus->mode&MD_BOSS)) { - int rate = 50 + skilllv * 5; - rate = rate + (status_get_lv(src) - status_get_lv(bl)); - if(rnd()%100 < rate) - skill_addtimerskill(src,tick + 800,bl->id,0,0,skillid,skilllv,0,flag); + if(damage > 0 && !(tstatus->mode&MD_BOSS)) { + if( skillid == RG_INTIMIDATE ) { + int rate = 50 + skilllv * 5; + rate = rate + (status_get_lv(src) - status_get_lv(bl)); + if(rnd()%100 < rate) + skill_addtimerskill(src,tick + 800,bl->id,0,0,skillid,skilllv,0,flag); + } else if( skillid == SC_FATALMENACE ) + skill_addtimerskill(src,tick + 800,bl->id,skill_area_temp[4],skill_area_temp[5],skillid,skilllv,0,flag); } if(skillid == CR_GRANDCROSS || skillid == NPC_GRANDDARKNESS) @@ -2468,11 +2505,11 @@ static int skill_check_unit_range_sub (struct block_list *bl, va_list ap) skillid = va_arg(ap,int); g_skillid = unit->group->skill_id; - switch (skillid) - { + switch (skillid) { case MG_SAFETYWALL: case AL_PNEUMA: - if(g_skillid != MG_SAFETYWALL && g_skillid != AL_PNEUMA) + case SC_MAELSTROM: + if(g_skillid != MG_SAFETYWALL && g_skillid != AL_PNEUMA && g_skillid != SC_MAELSTROM) return 0; break; case AL_WARP: @@ -2491,9 +2528,6 @@ static int skill_check_unit_range_sub (struct block_list *bl, va_list ap) case HT_CLAYMORETRAP: case HT_TALKIEBOX: case HP_BASILICA: - /** - * Ranger - **/ case RA_ELECTRICSHOCKER: case RA_CLUSTERBOMB: case RA_MAGENTATRAP: @@ -2502,6 +2536,7 @@ static int skill_check_unit_range_sub (struct block_list *bl, va_list ap) case RA_VERDURETRAP: case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: + case SC_DIMENSIONDOOR: //Non stackable on themselves and traps (including venom dust which does not has the trap inf2 set) if (skillid != g_skillid && !(skill_get_inf2(g_skillid)&INF2_TRAP) && g_skillid != AS_VENOMDUST) return 0; @@ -2749,7 +2784,7 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) break; if(skl->target_id) { target = map_id2bl(skl->target_id); - if( skl->skill_id == RG_INTIMIDATE && (!target || target->prev == NULL || !check_distance_bl(src,target,AREA_SIZE)) ) + if( ( skl->skill_id == RG_INTIMIDATE || skl->skill_id == SC_FATALMENACE ) && (!target || target->prev == NULL || !check_distance_bl(src,target,AREA_SIZE)) ) target = src; //Required since it has to warp. if(target == NULL) break; @@ -2856,6 +2891,15 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) } } break; + case SC_FATALMENACE: + if( src == target ) // Casters Part + unit_warp(src, -1, skl->x, skl->y, 3); + else { // Target's Part + short x = skl->x, y = skl->y; + map_search_freecell(NULL, target->m, &x, &y, 2, 2, 1); + unit_warp(target,-1,x,y,3); + } + break; case LG_MOONSLASHER: if( target->type == BL_PC ) { struct map_session_data *tsd = NULL; @@ -3101,33 +3145,17 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NPC_BLEEDING: case NPC_CRITICALWOUND: case NPC_HELLPOWER: - /** - * Rune Knight - **/ case RK_SONICWAVE: case RK_HUNDREDSPEAR: case RK_WINDCUTTER: - /** - * Arch Bishop - **/ case AB_DUPLELIGHT_MELEE: - /** - * Ranger - **/ case RA_AIMEDBOLT: - /** - * Mechanic - **/ case NC_AXEBOOMERANG: case NC_POWERSWING: - /** - * Guilotinne Cross - **/ case GC_CROSSIMPACT: case GC_VENOMPRESSURE: - /** - * Royal Guard - **/ + case SC_TRIANGLESHOT: + case SC_FEINTBOMB: case LG_BANISHINGPOINT: case LG_SHIELDPRESS: case LG_RAGEBURST: @@ -4011,6 +4039,21 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NC_MAGNETICFIELD: sc_start2(bl,SC_MAGNETICFIELD,100,skilllv,src->id,skill_get_time(skillid,skilllv)); break; + case SC_FATALMENACE: + if( flag&1 ) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + else + { + short x, y; + map_search_freecell(src, 0, &x, &y, -1, -1, 0); + // Destination area + skill_area_temp[4] = x; + skill_area_temp[5] = y; + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_damage_id); + skill_addtimerskill(src,tick + 800,src->id,x,y,skillid,skilllv,0,flag); // To teleport Self + clif_skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skillid,skilllv,6); + } + break; /** * Royal Guard **/ @@ -4662,34 +4705,17 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case ST_PRESERVE: case NPC_INVINCIBLE: case NPC_INVINCIBLEOFF: - /** - * Rune Knight - **/ case RK_DEATHBOUND: - /** - * Arch Bishop - **/ case AB_RENOVATIO: case AB_EXPIATIO: case AB_DUPLELIGHT: case AB_SECRAMENT: - /** - * Mechanic - **/ case NC_ACCELERATION: case NC_HOVERING: case NC_SHAPESHIFT: - /** - * Warlock - **/ case WL_RECOGNIZEDSPELL: - /** - * Guillotine Cross - **/ case GC_VENOMIMPRESS: - /** - * Royal Guard - **/ + case SC_DEADLYINFECT: case LG_EXEEDBREAK: case LG_PRESTIGE: clif_skill_nodamage(src,bl,skillid,skilllv, @@ -5169,16 +5195,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case AS_CLOAKING: case RA_CAMOUFLAGE: - /** - * Guilotine Cross - **/ case GC_CLOAKINGEXCEED: - /** - * Royal Guard - **/ case LG_FORCEOFVANGUARD: - if (tsce) - { + case SC_REPRODUCE: + case SC_INVISIBILITY: + if (tsce) { i = status_change_end(bl, type, INVALID_TIMER); if( i ) clif_skill_nodamage(src,bl,skillid,( skillid == LG_FORCEOFVANGUARD ) ? skilllv : -1,i); @@ -5499,16 +5520,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case RG_STRIPHELM: case ST_FULLSTRIP: case GC_WEAPONCRUSH: - { + case SC_STRIPACCESSARY: { unsigned short location = 0; int d = 0; //Rate in percent if ( skillid == ST_FULLSTRIP ) { i = 5 + 2*skilllv + (sstatus->dex - tstatus->dex)/5; + } else if( skillid == SC_STRIPACCESSARY ) { + i = 12 + 2 * skilllv + (sstatus->dex - tstatus->dex)/5; } else { i = 5 + 5*skilllv + (sstatus->dex - tstatus->dex)/5; } + if (i < 5) i = 5; //Minimum rate 5% //Duration in ms @@ -5532,6 +5556,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case ST_FULLSTRIP: location = EQP_WEAPON|EQP_SHIELD|EQP_ARMOR|EQP_HELM; break; + case SC_STRIPACCESSARY: + location = EQP_ACC; + break; } //Special message when trying to use strip on FCP [Jobbie] @@ -5548,8 +5575,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in //Nothing stripped. if( sd && !i ) clif_skill_fail(sd,skillid,USESKILL_FAIL_LEVEL,0); - } break; + } case AM_BERSERKPITCHER: case AM_POTIONPITCHER: @@ -5752,7 +5779,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case SC_FOOD_AGI_CASH: case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH: case SC_FOOD_INT_CASH: case SC_FOOD_LUK_CASH: case SC_SEVENWIND: case SC_MIRACLE: case SC_S_LIFEPOTION: case SC_L_LIFEPOTION: - case SC_INCHEALRATE: + case SC_INCHEALRATE: case SC_ELECTRICSHOCKER: case SC__STRIPACCESSORY: + //case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: case SC_MINOR_BBQ: + //case SC_SIROMA_ICE_TEA: case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES: + case SC_NEUTRALBARRIER_MASTER: case SC_NEUTRALBARRIER: case SC_STEALTHFIELD_MASTER: + case SC_STEALTHFIELD: case SC_GIANTGROWTH: case SC_MILLENNIUMSHIELD: + case SC_REFRESH: case SC_STONEHARDSKIN: case SC_VITALITYACTIVATION: + case SC_FIGHTINGSPIRIT: case SC_ABUNDANCE: case SC__SHADOWFORM: continue; /** * bugreport:4888 these songs may only be dispelled if you're not in their song area anymore @@ -7067,14 +7100,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case SC_HUMMING: case SC_DONTFORGETME: case SC_FORTUNE: case SC_SERVICE4U: case SC_FOOD_STR_CASH: case SC_FOOD_AGI_CASH: case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH: case SC_FOOD_INT_CASH: - case SC_FOOD_LUK_CASH: /* case SC_ELECTRICSHOCKER: case SC_BITE: + case SC_FOOD_LUK_CASH: case SC_ELECTRICSHOCKER: case SC_BITE: case SC__STRIPACCESSORY: case SC__ENERVATION: case SC__GROOMY: case SC__IGNORANCE: case SC__LAZINESS: case SC__UNLUCKY: - case SC__WEAKNESS: case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: - case SC_MAGNETICFIELD:case SC_MINOR_BBQ: case SC_SIROMA_ICE_TEA: - case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES: + case SC__WEAKNESS: //case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: + case SC_MAGNETICFIELD://case SC_MINOR_BBQ: case SC_SIROMA_ICE_TEA: + //case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES: case SC_NEUTRALBARRIER_MASTER: case SC_NEUTRALBARRIER: - case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD: */ + case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD: continue; case SC_ASSUMPTIO: if( bl->type == BL_MOB ) @@ -7357,9 +7390,79 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_skill_nodamage(src, bl, skillid, skilllv, 1); } break; - /** - * Royal Guard - **/ + case SC_AUTOSHADOWSPELL: + if( sd ) { + if( sd->status.skill[sd->reproduceskill_id].id || sd->status.skill[sd->cloneskill_id].id ) { + sc_start(src,SC_STOP,100,skilllv,-1);// The skilllv is stored in val1 used in skill_select_menu to determine the used skill lvl [Xazax] + clif_autoshadowspell_list(sd); + clif_skill_nodamage(src,bl,skillid,1,1); + } + else + clif_skill_fail(sd,skillid,0x15,0); + } + break; + + case SC_SHADOWFORM: + if( sd && dstsd && src != bl && !dstsd->shadowform_id ) { + if( clif_skill_nodamage(src,bl,skillid,skilllv,sc_start4(src,type,100,skilllv,bl->id,4+skilllv,0,skill_get_time(skillid, skilllv))) ) + dstsd->shadowform_id = src->id; + } + else if( sd ) + clif_skill_fail(sd, skillid, 0, 0); + break; + + case SC_BODYPAINT: + if( flag&1 ) { + if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || + tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED] || + tsc->data[SC__INVISIBILITY]) ) { + status_change_end(bl, SC_HIDING, -1); + status_change_end(bl, SC_CLOAKING, -1); + status_change_end(bl, SC_CHASEWALK, -1); + status_change_end(bl, SC_CLOAKINGEXCEED, -1); + status_change_end(bl, SC__INVISIBILITY, -1); + + sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)); + sc_start(bl,SC_BLIND,53 + 2 * skilllv,skilllv,skill_get_time(skillid,skilllv)); + } + } else { + clif_skill_nodamage(src, bl, skillid, 0, 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 SC_ENERVATION: + case SC_GROOMY: + case SC_LAZINESS: + case SC_UNLUCKY: + case SC_WEAKNESS: + if( !(tsc && tsc->data[type]) ) { + //((rand(myDEX / 12, myDEX / 4) + myJobLevel + 10 * skLevel) + myLevel / 10) - (targetLevel / 10 + targetLUK / 10 + (targetMaxWeight - targetWeight) / 1000 + rand(targetAGI / 6, targetAGI / 3)) + int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skilllv + (sd?sd->status.job_level:0) + status_get_lv(src)/10 + - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3); + rate = cap_value(rate, skilllv+sstatus->dex/20, 100); + clif_skill_nodamage(src,bl,skillid,0,sc_start(bl,type,rate,skilllv,skill_get_time(skillid,skilllv))); + } else if( sd ) + clif_skill_fail(sd,skillid,0,0); + break; + + case SC_IGNORANCE: + if( !(tsc && tsc->data[type]) ) { + int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skilllv + (sd?sd->status.job_level:0) + status_get_lv(src)/10 + - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3); + rate = cap_value(rate, skilllv+sstatus->dex/20, 100); + if (clif_skill_nodamage(src,bl,skillid,0,sc_start(bl,type,rate,skilllv,skill_get_time(skillid,skilllv)))) { + int sp = 200 * skilllv; + if( dstmd ) sp = dstmd->level * 2; + if( status_zap(bl,0,sp) ) + status_heal(src,0,sp/2,3); + } + else if( sd ) clif_skill_fail(sd,skillid,0,0); + } else if( sd ) + clif_skill_fail(sd,skillid,0,0); + break; + case LG_TRAMPLE: clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); map_foreachinrange(skill_destroy_trap,bl,skill_get_splash(skillid,skilllv),BL_SKILL,tick); @@ -8165,9 +8268,6 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case NJ_RAIGEKISAI: case NJ_KAMAITACHI: case NPC_EVILLAND: - /** - * Ranger - **/ case RA_ELECTRICSHOCKER: case RA_CLUSTERBOMB: case RA_MAGENTATRAP: @@ -8176,6 +8276,11 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case RA_VERDURETRAP: case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: + case SC_MANHOLE: + case SC_DIMENSIONDOOR: + case SC_CHAOSPANIC: + case SC_BLOODYLUST: + case SC_MAELSTROM: flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). case GS_GROUNDDRIFT: //Ammo should be deleted right away. skill_unitsetting(src,skillid,skilllv,x,y,0); @@ -8535,9 +8640,13 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case NC_MAGICDECOY: if( sd ) clif_magicdecoy_list(sd,skilllv,x,y); break; - /** - * Royal Guard - **/ + + case SC_FEINTBOMB: + clif_skill_nodamage(src,src,skillid,skilllv,1); + skill_unitsetting(src,skillid,skilllv,x,y,0); // Set bomb on current Position + skill_blown(src,src,6,unit_getdir(src),0); + break; + case LG_OVERBRAND: { int width;//according to data from irowiki it actually is a square @@ -8622,15 +8731,10 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char sd->sc.data[SC_BERSERK] || sd->sc.data[SC_BASILICA] || sd->sc.data[SC_MARIONETTE] || - /** - * Warlock - **/ sd->sc.data[SC_WHITEIMPRISON] || (sd->sc.data[SC_STASIS] && skill_stasis_check(&sd->bl, sd->sc.data[SC_STASIS]->val2, skill_num)) || - /** - * Guillotine Cross - **/ - sd->sc.data[SC_OBLIVIONCURSE] + sd->sc.data[SC_OBLIVIONCURSE] || + sd->sc.data[SC__MANHOLE] )) { skill_failed(sd); return 0; @@ -9302,6 +9406,8 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un break; case UNT_PNEUMA: + case UNT_CHAOSPANIC: + case UNT_MAELSTROM: if (!sce) sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit); break; @@ -9461,6 +9567,8 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns switch (sg->unit_id) { case UNT_ANKLESNARE: //These happen when a trap is splash-triggered by multiple targets on the same cell. case UNT_FIREPILLAR_ACTIVE: + case UNT_ELECTRICSHOCKER: + case UNT_MANHOLE: return 0; default: ShowError("skill_unit_onplace_timer: interval error (unit id %x)\n", sg->unit_id); @@ -9623,19 +9731,17 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns break; case UNT_ANKLESNARE: - if( sg->val2 == 0 && tsc ) - { + case UNT_MANHOLE: + if( sg->val2 == 0 && tsc && (sg->unit_id == UNT_ANKLESNARE || bl->id != sg->src_id) ) { int sec = skill_get_time2(sg->skill_id,sg->skill_lv); - if( status_change_start(bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, 8) ) - { + if( status_change_start(bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, 8) ) { const struct TimerData* td = tsc->data[type]?get_timer(tsc->data[type]->timer):NULL; if( td ) sec = DIFF_TICK(td->tick, tick); unit_movepos(bl, src->bl.x, src->bl.y, 0, 0); clif_fixpos(bl); sg->val2 = bl->id; - } - else + } else sec = 3000; //Couldn't trap it? clif_skillunit_update(&src->bl); @@ -10046,6 +10152,8 @@ static int skill_unit_onleft (int skill_id, struct block_list *bl, unsigned int case CG_HERMODE: case HW_GRAVITATION: case NJ_SUITON: + case SC_MAELSTROM: + case SC_BLOODYLUST: if (sce) status_change_end(bl, type, INVALID_TIMER); break; @@ -10411,6 +10519,9 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh return 0; } + if( sc && ( sc->data[SC__SHADOWFORM] || sc->data[SC__IGNORANCE] ) ) + return 0; + switch( skill ) { // Turn off check. case BS_MAXIMIZE: case NV_TRICKDEAD: case TF_HIDING: case AS_CLOAKING: case CR_AUTOGUARD: @@ -10802,7 +10913,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh } break; case RA_WUGMASTERY: - if( pc_isfalcon(sd) || pc_isridingwug(sd) ) { + if( pc_isfalcon(sd) || pc_isridingwug(sd) || sd->sc.data[SC__GROOMY]) { clif_skill_fail(sd,skill,USESKILL_FAIL_LEVEL,0); return 0; } @@ -10856,6 +10967,13 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh return 0; } break; + case SC_MANHOLE: + case SC_DIMENSIONDOOR: + if( sc && sc->data[SC_MAGNETICFIELD] ) { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; } switch(require.state) { @@ -11270,8 +11388,18 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short if( sd->dsprate!=100 ) req.sp = req.sp * sd->dsprate / 100; + if( sc ) { + if( sc->data[SC__LAZINESS] ) + req.sp += req.sp + sc->data[SC__LAZINESS]->val1 * 10; + if( sc->data[SC_RECOGNIZEDSPELL] ) + req.sp += req.sp / 4; + } + req.zeny = skill_db[j].zeny[lv-1]; + if( sc && sc->data[SC__UNLUCKY] ) + req.zeny += sc->data[SC__UNLUCKY]->val1 * 500; + req.spiritball = skill_db[j].spiritball[lv-1]; req.state = skill_db[j].state; @@ -11466,6 +11594,8 @@ int skill_castfix_sc (struct block_list *bl, int time, int skill_id, int skill_l if (sc->data[SC_POEMBRAGI]) time -= time * sc->data[SC_POEMBRAGI]->val2 / 100; #if RECASTING + if( sc->data[SC__LAZINESS] ) + fixed += fixed * sc->data[SC__LAZINESS]->val2 / 100; /** * AB Sacrament reduces fixed cast time by (10 x Level)% (up to 50%) **/ @@ -12559,15 +12689,8 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int case HP_BASILICA: skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,true); break; - /** - * Ranger - **/ - case RA_ELECTRICSHOCKER: - { - struct block_list* target = map_id2bl(group->val2); - if( target ) - status_change_end(target, SC_ELECTRICSHOCKER, -1); - } + case SC_MAELSTROM: + skill_unitsetmapcell(unit,SC_MAELSTROM,group->skill_lv,CELL_MAELSTROM,true); break; default: if (group->state.song_dance&0x1) //Check for dissonance. @@ -12620,6 +12743,22 @@ int skill_delunit (struct skill_unit* unit) case HP_BASILICA: skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,false); break; + case RA_ELECTRICSHOCKER: { + struct block_list* target = map_id2bl(group->val2); + if( target ) + status_change_end(target, SC_ELECTRICSHOCKER, -1); + break; + } + case SC_MAELSTROM: + skill_unitsetmapcell(unit,SC_MAELSTROM,group->skill_lv,CELL_MAELSTROM,false); + break; + case SC_MANHOLE: // Note : Removing the unit don't remove the status (official info) + if( group->val2 ) { // Someone Traped + struct status_change *tsc = status_get_sc( map_id2bl(group->val2)); + if( tsc && tsc->data[SC__MANHOLE] ) + tsc->data[SC__MANHOLE]->val4 = 0; // Remove the Unit ID + } + break; } clif_skill_delunit(unit); @@ -13033,6 +13172,14 @@ static int skill_unit_timer_sub (DBKey key, void* data, va_list ap) } break; + case UNT_FEINTBOMB: { + struct block_list *src = map_id2bl(group->src_id); + if( src ) + map_foreachinrange(skill_area_sub, &group->unit->bl, unit->range, splash_target(src), src, SC_FEINTBOMB, group->skill_lv, tick, BCT_ENEMY|1, skill_castend_damage_id); + skill_delunit(unit); + break; + } + default: skill_delunit(unit); } @@ -13973,6 +14120,27 @@ int skill_spellbook (struct map_session_data *sd, int nameid) { return 1; } +int skill_select_menu(struct map_session_data *sd,int flag,int skill_id) { + int id, lv, prob, aslvl = 0; + nullpo_ret(sd); + + if (sd->sc.data[SC_STOP]) { + aslvl = sd->sc.data[SC_STOP]->val1; + status_change_end(&sd->bl,SC_STOP,-1); + } + + if( (id = sd->status.skill[skill_id].id) == 0 || sd->status.skill[skill_id].flag != 13 || + skill_id >= GS_GLITTERING || skill_get_type(skill_id) != BF_MAGIC ) { + clif_skill_fail(sd,SC_AUTOSHADOWSPELL,0,0); + return 0; + } + + lv = (aslvl + 1) / 2; // The level the skill will be autocasted + lv = min(lv,sd->status.skill[skill_id].lv); + prob = (aslvl == 10) ? 15 : (32 - 2 * aslvl); // Probability at level 10 was increased to 15. + sc_start4(&sd->bl,SC__AUTOSHADOWSPELL,100,id,lv,prob,0,skill_get_time(SC_AUTOSHADOWSPELL,aslvl)); + return 0; +} /** * for Royal Guard's LG_TRAMPLE **/ @@ -14489,8 +14657,7 @@ void skill_init_unit_layout (void) } // Stasis skill usage check. [LimitLine/3CeAM] -int skill_stasis_check(struct block_list *bl, int src_id, int skillid) -{ +int skill_stasis_check(struct block_list *bl, int src_id, int skillid) { int inf = 0; if( !bl || skillid < 1 ) return 0; // Can do it @@ -14880,6 +15047,18 @@ static bool skill_parse_row_magicmushroomdb(char* split[], int column, int curre return true; } +static bool skill_parse_row_reproducedb(char* split[], int column, int current) { + int skillid = atoi(split[0]); + + skillid = skill_get_index(skillid); + if( !skillid ) + return false; + + skill_reproduce_db[skillid] = true; + + return true; +} + static bool skill_parse_row_abradb(char* split[], int columns, int current) {// SkillID,DummyName,RequiredHocusPocusLevel,Rate @@ -14912,6 +15091,8 @@ static void skill_readdb(void) memset(skill_abra_db,0,sizeof(skill_abra_db)); memset(skill_spellbook_db,0,sizeof(skill_spellbook_db)); memset(skill_magicmushroom_db,0,sizeof(skill_magicmushroom_db)); + memset(skill_reproduce_db,0,sizeof(skill_reproduce_db)); + // load skill databases safestrncpy(skill_db[0].name, "UNKNOWN_SKILL", sizeof(skill_db[0].name)); safestrncpy(skill_db[0].desc, "Unknown Skill", sizeof(skill_db[0].desc)); @@ -14939,6 +15120,7 @@ static void skill_readdb(void) sv_readdb(db_path, "spellbook_db.txt" , ',', 3, 3, MAX_SKILL_SPELLBOOK_DB, skill_parse_row_spellbookdb); //Guillotine Cross sv_readdb(db_path, "magicmushroom_db.txt" , ',', 1, 1, MAX_SKILL_MAGICMUSHROOM_DB, skill_parse_row_magicmushroomdb); + sv_readdb(db_path, "skill_reproduce_db.txt", ',', 1, 1, MAX_SKILL_DB, skill_parse_row_reproducedb); } diff --git a/src/map/skill.h b/src/map/skill.h index 9e087b464..7c325adde 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1575,6 +1575,7 @@ enum wl_spheres { WLS_STONE, }; int skill_spellbook (struct map_session_data *sd, int nameid); +int skill_stasis_check(struct block_list *bl, int src_id, int skillid); /** * Guilottine Cross **/ diff --git a/src/map/status.c b/src/map/status.c index a65de486b..c0628ab24 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -539,22 +539,22 @@ void initChangeTables(void) ///** // * Shadow Chaser // **/ - //set_sc( SC_REPRODUCE , SC__REPRODUCE , SI_REPRODUCE , SCB_NONE ); - //set_sc( SC_AUTOSHADOWSPELL , SC__AUTOSHADOWSPELL, SI_AUTOSHADOWSPELL , SCB_NONE ); - //set_sc( SC_SHADOWFORM , SC__SHADOWFORM , SI_SHADOWFORM , SCB_NONE ); - //set_sc( SC_BODYPAINT , SC__BODYPAINT , SI_BODYPAINTING , SCB_ASPD ); - //set_sc( SC_INVISIBILITY , SC__INVISIBILITY , SI_INVISIBILITY , SCB_ASPD|SCB_CRI|SCB_ATK_ELE ); - //set_sc( SC_DEADLYINFECT , SC__DEADLYINFECT , SI_DEADLYINFECT , SCB_NONE ); - //set_sc( SC_ENERVATION , SC__ENERVATION , SI_ENERVATION , SCB_BATK ); - //set_sc( SC_GROOMY , SC__GROOMY , SI_GROOMY , SCB_ASPD|SCB_HIT|SCB_SPEED ); - //set_sc( SC_IGNORANCE , SC__IGNORANCE , SI_IGNORANCE , SCB_NONE ); - //set_sc( SC_LAZINESS , SC__LAZINESS , SI_LAZINESS , SCB_FLEE ); - //set_sc( SC_UNLUCKY , SC__UNLUCKY , SI_UNLUCKY , SCB_CRI|SCB_FLEE2 ); - //set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_FLEE2|SCB_MAXHP ); - //set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSORY , SI_STRIPACCESSORY , SCB_DEX|SCB_INT|SCB_LUK ); - //set_sc( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); - //add_sc( SC_CHAOSPANIC , SC_CHAOS ); - //set_sc( SC_BLOODYLUST , SC__BLOODYLUST , SI_BLOODYLUST , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); + set_sc( SC_REPRODUCE , SC__REPRODUCE , SI_REPRODUCE , SCB_NONE ); + set_sc( SC_AUTOSHADOWSPELL , SC__AUTOSHADOWSPELL, SI_AUTOSHADOWSPELL , SCB_NONE ); + set_sc( SC_SHADOWFORM , SC__SHADOWFORM , SI_SHADOWFORM , SCB_NONE ); + set_sc( SC_BODYPAINT , SC__BODYPAINT , SI_BODYPAINT , SCB_ASPD ); + set_sc( SC_INVISIBILITY , SC__INVISIBILITY , SI_INVISIBILITY , SCB_ASPD|SCB_CRI|SCB_ATK_ELE ); + set_sc( SC_DEADLYINFECT , SC__DEADLYINFECT , SI_DEADLYINFECT , SCB_NONE ); + set_sc( SC_ENERVATION , SC__ENERVATION , SI_ENERVATION , SCB_BATK ); + set_sc( SC_GROOMY , SC__GROOMY , SI_GROOMY , SCB_ASPD|SCB_HIT|SCB_SPEED ); + set_sc( SC_IGNORANCE , SC__IGNORANCE , SI_IGNORANCE , SCB_NONE ); + set_sc( SC_LAZINESS , SC__LAZINESS , SI_LAZINESS , SCB_FLEE ); + set_sc( SC_UNLUCKY , SC__UNLUCKY , SI_UNLUCKY , SCB_CRI|SCB_FLEE2 ); + set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_FLEE2|SCB_MAXHP ); + set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSORY , SI_STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK ); + set_sc( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); + add_sc( SC_CHAOSPANIC , SC_CHAOS ); + set_sc( SC_BLOODYLUST , SC__BLOODYLUST , SI_BLOODYLUST , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); ///** // * Sura // **/ @@ -978,6 +978,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s status_change_end(target, SC_CLOAKING, INVALID_TIMER); status_change_end(target, SC_CHASEWALK, INVALID_TIMER); status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(target, SC__INVISIBILITY, INVALID_TIMER); if ((sce=sc->data[SC_ENDURE]) && !sce->val4) { //Endure count is only reduced by non-players on non-gvg maps. //val4 signals infinite endure. [Skotlex] @@ -1405,7 +1406,11 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int (sc->data[SC_MARIONETTE2] && skill_num == CG_MARIONETTE) || //Cannot use marionette if you are being buffed by another sc->data[SC_STEELBODY] || sc->data[SC_BERSERK] || - sc->data[SC_OBLIVIONCURSE] + sc->data[SC_OBLIVIONCURSE] || + sc->data[SC_WHITEIMPRISON] || + (sc->data[SC_STASIS] && skill_stasis_check(src, sc->data[SC_STASIS]->val2, skill_num)) || + sc->data[SC__INVISIBILITY] || + sc->data[SC__IGNORANCE] )) return 0; @@ -1418,6 +1423,17 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int ) return 0; + if( sc->data[SC__MANHOLE] || ((tsc = status_get_sc(target)) && tsc->data[SC__MANHOLE]) ) { + switch(skill_num) {//##TODO## make this a flag in skill_db? + // Skills that can be used even under Man Hole effects. + case SC_SHADOWFORM: + case SC_STRIPACCESSARY: + break; + default: + return 0; + } + } + } } @@ -1528,12 +1544,12 @@ int status_check_visibility(struct block_list *src, struct block_list *target) { //Check for chase-walk/hiding/cloaking opponents. case BL_PC: if ( tsc->data[SC_CLOAKINGEXCEED] && !(status->mode&MD_BOSS) ) - if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&MD_BOSS) && + if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY] || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&MD_BOSS) && ( ((TBL_PC*)target)->special_state.perfect_hiding || !(status->mode&MD_DETECTOR) ) ) return 0; break; default: - if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&(MD_BOSS|MD_DETECTOR)) ) + if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY] || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&(MD_BOSS|MD_DETECTOR)) ) return 0; } @@ -3778,6 +3794,8 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang int_ += ((sc->data[SC_MARIONETTE2]->val4)>>16)&0xFF; if(sc->data[SC_INSPIRATION]) int_ += sc->data[SC_INSPIRATION]->val3; + if(sc->data[SC__STRIPACCESSORY]) + int_ -= int_ * sc->data[SC__STRIPACCESSORY]->val2 / 100; if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && int_ < 50) int_ = 50; @@ -3822,6 +3840,8 @@ static unsigned short status_calc_dex(struct block_list *bl, struct status_chang dex += ((sc->data[SC_MARIONETTE2]->val4)>>8)&0xFF; if(sc->data[SC_INSPIRATION]) dex += sc->data[SC_INSPIRATION]->val3; + if(sc->data[SC__STRIPACCESSORY]) + dex -= dex * sc->data[SC__STRIPACCESSORY]->val2 / 100; if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && dex < 50) dex = 50; @@ -3853,6 +3873,8 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang luk += sc->data[SC_MARIONETTE2]->val4&0xFF; if(sc->data[SC_INSPIRATION]) luk += sc->data[SC_INSPIRATION]->val3; + if(sc->data[SC__STRIPACCESSORY]) + luk -= luk * sc->data[SC__STRIPACCESSORY]->val2 / 100; if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && luk < 50) luk = 50; @@ -3891,6 +3913,10 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan batk += sc->data[SC_GATLINGFEVER]->val3; if(sc->data[SC_MADNESSCANCEL]) batk += 100; + if(sc->data[SC__ENERVATION]) + batk -= batk * sc->data[SC__ENERVATION]->val2 / 100; + if(sc->data[SC__BLOODYLUST]) + batk += batk * 32 / 100; #if RE_EDP /** * in RE EDP increases your base atk by atk x Skill Level. @@ -3932,8 +3958,10 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan watk += sc->data[SC_NIBELUNGEN]->val2; } } - if(sc->data[SC_BLOODLUST]) - watk += watk * sc->data[SC_BLOODLUST]->val2/100; + if(sc->data[SC__ENERVATION]) + watk -= watk * sc->data[SC__ENERVATION]->val2 / 100; + if(sc->data[SC__BLOODYLUST]) + watk += watk * 32 / 100; if(sc->data[SC_FLEET]) watk += watk * sc->data[SC_FLEET]->val3/100; if(sc->data[SC_CURSE]) @@ -3994,8 +4022,13 @@ static signed short status_calc_critical(struct block_list *bl, struct status_ch critical += sc->data[SC_TRUESIGHT]->val2; if(sc->data[SC_CLOAKING]) critical += critical; + if(sc->data[SC__INVISIBILITY]) + critical += critical * sc->data[SC__INVISIBILITY]->val3 / 100; if(sc->data[SC_CAMOUFLAGE]) critical += 100; + if(sc->data[SC__UNLUCKY]) + critical -= critical * sc->data[SC__UNLUCKY]->val2 / 100; + return (short)cap_value(critical,10,SHRT_MAX); } @@ -4026,6 +4059,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__GROOMY]) + hit -= hit * sc->data[SC__GROOMY]->val3 / 100; if(sc->data[SC_FEAR]) hit -= hit * 20 / 100; if(sc->data[SC_INSPIRATION]) @@ -4113,6 +4148,8 @@ static signed short status_calc_flee2(struct block_list *bl, struct status_chang flee2 += sc->data[SC_INCFLEE2]->val2; if(sc->data[SC_WHISTLE]) flee2 += sc->data[SC_WHISTLE]->val3*10; + if(sc->data[SC__UNLUCKY]) + flee2 -= flee2 * sc->data[SC__UNLUCKY]->val2 / 100; return (short)cap_value(flee2,10,SHRT_MAX); } @@ -4665,6 +4702,8 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang maxhp += maxhp * 5 * sc->data[SC_EPICLESIS]->val1 / 100; if(sc->data[SC_VENOMBLEED]) maxhp -= maxhp * 15 / 100; + if(sc->data[SC__WEAKNESS]) + maxhp -= maxhp * sc->data[SC__WEAKNESS]->val2 / 100; if(sc->data[SC_FORCEOFVANGUARD]) maxhp += maxhp * 3 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; if(sc->data[SC_INSPIRATION]) //Custom value. @@ -4727,6 +4766,8 @@ static unsigned char status_calc_element_lv(struct block_list *bl, struct status return sc->data[SC_ELEMENTALCHANGE]->val1; if(sc->data[SC_SHAPESHIFT]) return 1; + if(sc->data[SC__INVISIBILITY]) + return 1; return (unsigned char)cap_value(lv,1,4); } @@ -4752,7 +4793,7 @@ unsigned char status_calc_attack_element(struct block_list *bl, struct status_ch return ELE_HOLY; if(sc->data[SC_SHADOWWEAPON]) return ELE_DARK; - if(sc->data[SC_GHOSTWEAPON]) + if(sc->data[SC_GHOSTWEAPON] || sc->data[SC__INVISIBILITY]) return ELE_GHOST; return (unsigned char)cap_value(element,0,UCHAR_MAX); } @@ -5214,39 +5255,48 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti //Status that are blocked by Golden Thief Bug card or Wand of Hermod if (status_isimmune(bl)) - switch (type) - { - case SC_DECREASEAGI: - case SC_SILENCE: - case SC_COMA: - case SC_INCREASEAGI: - case SC_BLESSING: - case SC_SLOWPOISON: - case SC_IMPOSITIO: - case SC_AETERNA: - case SC_SUFFRAGIUM: - case SC_BENEDICTIO: - case SC_PROVIDENCE: - case SC_KYRIE: - case SC_ASSUMPTIO: - case SC_ANGELUS: - case SC_MAGNIFICAT: - case SC_GLORIA: - case SC_WINDWALK: - case SC_MAGICROD: - case SC_HALLUCINATION: - case SC_STONE: - case SC_QUAGMIRE: - case SC_SUITON: - return 0; - } + switch (type) { + case SC_DECREASEAGI: + case SC_SILENCE: + case SC_COMA: + case SC_INCREASEAGI: + case SC_BLESSING: + case SC_SLOWPOISON: + case SC_IMPOSITIO: + case SC_AETERNA: + case SC_SUFFRAGIUM: + case SC_BENEDICTIO: + case SC_PROVIDENCE: + case SC_KYRIE: + case SC_ASSUMPTIO: + case SC_ANGELUS: + case SC_MAGNIFICAT: + case SC_GLORIA: + case SC_WINDWALK: + case SC_MAGICROD: + case SC_HALLUCINATION: + case SC_STONE: + case SC_QUAGMIRE: + case SC_SUITON: + case SC__ENERVATION: + case SC__GROOMY: + case SC__IGNORANCE: + case SC__LAZINESS: + case SC__UNLUCKY: + case SC__WEAKNESS: + return 0; + } sd = BL_CAST(BL_PC,bl); status = status_get_status_data(bl); - switch (type) - { + sc = status_get_sc(bl); + if( sc && !sc->count ) + sc = NULL; + switch (type) { case SC_STUN: case SC_POISON: + if( sc && sc->data[SC__UNLUCKY] ) + return tick; case SC_DPOISON: case SC_SILENCE: case SC_BLEEDING: @@ -5271,6 +5321,8 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti tick_def = status->vit; break; case SC_BLIND: + if( sc && sc->data[SC__UNLUCKY] ) + return tick; sc_def = 3 +(status->vit + status->int_)/2; break; case SC_CONFUSION: @@ -5360,9 +5412,7 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti } } - sc = status_get_sc(bl); - if (sc && sc->count) - { + if (sc) { if (sc->data[SC_SCRESIST]) sc_def += sc->data[SC_SCRESIST]->val1; //Status resist else if (sc->data[SC_SIEGFRIED]) @@ -5741,6 +5791,23 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( sd && pc_checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill_check_camouflage(bl,NULL) ) return 0; break; + case SC__STRIPACCESSORY: + if( sd ) { + int i = -1; + if( !(sd->unstripable_equip&EQI_ACC_L) ) { + i = sd->equip_index[EQI_ACC_L]; + if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) + pc_unequipitem(sd,i,3); //L-Accessory + } if( !(sd->unstripable_equip&EQI_ACC_R) ) { + i = sd->equip_index[EQI_ACC_R]; + if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) + pc_unequipitem(sd,i,3); //R-Accessory + } + if( i < 0 ) + return 0; + } + if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC + break; } //Check for BOSS resistances @@ -5972,6 +6039,14 @@ 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__INVISIBILITY: + case SC__ENERVATION: + case SC__GROOMY: + case SC__IGNORANCE: + case SC__LAZINESS: + case SC__WEAKNESS: + case SC__UNLUCKY: + case SC_CHAOS: return 0; case SC_COMBO: case SC_DANCING: @@ -6996,11 +7071,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val4 = gettick(); //Store time at which you started running. tick = -1; break; - case SC__SHADOWFORM: - { - //struct map_session_data * s_sd = map_id2sd(val2); - //if( s_sd ) - // s_sd->shadowform_id = bl->id; + case SC__SHADOWFORM: { + struct map_session_data * s_sd = map_id2sd(val2); + if( s_sd ) + s_sd->shadowform_id = bl->id; val4 = tick / 1000; val_flag |= 1|2|4; tick_time = 1000; // [GodLesZ] tick time @@ -7381,6 +7455,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_ANKLE: case SC_SPIDERWEB: case SC_ELECTRICSHOCKER: + case SC_BITE: + case SC__MANHOLE: + case SC_CHAOS: unit_stop_walking(bl,1); break; case SC_HIDING: @@ -7412,7 +7489,12 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_POISON: sc->opt2 |= OPT2_POISON; break; case SC_CURSE: sc->opt2 |= OPT2_CURSE; break; case SC_SILENCE: sc->opt2 |= OPT2_SILENCE; break; - case SC_SIGNUMCRUCIS: sc->opt2 |= OPT2_SIGNUMCRUCIS; break; + + case SC_SIGNUMCRUCIS: + case SC_CHAOS: + sc->opt2 |= OPT2_SIGNUMCRUCIS; + break; + case SC_BLIND: sc->opt2 |= OPT2_BLIND; break; case SC_ANGELUS: sc->opt2 |= OPT2_ANGELUS; break; case SC_BLEEDING: sc->opt2 |= OPT2_BLEEDING; break; @@ -7513,6 +7595,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_CLOAKING: case SC_CLOAKINGEXCEED: + case SC__INVISIBILITY: sc->option |= OPTION_CLOAK; opt_flag = 2; break; @@ -8066,6 +8149,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const if (vd) vd->dead_sit = 0; break; case SC_WARM: + case SC__MANHOLE: if (sce->val4) { //Clear the group. struct skill_unit_group* group = skill_id2group(sce->val4); sce->val4 = 0; @@ -8138,9 +8222,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_ADORAMUS: status_change_end(bl, SC_BLIND, -1); break; - /* - case SC__SHADOWFORM: - { + case SC__SHADOWFORM: { struct map_session_data *s_sd = map_id2sd(sce->val2); if( !s_sd ) break; @@ -8148,13 +8230,11 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } break; case SC_SITDOWN_FORCE: - if( sd && pc_issit(sd) ) - { + if( sd && pc_issit(sd) ) { pc_setstand(sd); - clif_standing(bl,true); + clif_standing(bl); } break; - */ case SC_NEUTRALBARRIER_MASTER: case SC_STEALTHFIELD_MASTER: if( sce->val2 ) @@ -8216,6 +8296,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const sc->opt2 &= ~OPT2_DPOISON; break; case SC_SIGNUMCRUCIS: + case SC_CHAOS: sc->opt2 &= ~OPT2_SIGNUMCRUCIS; break; @@ -8225,6 +8306,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_CLOAKING: case SC_CLOAKINGEXCEED: + case SC__INVISIBILITY: sc->option &= ~OPTION_CLOAK; opt_flag|= 2; break; @@ -9226,13 +9308,17 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC__INVISIBILITY, INVALID_TIMER); break; case SC_RUWACH: /* ƒ‹ƒAƒt */ - if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED])) { + if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || + tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED] || + tsc->data[SC__INVISIBILITY])) { status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + status_change_end(bl, SC__INVISIBILITY, INVALID_TIMER); if(battle_check_target( src, bl, BCT_ENEMY ) > 0) skill_attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0); } @@ -9317,6 +9403,15 @@ int status_change_clear_buffs (struct block_list* bl, int type) case SC_EXPBOOST: case SC_JEXPBOOST: case SC_ITEMBOOST: + case SC_ELECTRICSHOCKER: + case SC__MANHOLE: + case SC_GIANTGROWTH: + case SC_MILLENNIUMSHIELD: + case SC_REFRESH: + case SC_STONEHARDSKIN: + case SC_VITALITYACTIVATION: + case SC_FIGHTINGSPIRIT: + case SC_ABUNDANCE: continue; //Debuffs that can be removed. @@ -9352,6 +9447,81 @@ int status_change_clear_buffs (struct block_list* bl, int type) return 0; } +int status_change_spread( struct block_list *src, struct block_list *bl ) { + int i, flag = 0; + struct status_change *sc = status_get_sc(src); + const struct TimerData *timer; + unsigned int tick; + struct status_change_data data; + + if( !sc || !sc->count ) + return 0; + + tick = gettick(); + + for( i = SC_COMMON_MIN; i < SC_MAX; i++ ) { + if( !sc->data[i] || i == SC_COMMON_MAX ) + continue; + + switch( i ) { + //Debuffs that can be spreaded. + // NOTE: We'll add/delte SCs when we are able to confirm it. + case SC_POISON: + case SC_CURSE: + case SC_SILENCE: + case SC_CONFUSION: + case SC_BLIND: + case SC_BLEEDING: + case SC_DPOISON: + case SC_NOCHAT: + case SC_HALLUCINATION: + case SC_SIGNUMCRUCIS: + case SC_DECREASEAGI: + case SC_SLOWDOWN: + case SC_MINDBREAKER: + case SC_WINKCHARM: + case SC_STOP: + case SC_ORCISH: + //case SC_STRIPWEAPON://Omg I got infected and had the urge to strip myself physically. + //case SC_STRIPSHIELD://No this is stupid and shouldnt be spreadable at all. + //case SC_STRIPARMOR:// Disabled until I can confirm if it does or not. [Rytech] + //case SC_STRIPHELM: + //case SC__STRIPACCESSORY: + case SC_BITE: + case SC_FREEZING: + case SC_BURNING: + case SC_FEAR: + case SC_PYREXIA: + case SC_PARALYSE: + case SC_DEATHHURT: + case SC_MAGICMUSHROOM: + case SC_VENOMBLEED: + case SC_TOXIN: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + if( sc->data[i]->timer != INVALID_TIMER ) { + timer = get_timer(sc->data[i]->timer); + if (timer == NULL || timer->func != status_change_timer || DIFF_TICK(timer->tick,tick) < 0) + continue; + data.tick = DIFF_TICK(timer->tick,tick); + } else + data.tick = INVALID_TIMER; + data.val1 = sc->data[i]->val1; + data.val2 = sc->data[i]->val2; + data.val3 = sc->data[i]->val3; + data.val4 = sc->data[i]->val4; + status_change_start(bl,i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,1|2|8); + flag = 1; + break; + default: + continue; + break; + } + } + + return flag; +} + //Natural regen related stuff. static unsigned int natural_heal_prev_tick,natural_heal_diff_tick; static int status_natural_heal(struct block_list* bl, va_list args) @@ -9381,7 +9551,7 @@ static int status_natural_heal(struct block_list* bl, va_list args) if (flag && ( status_isdead(bl) || - (sc && sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) + (sc && (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || sc->data[SC__INVISIBILITY])) )) flag=0; diff --git a/src/map/status.h b/src/map/status.h index 1e72f9b5f..bd150977a 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -1584,6 +1584,8 @@ int status_getrefinebonus(int lv,int type); int status_check_skilluse(struct block_list *src, struct block_list *target, int skill_num, int flag); // [Skotlex] int status_check_visibility(struct block_list *src, struct block_list *target); //[Skotlex] +int status_change_spread( struct block_list *src, struct block_list *bl ); + int status_readdb(void); int do_init_status(void); void do_final_status(void); diff --git a/src/map/unit.c b/src/map/unit.c index 511a33fe6..e541cd549 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -930,6 +930,12 @@ 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_WHITEIMPRISON] + || sc->data[SC_ELECTRICSHOCKER] + || sc->data[SC_BITE] + || sc->data[SC_MAGNETICFIELD] + || sc->data[SC__MANHOLE] + || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val2 > 0) )) return 0; } @@ -1990,6 +1996,9 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, status_change_end(bl, SC_CHANGE, INVALID_TIMER); status_change_end(bl, SC_STOP, INVALID_TIMER); status_change_end(bl, SC_WUGDASH, INVALID_TIMER); + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + status_change_end(bl, SC__MANHOLE, INVALID_TIMER); + } if (bl->type&(BL_CHAR|BL_PET)) { -- cgit v1.2.3-70-g09d2