Browse Source

Bug Fixes
* Fixes #696 - Fixed an issue with ammo type fail message for bows and guns.
* Fixes #708 - Fixed Neutral Barrier and Stealth Field not staying with the player through warp portals on the same map. Thanks to @exneval.
* Added the new Pile Bunker S/P/T items to the Pile Bunker skill equipment check.
* Updated Exeed Break damage formula.
* Added a check for skill_require_db parsing to skip requirements on invalid item IDs.

aleos89 9 years ago
parent
commit
a7b8fd4a5d

+ 1 - 1
db/pre-re/skill_require_db.txt

@@ -680,7 +680,7 @@
 //****
 //****
 // NC Mechanic
 // NC Mechanic
 2256,0,0,3:6:9:12:15,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//NC_BOOSTKNUCKLE
 2256,0,0,3:6:9:12:15,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//NC_BOOSTKNUCKLE
-2257,0,0,50,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1549							//NC_PILEBUNKER
+2257,0,0,50,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1549:16030:16031:16032		//NC_PILEBUNKER
 2258,0,0,2:4:6,0,0,0,99,0,0,mado,0,0,6145,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_VULCANARM
 2258,0,0,2:4:6,0,0,0,99,0,0,mado,0,0,6145,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_VULCANARM
 2259,0,0,20,0,0,0,99,0,0,mado,0,0,2139,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_FLAMELAUNCHER
 2259,0,0,20,0,0,0,99,0,0,mado,0,0,2139,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_FLAMELAUNCHER
 2260,0,0,20,0,0,0,99,0,0,mado,0,0,6146,1,6147,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_COLDSLOWER
 2260,0,0,20,0,0,0,99,0,0,mado,0,0,6146,1,6147,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_COLDSLOWER

+ 1 - 1
db/pre-re/skill_unit_db.txt

@@ -123,7 +123,7 @@
 2254,0xd7,    ,  0, 1,1000,enemy, 0x8002	//RA_ICEBOUNDTRAP
 2254,0xd7,    ,  0, 1,1000,enemy, 0x8002	//RA_ICEBOUNDTRAP
 
 
 2273,0xe2,    ,  2, 0,  -1,all,   0x000	//NC_NEUTRALBARRIER
 2273,0xe2,    ,  2, 0,  -1,all,   0x000	//NC_NEUTRALBARRIER
-2274,0xe3,    ,  2, 0,  -1,friend,0x000	//NC_STEALTHFIELD
+2274,0xe3,    ,  2, 0,  -1,ally,  0x000	//NC_STEALTHFIELD
 
 
 2299,0xcc,    ,  0, 1,1000,all,   0x8006 //SC_MANHOLE
 2299,0xcc,    ,  0, 1,1000,all,   0x8006 //SC_MANHOLE
 2300,0xcd,    ,  0, 0,1000,all,   0xC006 //SC_DIMENSIONDOOR
 2300,0xcd,    ,  0, 0,1000,all,   0xC006 //SC_DIMENSIONDOOR

+ 1 - 1
db/re/skill_require_db.txt

@@ -680,7 +680,7 @@
 //****
 //****
 // NC Mechanic
 // NC Mechanic
 2256,0,0,3:6:9:12:15,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//NC_BOOSTKNUCKLE
 2256,0,0,3:6:9:12:15,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//NC_BOOSTKNUCKLE
-2257,0,0,50,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1549							//NC_PILEBUNKER
+2257,0,0,50,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1549:16030:16031:16032		//NC_PILEBUNKER
 2258,0,0,2:4:6,0,0,0,99,0,0,mado,0,0,6145,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_VULCANARM
 2258,0,0,2:4:6,0,0,0,99,0,0,mado,0,0,6145,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_VULCANARM
 2259,0,0,20,0,0,0,99,0,0,mado,0,0,2139,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_FLAMELAUNCHER
 2259,0,0,20,0,0,0,99,0,0,mado,0,0,2139,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_FLAMELAUNCHER
 2260,0,0,20,0,0,0,99,0,0,mado,0,0,6146,1,6147,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_COLDSLOWER
 2260,0,0,20,0,0,0,99,0,0,mado,0,0,6146,1,6147,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//NC_COLDSLOWER

+ 1 - 1
db/re/skill_unit_db.txt

