From b0be3f023a024a4f8cc9903d52add7c81961303a Mon Sep 17 00:00:00 2001
From: "Guilherme G. Menaldo" <guilherme.menaldo@outlook.com>
Date: Mon, 1 Oct 2018 13:48:10 -0300
Subject: Added option to make hunter traps invisible

---
 conf/map/battle/skill.conf | 11 +++++++----
 db/pre-re/skill_db.conf    |  1 +
 db/re/skill_db.conf        |  9 +++++++++
 src/map/battle.c           |  2 +-
 src/map/battle.h           |  2 +-
 src/map/clif.c             |  7 +++----
 src/map/skill.c            | 38 +++++++++++++++++++++++++++++---------
 src/map/skill.h            |  2 ++
 8 files changed, 53 insertions(+), 19 deletions(-)

diff --git a/conf/map/battle/skill.conf b/conf/map/battle/skill.conf
index d258567a0..6923e729b 100644
--- a/conf/map/battle/skill.conf
+++ b/conf/map/battle/skill.conf
@@ -138,10 +138,13 @@ skill_nofootset: 1
 // Default on official servers: true for player-traps
 gvg_traps_target_all: 1
 
-// Some traps settings (add as necessary):
-// 1: Traps are invisible to those who come into view of it. When unset, all traps are visible at all times.
-//    (Invisible traps can be revealed through Hunter's Detecting skill)
-traps_setting: 0
+// Hunter's traps visibility setting (with HiddenTrap: true on skill_db.conf)
+// 0: Traps are always visible to everyone (Hercules/Pre-renewal)
+// 1: Traps with HiddenTrap: true are hidden in versus maps (PvP/GvG/BG)
+// 2: Traps with HiddenTrap: true are always invisible (Renewal) (Default)
+// Notes: Invisibility applies to players that are not in caster's party.
+//        Invisible traps can be made visible to everyone with Hunter's Detecting skill.
+trap_visibility: 2
 
 // Restrictions applied to the Alchemist's Summon Flora skill (add as necessary)
 // 1: Enable players to damage the floras outside of versus grounds.
diff --git a/db/pre-re/skill_db.conf b/db/pre-re/skill_db.conf
index 4873012aa..92a3b76bb 100644
--- a/db/pre-re/skill_db.conf
+++ b/db/pre-re/skill_db.conf
@@ -75,6 +75,7 @@
 							Works like FreeCastReduced, but not reduce speed.
 		ShowSkillScale: true/false              (boolean, defaults to false)
 		AllowReproduce: true/false              (boolean, defaults to false)
+		HiddenTrap: true/false                  (boolean, defaults to false)
 	}
 	AttackType: "Attack Type"                   (string, defaults to "None")
 	                                            Types: "None", "Weapon", "Magic" or "Misc"
diff --git a/db/re/skill_db.conf b/db/re/skill_db.conf
index 4863e4051..842a50143 100644
--- a/db/re/skill_db.conf
+++ b/db/re/skill_db.conf
@@ -75,6 +75,7 @@
 							Works like FreeCastReduced, but not reduce speed.
 		ShowSkillScale: true/false              (boolean, defaults to false)
 		AllowReproduce: true/false              (boolean, defaults to false)
+		HiddenTrap: true/false                  (boolean, defaults to false)
 	}
 	AttackType: "Attack Type"                   (string, defaults to "None")
 	                                            Types: "None", "Weapon", "Magic" or "Misc"
