From 5cc9f30cbe8c57a97e58a5a3b5387622e4304873 Mon Sep 17 00:00:00 2001
From: shennetsind <shennetsind@54d463be-8e91-2dee-dedb-b68131a5f0ec>
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