@@ -125,7 +125,7 @@
 2254,0xd7,    ,  0, 1,1000,enemy, 0x8002	//RA_ICEBOUNDTRAP
 2254,0xd7,    ,  0, 1,1000,enemy, 0x8002	//RA_ICEBOUNDTRAP
 
 
 2273,0xe2,    ,  2, 0,  -1,all,   0x000	//NC_NEUTRALBARRIER
 2273,0xe2,    ,  2, 0,  -1,all,   0x000	//NC_NEUTRALBARRIER
-2274,0xe3,    ,  2, 0,  -1,friend,0x000	//NC_STEALTHFIELD
+2274,0xe3,    ,  2, 0,  -1,ally,  0x000	//NC_STEALTHFIELD
 
 
 2299,0xcc,    ,  0, 1,1000,all,   0x8006 //SC_MANHOLE
 2299,0xcc,    ,  0, 1,1000,all,   0x8006 //SC_MANHOLE
 2300,0xcd,    ,  0, 0,1000,all,   0xC006 //SC_DIMENSIONDOOR
 2300,0xcd,    ,  0, 0,1000,all,   0xC006 //SC_DIMENSIONDOOR

+ 2 - 2
src/map/battle.c

@@ -6909,7 +6909,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 		{
 		{
 			short index = sd->equip_index[EQI_AMMO];
 			short index = sd->equip_index[EQI_AMMO];
 			if (index < 0) {
 			if (index < 0) {
-				if (sd->weapontype1 > W_KATAR || sd->weapontype1 < W_HUUMA)
+				if (sd->weapontype1 > W_KATAR && sd->weapontype1 < W_HUUMA)
 					clif_skill_fail(sd,0,USESKILL_FAIL_NEED_MORE_BULLET,0);
 					clif_skill_fail(sd,0,USESKILL_FAIL_NEED_MORE_BULLET,0);
 				else
 				else
 					clif_arrow_fail(sd,0);
 					clif_arrow_fail(sd,0);
@@ -7054,7 +7054,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 
 
 	if( sc && sc->count ) {
 	if( sc && sc->count ) {
 		if (sc->data[SC_EXEEDBREAK]) {
 		if (sc->data[SC_EXEEDBREAK]) {
-			wd.damage *= sc->data[SC_EXEEDBREAK]->val1 / 100;
+			wd.damage *= sc->data[SC_EXEEDBREAK]->val2 / 100;
 			status_change_end(src, SC_EXEEDBREAK, INVALID_TIMER);
 			status_change_end(src, SC_EXEEDBREAK, INVALID_TIMER);
 		}
 		}
 		if( sc->data[SC_SPELLFIST] ) {
 		if( sc->data[SC_SPELLFIST] ) {

+ 44 - 18
src/map/skill.c

@@ -12910,12 +12910,16 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, un
 
 
 		case UNT_STEALTHFIELD:
 		case UNT_STEALTHFIELD:
 			if( bl->id == sg->src_id )
 			if( bl->id == sg->src_id )
-				break; // Dont work on Self (video shows that)
-		case UNT_NEUTRALBARRIER:
+				break; // Doesn't work on self (video shows that)
 			if (!sce)
 			if (!sce)
 				sc_start(ss, bl,type,100,sg->skill_lv,sg->limit);
 				sc_start(ss, bl,type,100,sg->skill_lv,sg->limit);
 			break;
 			break;
 
 
+		case UNT_NEUTRALBARRIER:
+			if (!sce)
+				status_change_start(ss, bl, type, 10000, sg->skill_lv, 0, 0, 0, sg->limit, SCSTART_NOICON);
+			break;
+
 		case UNT_GD_LEADERSHIP:
 		case UNT_GD_LEADERSHIP:
 		case UNT_GD_GLORYWOUNDS:
 		case UNT_GD_GLORYWOUNDS:
 		case UNT_GD_SOULCOLD:
 		case UNT_GD_SOULCOLD:
@@ -17470,6 +17474,8 @@ int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int li
 			case DC_DONTFORGETME:
 			case DC_DONTFORGETME:
 			case DC_FORTUNEKISS:
 			case DC_FORTUNEKISS:
 			case DC_SERVICEFORYOU:
 			case DC_SERVICEFORYOU:
+			case NC_NEUTRALBARRIER:
+			case NC_STEALTHFIELD:
 				skill_usave_add(((TBL_PC*)src), group->skill_id, group->skill_lv);
 				skill_usave_add(((TBL_PC*)src), group->skill_id, group->skill_lv);
 				break;
 				break;
 		}
 		}
@@ -19441,33 +19447,42 @@ int skill_blockmerc_start(struct mercenary_data *md, uint16 skill_id, int tick)
 }
 }
 /**
 /**
  * Adds a new skill unit entry for this player to recast after map load
  * Adds a new skill unit entry for this player to recast after map load
+ * @param sd: Player
+ * @param skill_id: Skill ID to save
+ * @param skill_lv: Skill level to save
  */
  */
-void skill_usave_add(struct map_session_data * sd, uint16 skill_id, uint16 skill_lv) {
-	struct skill_usave * sus = NULL;
+void skill_usave_add(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv)
+{
+	struct skill_usave *sus = NULL;
 
 
-	if( idb_exists(skillusave_db,sd->status.char_id) ) {
+	if (idb_exists(skillusave_db,sd->status.char_id))
 		idb_remove(skillusave_db,sd->status.char_id);
 		idb_remove(skillusave_db,sd->status.char_id);
-	}
 
 
 	CREATE(sus, struct skill_usave, 1);
 	CREATE(sus, struct skill_usave, 1);
 	idb_put(skillusave_db, sd->status.char_id, sus);
 	idb_put(skillusave_db, sd->status.char_id, sus);
 
 
 	sus->skill_id = skill_id;
 	sus->skill_id = skill_id;
 	sus->skill_lv = skill_lv;
 	sus->skill_lv = skill_lv;
-
-	return;
 }
 }
-void skill_usave_trigger(struct map_session_data *sd) {
-	struct skill_usave * sus = NULL;
 
 
-	if( ! (sus = (struct skill_usave *)idb_get(skillusave_db,sd->status.char_id)) )
-		return;
+/**
+ * Loads saved skill unit entries for this player after map load
+ * @param sd: Player
+ */
+void skill_usave_trigger(struct map_session_data *sd)
+{
+	struct skill_usave *sus = NULL;
+	struct skill_unit_group *group = NULL;
 
 
-	skill_unitsetting(&sd->bl,sus->skill_id,sus->skill_lv,sd->bl.x,sd->bl.y,0);
-	idb_remove(skillusave_db,sd->status.char_id);
+	if (!(sus = idb_get(skillusave_db,sd->status.char_id)))
+		return;
 
 
-	return;
+	if ((group = skill_unitsetting(&sd->bl, sus->skill_id, sus->skill_lv, sd->bl.x, sd->bl.y, 0)))
+		if (sus->skill_id == NC_NEUTRALBARRIER || sus->skill_id == NC_STEALTHFIELD )
+			sc_start2(&sd->bl, &sd->bl, (sus->skill_id == NC_NEUTRALBARRIER ? SC_NEUTRALBARRIER_MASTER : SC_STEALTHFIELD_MASTER), 100, sus->skill_lv, group->group_id, skill_get_time(sus->skill_id, sus->skill_lv));
+	idb_remove(skillusave_db, sd->status.char_id);
 }
 }
+
 /*
 /*
  *
  *
  */
  */
@@ -20150,7 +20165,7 @@ static bool skill_parse_row_skilldb(char* split[], int columns, int current)
 }
 }
 
 
 /**
 /**
- * Split string to int by constanta value (const.txt) or atoi()
+ * Split string to int by constant value (const.txt) or atoi()
  * @param *str: String input
  * @param *str: String input
  * @param *val: Temporary storage
  * @param *val: Temporary storage
  * @param *delim: Delimiter (for multiple value support)
  * @param *delim: Delimiter (for multiple value support)
@@ -20164,6 +20179,7 @@ uint8 skill_split_atoi2(char *str, int *val, const char *delim, int min_value, u
 
 
 	while (p != NULL) {
 	while (p != NULL) {
 		int n = min_value;
 		int n = min_value;
+
 		trim(p);
 		trim(p);
 
 
 		if (ISDIGIT(p[0])) // If using numeric
 		if (ISDIGIT(p[0])) // If using numeric
@@ -20200,7 +20216,7 @@ static void skill_destroy_requirement(uint16 idx) {
 
 
 /**
 /**
  * Read skill requirement from skill_require_db.txt
  * Read skill requirement from skill_require_db.txt
- * Structure: skill_id,HPCost,MaxHPTrigger,SPCost,HPRateCost,SPRateCost,ZenyCost,RequiredWeapons,RequiredAmmoTypes,RequiredAmmoAmount,RequiredState,RequiredStatuss,SpiritSphereCost,RequiredItemID1,RequiredItemAmount1,RequiredItemID2,RequiredItemAmount2,RequiredItemID3,RequiredItemAmount3,RequiredItemID4,RequiredItemAmount4,RequiredItemID5,RequiredItemAmount5,RequiredItemID6,RequiredItemAmount6,RequiredItemID7,RequiredItemAmount7,RequiredItemID8,RequiredItemAmount8,RequiredItemID9,RequiredItemAmount9,RequiredItemID10,RequiredItemAmount10
+ * Structure: skill_id,HPCost,MaxHPTrigger,SPCost,HPRateCost,SPRateCost,ZenyCost,RequiredWeapons,RequiredAmmoTypes,RequiredAmmoAmount,RequiredState,RequiredStatuses,SpiritSphereCost,RequiredItemID1,RequiredItemAmount1,RequiredItemID2,RequiredItemAmount2,RequiredItemID3,RequiredItemAmount3,RequiredItemID4,RequiredItemAmount4,RequiredItemID5,RequiredItemAmount5,RequiredItemID6,RequiredItemAmount6,RequiredItemID7,RequiredItemAmount7,RequiredItemID8,RequiredItemAmount8,RequiredItemID9,RequiredItemAmount9,RequiredItemID10,RequiredItemAmount10,RequiredEquipment
  */
  */
 static bool skill_parse_row_requiredb(char* split[], int columns, int current)
 static bool skill_parse_row_requiredb(char* split[], int columns, int current)
 {
 {
@@ -20269,6 +20285,7 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current)
 	trim(split[11]);
 	trim(split[11]);
 	if (split[11][0] != '\0' || atoi(split[11])) {
 	if (split[11][0] != '\0' || atoi(split[11])) {
 		int require[MAX_SKILL_STATUS_REQUIRE];
 		int require[MAX_SKILL_STATUS_REQUIRE];
+
 		if ((skill_db[idx]->require.status_count = skill_split_atoi2(split[11], require, ":", SC_STONE, ARRAYLENGTH(require)))) {
 		if ((skill_db[idx]->require.status_count = skill_split_atoi2(split[11], require, ":", SC_STONE, ARRAYLENGTH(require)))) {
 			CREATE(skill_db[idx]->require.status, enum sc_type, skill_db[idx]->require.status_count);
 			CREATE(skill_db[idx]->require.status, enum sc_type, skill_db[idx]->require.status_count);
 			for (i = 0; i < skill_db[idx]->require.status_count; i++)
 			for (i = 0; i < skill_db[idx]->require.status_count; i++)
@@ -20279,16 +20296,25 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current)
 	skill_split_atoi(split[12],skill_db[idx]->require.spiritball);
 	skill_split_atoi(split[12],skill_db[idx]->require.spiritball);
 
 
 	for( i = 0; i < MAX_SKILL_ITEM_REQUIRE; i++ ) {
 	for( i = 0; i < MAX_SKILL_ITEM_REQUIRE; i++ ) {
+		if (atoi(split[13 + 2 * i]) > 0 && !itemdb_exists(atoi(split[13 + 2 * i]))) {
+			ShowError("skill_parse_row_requiredb: Invalid item %d for skill %d.\n", atoi(split[13 + 2 * i]), atoi(split[0]));
+			return false;
+		}
 		skill_db[idx]->require.itemid[i] = atoi(split[13+ 2*i]);
 		skill_db[idx]->require.itemid[i] = atoi(split[13+ 2*i]);
 		skill_db[idx]->require.amount[i] = atoi(split[14+ 2*i]);
 		skill_db[idx]->require.amount[i] = atoi(split[14+ 2*i]);
 	}
 	}
 
 
 	//Equipped Item requirements.
 	//Equipped Item requirements.
-	//NOTE: We don't check the item is exist or not here
 	trim(split[33]);
 	trim(split[33]);
 	if (split[33][0] != '\0' || atoi(split[33])) {
 	if (split[33][0] != '\0' || atoi(split[33])) {
 		int require[MAX_SKILL_EQUIP_REQUIRE];
 		int require[MAX_SKILL_EQUIP_REQUIRE];
+
 		if ((skill_db[idx]->require.eqItem_count = skill_split_atoi2(split[33], require, ":", 500, ARRAYLENGTH(require)))) {
 		if ((skill_db[idx]->require.eqItem_count = skill_split_atoi2(split[33], require, ":", 500, ARRAYLENGTH(require)))) {
+			if (require[i] > 0 && !itemdb_exists(require[i])) {
+				ShowError("skill_parse_row_requiredb: Invalid item %d for skill %d.\n", require[i], atoi(split[0]));
+				return false;
+			}
+
 			CREATE(skill_db[idx]->require.eqItem, uint16, skill_db[idx]->require.eqItem_count);
 			CREATE(skill_db[idx]->require.eqItem, uint16, skill_db[idx]->require.eqItem_count);
 			for (i = 0; i < skill_db[idx]->require.eqItem_count; i++)
 			for (i = 0; i < skill_db[idx]->require.eqItem_count; i++)
 				skill_db[idx]->require.eqItem[i] = require[i];
 				skill_db[idx]->require.eqItem[i] = require[i];

+ 15 - 11
src/map/status.c

@@ -1166,6 +1166,7 @@ void initChangeTables(void)
 	StatusDisplayType[SC_SPHERE_4]		  = true;
 	StatusDisplayType[SC_SPHERE_4]		  = true;
 	StatusDisplayType[SC_SPHERE_5]		  = true;
 	StatusDisplayType[SC_SPHERE_5]		  = true;
 	StatusDisplayType[SC_CAMOUFLAGE]	  = true;
 	StatusDisplayType[SC_CAMOUFLAGE]	  = true;
+	StatusDisplayType[SC_STEALTHFIELD]	  = true;
 	StatusDisplayType[SC_DUPLELIGHT]	  = true;
 	StatusDisplayType[SC_DUPLELIGHT]	  = true;
 	StatusDisplayType[SC_ORATIO]		  = true;
 	StatusDisplayType[SC_ORATIO]		  = true;
 	StatusDisplayType[SC_FREEZING]		  = true;
 	StatusDisplayType[SC_FREEZING]		  = true;
@@ -6168,7 +6169,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
 			if( sc->data[SC_CAMOUFLAGE] && (sc->data[SC_CAMOUFLAGE]->val3&1) == 0 )
 			if( sc->data[SC_CAMOUFLAGE] && (sc->data[SC_CAMOUFLAGE]->val3&1) == 0 )
 				val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 0 : 25 * (5 - sc->data[SC_CAMOUFLAGE]->val1) );
 				val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 0 : 25 * (5 - sc->data[SC_CAMOUFLAGE]->val1) );
 			if( sc->data[SC_STEALTHFIELD] )
 			if( sc->data[SC_STEALTHFIELD] )
-				val = max( val, sc->data[SC_STEALTHFIELD]->val2 );
+				val = max( val, 20 );
 			if( sc->data[SC__LAZINESS] )
 			if( sc->data[SC__LAZINESS] )
 				val = max( val, 25 );
 				val = max( val, 25 );
 			if( sc->data[SC_BANDING_DEFENCE] )
 			if( sc->data[SC_BANDING_DEFENCE] )
@@ -9823,14 +9824,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			tick_time = 10000; // [GodLesZ] tick time
 			tick_time = 10000; // [GodLesZ] tick time
 			break;
 			break;
 		case SC_EXEEDBREAK:
 		case SC_EXEEDBREAK:
-			val1 = 100 * val1;
+			val2 = 150 * val1;
 			if (sd) { // Players
 			if (sd) { // Players
 				short index = sd->equip_index[EQI_HAND_R];
 				short index = sd->equip_index[EQI_HAND_R];
 
 
 				if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON)
 				if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON)
-					val1 += 10 * sd->status.job_level + sd->inventory_data[index]->weight / 10 * sd->inventory_data[index]->wlv * status_get_lv(bl) / 100;
+					val2 += 15 * sd->status.job_level + sd->inventory_data[index]->weight / 10 * sd->inventory_data[index]->wlv * status_get_lv(bl) / 100;
 			} else // Monster
 			} else // Monster
-				val1 += 500;
+				val2 += 750;
 			break;
 			break;
 		case SC_PRESTIGE:
 		case SC_PRESTIGE:
 			val2 = (status->int_ + status->luk) * val1 / 20 * status_get_lv(bl) / 200 + val1;	// Chance to evade magic damage.
 			val2 = (status->int_ + status->luk) * val1 / 20 * status_get_lv(bl) / 200 + val1;	// Chance to evade magic damage.
@@ -10162,12 +10163,12 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			break;
 			break;
 
 
 		case SC_STEALTHFIELD:
 		case SC_STEALTHFIELD:
-			val2 = 30; // Speed reduction
+			tick_time = tick;
+			tick = -1;
 			break;
 			break;
 		case SC_STEALTHFIELD_MASTER:
 		case SC_STEALTHFIELD_MASTER:
-			val3 = 3; // Reduces SP 3%
-			tick_time = 3000;
-			val4 = tick/tick_time;
+			tick_time = val3 = 2000 + 1000 * val1;
+			val4 = tick / tick_time;
 			break;
 			break;
 		case SC_VACUUM_EXTREME:
 		case SC_VACUUM_EXTREME:
 			// Suck target at n second, only if the n second is lower than the duration
 			// Suck target at n second, only if the n second is lower than the duration
@@ -10392,6 +10393,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_CHASEWALK:
 		case SC_CHASEWALK:
 		case SC_WEIGHT90:
 		case SC_WEIGHT90:
 		case SC_CAMOUFLAGE:
 		case SC_CAMOUFLAGE:
+		case SC_STEALTHFIELD:
 		case SC_VOICEOFSIREN:
 		case SC_VOICEOFSIREN:
 		case SC_HEAT_BARREL_AFTER:
 		case SC_HEAT_BARREL_AFTER:
 		case SC_WEDDING:
 		case SC_WEDDING:
@@ -10531,6 +10533,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC__INVISIBILITY:
 		case SC__INVISIBILITY:
 			sc->option |= OPTION_CLOAK;
 			sc->option |= OPTION_CLOAK;
 		case SC_CAMOUFLAGE:
 		case SC_CAMOUFLAGE:
+		case SC_STEALTHFIELD:
 			opt_flag = 2;
 			opt_flag = 2;
 			break;
 			break;
 		case SC_CHASEWALK:
 		case SC_CHASEWALK:
@@ -11426,6 +11429,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
 	case SC__INVISIBILITY:
 	case SC__INVISIBILITY:
 		sc->option &= ~OPTION_CLOAK;
 		sc->option &= ~OPTION_CLOAK;
 	case SC_CAMOUFLAGE:
 	case SC_CAMOUFLAGE:
+	case SC_STEALTHFIELD:
 		opt_flag |= 2;
 		opt_flag |= 2;
 		break;
 		break;
 	case SC_CHASEWALK:
 	case SC_CHASEWALK:
@@ -12506,10 +12510,10 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
 		break;
 		break;
 	case SC_STEALTHFIELD_MASTER:
 	case SC_STEALTHFIELD_MASTER:
 		if (--(sce->val4) >= 0) {
 		if (--(sce->val4) >= 0) {
-			int sp = (status->max_sp * sce->val3) / 100;
-			if (!status_charge(bl,0,sp))
+			if (!status_charge(bl, 0, status->max_sp * 3 / 100))
 				break;
 				break;
-			sc_timer_next(3000 + tick, status_change_timer, bl->id, data);
+			sc_timer_next(sce->val3 + tick, status_change_timer, bl->id, data);
+			return 0;
 		}
 		}
 		break;
 		break;
 	case SC_VACUUM_EXTREME:
 	case SC_VACUUM_EXTREME:

+ 2 - 0
src/map/unit.c

@@ -2860,6 +2860,8 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
 		status_change_end(bl, SC_STOP, INVALID_TIMER);
 		status_change_end(bl, SC_STOP, INVALID_TIMER);
 		status_change_end(bl, SC_WUGDASH, INVALID_TIMER);
 		status_change_end(bl, SC_WUGDASH, INVALID_TIMER);
 		status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER);
 		status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER);
+		status_change_end(bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER);
+		status_change_end(bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER);
 		status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
 		status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
 		status_change_end(bl, SC__MANHOLE, INVALID_TIMER);
 		status_change_end(bl, SC__MANHOLE, INVALID_TIMER);
 		status_change_end(bl, SC_VACUUM_EXTREME, INVALID_TIMER);
 		status_change_end(bl, SC_VACUUM_EXTREME, INVALID_TIMER);