@@ -4110,6 +4111,7 @@ skill_db: (
 	}
 	SkillInfo: {
 		Trap: true
+		HiddenTrap: true
 	}
 	AttackType: "Misc"
 	DamageType: {
@@ -4170,6 +4172,7 @@ skill_db: (
 	SkillInfo: {
 		Trap: true
 		AllowReproduce: true
+		HiddenTrap: true
 	}
 	AttackType: "Misc"
 	Element: "Ele_Earth"
@@ -4222,6 +4225,7 @@ skill_db: (
 	}
 	SkillInfo: {
 		Trap: true
+		HiddenTrap: true
 	}
 	AttackType: "Misc"
 	DamageType: {
@@ -4281,6 +4285,7 @@ skill_db: (
 	}
 	SkillInfo: {
 		Trap: true
+		HiddenTrap: true
 	}
 	AttackType: "Misc"
 	DamageType: {
@@ -4329,6 +4334,7 @@ skill_db: (
 	}
 	SkillInfo: {
 		Trap: true
+		HiddenTrap: true
 	}
 	AttackType: "Misc"
 	DamageType: {
@@ -4390,6 +4396,7 @@ skill_db: (
 	}
 	SkillInfo: {
 		Trap: true
+		HiddenTrap: true
 	}
 	AttackType: "Misc"
 	DamageType: {
@@ -4452,6 +4459,7 @@ skill_db: (
 	SkillInfo: {
 		Trap: true
 		AllowReproduce: true
+		HiddenTrap: true
 	}
 	AttackType: "Weapon"
 	Element: "Ele_Water"
@@ -4636,6 +4644,7 @@ skill_db: (
 	}
 	SkillInfo: {
 		Trap: true
+		HiddenTrap: true
 	}
 	AttackType: "Misc"
 	DamageType: {
diff --git a/src/map/battle.c b/src/map/battle.c
index fceb30be1..2cf04ffce 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -6966,7 +6966,7 @@ static const struct battle_data {
 	{ "player_damage_delay_rate",           &battle_config.pc_damage_delay_rate,            100,    0,      INT_MAX,        },
 	{ "defunit_not_enemy",                  &battle_config.defnotenemy,                     0,      0,      1,              },
 	{ "gvg_traps_target_all",               &battle_config.vs_traps_bctall,                 BL_PC,  BL_NUL, BL_ALL,         },
-	{ "traps_setting",                      &battle_config.traps_setting,                   0,      0,      1,              },
+	{ "trap_visibility",                    &battle_config.trap_visibility,                 0,      0,      2,              },
 	{ "summon_flora_setting",               &battle_config.summon_flora,                    1|2,    0,      1|2,            },
 	{ "clear_skills_on_death",              &battle_config.clear_unit_ondeath,              BL_NUL, BL_NUL, BL_ALL,         },
 	{ "clear_skills_on_warp",               &battle_config.clear_unit_onwarp,               BL_ALL, BL_NUL, BL_ALL,         },
diff --git a/src/map/battle.h b/src/map/battle.h
index 9f5207e95..297768765 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -149,7 +149,7 @@ struct Battle_Config {
 	int pc_damage_delay_rate;
 	int defnotenemy;
 	int vs_traps_bctall;
-	int traps_setting;
+	int trap_visibility;
 	int summon_flora; //[Skotlex]
 	int clear_unit_ondeath; //[Skotlex]
 	int clear_unit_onwarp; //[Skotlex]
diff --git a/src/map/clif.c b/src/map/clif.c
index 76625f0ba..cb9bd3ee2 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -4904,9 +4904,8 @@ static void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit
 	p.xPos = su->bl.x;
 	p.yPos = su->bl.y;
 
-	//Use invisible unit id for traps.
-	if ((battle_config.traps_setting&1 && skill->get_inf2(su->group->skill_id)&INF2_TRAP) ||
-		(skill->get_unit_flag(su->group->skill_id) & UF_RANGEDSINGLEUNIT && !(su->val2 & UF_RANGEDSINGLEUNIT)))
+	// Use invisible unit id for some ground skills.
+	if (skill->get_unit_flag(su->group->skill_id) & UF_RANGEDSINGLEUNIT && !(su->val2 & UF_RANGEDSINGLEUNIT))
 		p.job = UNT_DUMMYSKILL;
 	else
 		p.job = su->group->unit_id;
@@ -4915,7 +4914,7 @@ static void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit
 	p.RadiusRange = (unsigned char)su->range;
 #endif
 
-	p.isVisible = 1;
+	p.isVisible = su->visible;
 
 #if PACKETVER >= 20130731
 	p.level = (unsigned char)su->group->skill_lv;
diff --git a/src/map/skill.c b/src/map/skill.c
index 4eaab5457..2b31de6fc 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -4153,10 +4153,9 @@ static int skill_reveal_trap(struct block_list *bl, va_list ap)
 	Assert_ret(bl->type == BL_SKILL);
 	su = BL_UCAST(BL_SKILL, bl);
 
-	if (su->alive && su->group && skill->get_inf2(su->group->skill_id)&INF2_TRAP) { //Reveal trap.
-		//Change look is not good enough, the client ignores it as an actual trap still. [Skotlex]
-		//clif->changetraplook(bl, su->group->unit_id);
-		clif->getareachar_skillunit(&su->bl,su,AREA);
+	if (su->alive && su->group && skill->get_inf2(su->group->skill_id) & INF2_HIDDEN_TRAP) { //Reveal trap.
+		su->visible = true;
+		clif->skillunit_update(bl);
 		return 1;
 	}
 	return 0;
@@ -11040,9 +11039,10 @@ static int skill_castend_pos2(struct block_list *src, int x, int y, uint16 skill
 			map->foreachinarea(status->change_timer_sub,
 			                   src->m, x-r, y-r, x+r,y+r,BL_CHAR,
 			                   src,NULL,SC_SIGHT,tick);
-			if(battle_config.traps_setting&1)
-			map->foreachinarea(skill_reveal_trap,
-			                   src->m, x-r, y-r, x+r, y+r, BL_SKILL);
+			if (battle_config.trap_visibility != 0) {
+				map->foreachinarea(skill_reveal_trap,
+			                   src->m, x - r, y - r, x + r, y + r, BL_SKILL);
+			}
 			break;
 
 		case SR_RIDEINLIGHTNING:
@@ -12759,6 +12759,11 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b
 			ts->tick += sg->interval*(map->count_oncell(bl->m,bl->x,bl->y,BL_CHAR,0)-1);
 	}
 
+	if (battle_config.trap_visibility != 0 && skill->get_inf2(sg->skill_id) & INF2_HIDDEN_TRAP) {
+		src->visible = true;
+		clif->skillunit_update(&src->bl);
+	}
+
 	switch (sg->unit_id) {
 		case UNT_FIREWALL:
 		case UNT_KAEN: {
@@ -12911,10 +12916,11 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b
 						clif->fixpos(bl);
 					}
 					sg->val2 = bl->id;
-				} else
+				} else {
 					sec = 3000; //Couldn't trap it?
+				}
+
 				if( sg->unit_id == UNT_ANKLESNARE ) {
-					clif->skillunit_update(&src->bl);
 					/**
 					 * If you're snared from a trap that was invisible this makes the trap be
 					 * visible again -- being you stepped on it (w/o this the trap remains invisible and you go "WTF WHY I CANT MOVE")
@@ -17051,6 +17057,14 @@ static struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx
 	su->val1=val1;
 	su->val2 = val2;
 	su->prev = 0;
+	su->visible = true;
+
+	if (skill->get_inf2(group->skill_id) & INF2_HIDDEN_TRAP
+		&& ((battle_config.trap_visibility == 1 && map_flag_vs(group->map)) // invisible in PvP/GvG
+			|| battle_config.trap_visibility == 2 // always invisible
+	)) {
+	 	su->visible = false;
+	}
 
 	idb_put(skill->unit_db, su->bl.id, su);
 	map->addiddb(&su->bl);
@@ -20216,6 +20230,12 @@ static void skill_validate_skillinfo(struct config_setting_t *conf, struct s_ski
 				} else {
 					sk->inf2 &= ~INF2_ALLOW_REPRODUCE;
 				}
+			} else if (strcmpi(type, "HiddenTrap") == 0) {
+				if (on) {
+					sk->inf2 |= INF2_HIDDEN_TRAP;
+				} else {
+					sk->inf2 &= ~INF2_HIDDEN_TRAP;
+				}
 			} else if (strcmpi(type, "None") != 0) {
 				skilldb_invalid_error(type, config_setting_name(t), sk->nameid);
 			}
diff --git a/src/map/skill.h b/src/map/skill.h
index 97134224e..0c6ee8cae 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -124,6 +124,7 @@ enum e_skill_inf2 {
 	INF2_FREE_CAST_REDUCED = 0x10000,
 	INF2_SHOW_SKILL_SCALE  = 0x20000,
 	INF2_ALLOW_REPRODUCE   = 0x40000,
+	INF2_HIDDEN_TRAP       = 0x80000, // Traps that are hidden (based on trap_visiblity battle conf)
 };
 
 
@@ -1806,6 +1807,7 @@ struct skill_unit {
 
 	int limit;
 	int val1,val2;
+	bool visible;
 	short alive,range;
 	int prev;
 };
-- 
cgit v1.2.3-70-g09d2


From df3f7552e61d1dae45e83c55ff36b95ab95181bb Mon Sep 17 00:00:00 2001
From: gumi <git@gumi.ca>
Date: Wed, 3 Oct 2018 21:02:01 -0400
Subject: add a warning for `traps_setting` in battle conf

---
 src/map/battle.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/map/battle.c b/src/map/battle.c
index 2cf04ffce..895876300 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -7525,6 +7525,10 @@ static bool battle_config_read(const char *filename, bool imported)
 	if (!imported)
 		battle->config_set_defaults();
 
+	if (libconfig->lookup(&config, "battle_configuration/traps_setting") != NULL) {
+		ShowError("The `traps_setting` battle conf option has been replaced by `trap_visibility`. Please see conf/map/battle/skill.conf.\n");
+	}
+
 	for (i = 0; i < ARRAYLENGTH(battle_data); i++) {
 		int type, val;
 		char config_name[256];
-- 
cgit v1.2.3-70-g09d2


From 1e3d3a3c0bca912ebdf18ae337814b2f434ec442 Mon Sep 17 00:00:00 2001
From: "Guilherme G. Menaldo" <guilherme.menaldo@outlook.com>
Date: Sat, 20 Oct 2018 23:21:07 -0300
Subject: Added setting to keep traps invisible when triggered

---
 conf/map/battle/skill.conf | 15 ++++++++++++---
 src/map/battle.c           |  3 ++-
 src/map/battle.h           |  1 +
 src/map/skill.c            |  4 +++-
 4 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/conf/map/battle/skill.conf b/conf/map/battle/skill.conf
index 6923e729b..cb219740f 100644
--- a/conf/map/battle/skill.conf
+++ b/conf/map/battle/skill.conf
@@ -139,12 +139,21 @@ skill_nofootset: 1
 gvg_traps_target_all: 1
 
 // Hunter's traps visibility setting (with HiddenTrap: true on skill_db.conf)
+// Here we have 2 configs:
+// visibility stands to how traps are displayed by default:
 // 0: Traps are always visible to everyone (Hercules/Pre-renewal)
 // 1: Traps with HiddenTrap: true are hidden in versus maps (PvP/GvG/BG)
 // 2: Traps with HiddenTrap: true are always invisible (Renewal) (Default)
-// Notes: Invisibility applies to players that are not in caster's party.
-//        Invisible traps can be made visible to everyone with Hunter's Detecting skill.
-trap_visibility: 2
+// Notes: - Invisibility applies to players that are not in caster's party.
+//        - Invisible traps can be made visible to everyone with Hunter's Detecting skill.
+//
+// display_on_trigger tells if HiddenTraps should become visible once triggered
+// 0: Do not make traps visible once triggered (except for Ankle Snare) (Aegis)
+// 1: Always make traps visible once triggered (Hercules)
+trap_options: {
+    visibility: 2
+    display_on_trigger: 1
+}
 
 // Restrictions applied to the Alchemist's Summon Flora skill (add as necessary)
 // 1: Enable players to damage the floras outside of versus grounds.
diff --git a/src/map/battle.c b/src/map/battle.c
index 895876300..a784f6884 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -6966,7 +6966,8 @@ static const struct battle_data {
 	{ "player_damage_delay_rate",           &battle_config.pc_damage_delay_rate,            100,    0,      INT_MAX,        },
 	{ "defunit_not_enemy",                  &battle_config.defnotenemy,                     0,      0,      1,              },
 	{ "gvg_traps_target_all",               &battle_config.vs_traps_bctall,                 BL_PC,  BL_NUL, BL_ALL,         },
-	{ "trap_visibility",                    &battle_config.trap_visibility,                 0,      0,      2,              },
+	{ "trap_options/visibility",            &battle_config.trap_visibility,                 2,      0,      2,              },
+	{ "trap_options/display_on_trigger",    &battle_config.trap_trigger,                    1,      0,      1,              },
 	{ "summon_flora_setting",               &battle_config.summon_flora,                    1|2,    0,      1|2,            },
 	{ "clear_skills_on_death",              &battle_config.clear_unit_ondeath,              BL_NUL, BL_NUL, BL_ALL,         },
 	{ "clear_skills_on_warp",               &battle_config.clear_unit_onwarp,               BL_ALL, BL_NUL, BL_ALL,         },
diff --git a/src/map/battle.h b/src/map/battle.h
index 297768765..007fbabd2 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -150,6 +150,7 @@ struct Battle_Config {
 	int defnotenemy;
 	int vs_traps_bctall;
 	int trap_visibility;
+	int trap_trigger;
 	int summon_flora; //[Skotlex]
 	int clear_unit_ondeath; //[Skotlex]
 	int clear_unit_onwarp; //[Skotlex]
diff --git a/src/map/skill.c b/src/map/skill.c
index 2b31de6fc..c320fe4b3 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -12759,7 +12759,9 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b
 			ts->tick += sg->interval*(map->count_oncell(bl->m,bl->x,bl->y,BL_CHAR,0)-1);
 	}
 
-	if (battle_config.trap_visibility != 0 && skill->get_inf2(sg->skill_id) & INF2_HIDDEN_TRAP) {
+	if (sg->skill_id == HT_ANKLESNARE
+		|| (battle_config.trap_trigger == 1 && skill->get_inf2(sg->skill_id) & INF2_HIDDEN_TRAP)
+	) {
 		src->visible = true;
 		clif->skillunit_update(&src->bl);
 	}
-- 
cgit v1.2.3-70-g09d2