summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
authorshennetsind <shennetsind@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-02-17 15:33:13 +0000
committershennetsind <shennetsind@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-02-17 15:33:13 +0000
commit5cc9f30cbe8c57a97e58a5a3b5387622e4304873 (patch)
treefa7590892983540d46245781a83d9fb2a08ecaa4 /src/map
parentc021f63e10a7dca24119e436e2450e0bbb2266a3 (diff)
downloadhercules-5cc9f30cbe8c57a97e58a5a3b5387622e4304873.tar.gz
hercules-5cc9f30cbe8c57a97e58a5a3b5387622e4304873.tar.bz2
hercules-5cc9f30cbe8c57a97e58a5a3b5387622e4304873.tar.xz
hercules-5cc9f30cbe8c57a97e58a5a3b5387622e4304873.zip
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
Diffstat (limited to 'src/map')
-rw-r--r--src/map/battle.c83
-rw-r--r--src/map/clif.c32
-rw-r--r--src/map/clif.h4
-rw-r--r--src/map/map.c3
-rw-r--r--src/map/map.h7
-rw-r--r--src/map/pc.c24
-rw-r--r--src/map/pc.h4
-rw-r--r--src/map/skill.c416
-rw-r--r--src/map/skill.h1
-rw-r--r--src/map/status.c306
-rw-r--r--src/map/status.h2
-rw-r--r--src/map/unit.c9
12 files changed, 699 insertions, 192 deletions
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
@@ -735,6 +735,10 @@ int clif_magicdecoy_list(struct map_session_data *sd, int skill_lv, short x, sho
**/
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
**/
int clif_status_load_notick(struct block_list *bl,int type,int flag,int val1, int val2, int val3);
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)) {