define DUNGEON_MAN 20397
define ENTRY_MAN 20395
define DUNGEON_MAP_INDEX 352
define ENTER_LIMIT_TIME 240
define ENTRY_MAP_INDEX 61
define FINAL_BOSS 6191
define LEVEL2_REALKEY 30331
define LEVEL2_STONE 20386
define LEVEL4_TARGET_GROUP 6062
define LEVEL5_REALKEY 30332
define LEVEL5_STONE 20398
define LEVEL5_GEN_LIMIT 100
define LEVEL6_TARGET 8058
define LEVEL7_BOSSMOB 6151
define LEVEL8_REALKEY 30333
define LEVEL8_STONE 20386
define LEVEL9_TARGET 20399
define MOB_REGEN_FILE_PATH = "data/dungeon/snow_dungeon/"
define PASS_TICKET 71095
define HOSIN_BUFF 94
define GICHEON_BUFF 96

quest snow_dungeon begin
	state start begin
		function setting()
			return
			{
				["dungeon_entry_pos"] = { 5291, 1814 },
				["DUNGEON_MAN_pos"] = { 172, 261 },
				["WARP_pos"] = {
					{ 5291, 1814 },
					{ 5540, 1797 },
					{ 5882, 1800 },
					{ 5293, 2071 },
					{ 5540, 2074 },
					{ 5866, 2076 },
					{ 5423, 2244 },
					{ 5689, 2237 },
					{ 5969, 2229 },
					{ 6047, 1924 }
				},
				["LEVEL2_STONE_pos"] = { 421, 191 },
				["LEVEL4_TARGET_pos"] = { 171, 496 },
				["LEVEL5_STONE_pos"] = {
					{ 449, 488 },
					{ 455, 445 },
					{ 419, 422 },
					{ 382, 444 },
					{ 389, 488 }
				},
				["LEVEL6_TARGET_pos"] = { 747, 494 },
				["LEVEL7_BOSSMOB_pos"] = {
					{ 302, 678 },
					{ 281, 657 },
					{ 303, 635 },
					{ 324, 656 }
				},
				["LEVEL8_STONE_pos"] = {
					{ 570, 650 }
				},
				["LEVEL9_TARGET_pos"] = {
					{ 849, 660 }
				},
				["boss_pos"] = { 927, 333 },
				["outside_entry_pos"] = { 4322, 1655 }
			}
		end

		function make_dungeon()
			local setting = snow_dungeon.setting()

			d.new_jump_party(DUNGEON_MAP_INDEX, setting.dungeon_entry_pos[1], setting.dungeon_entry_pos[2])
			d.set_item_group("fd_pass_ticket", 1, PASS_TICKET, 1)
			d.spawn_mob_ac_dir(DUNGEON_MAN, setting.DUNGEON_MAN_pos[1], setting.DUNGEON_MAN_pos[2], 1)
		end

		function start_at_level(stage)
			local setting = snow_dungeon.setting()
			
			-- Create dungeon and warp to appropriate position
			local warp_x = setting.dungeon_entry_pos[1]
			local warp_y = setting.dungeon_entry_pos[2]
			
			if stage > 1 then
				warp_x = setting.WARP_pos[stage][1]
				warp_y = setting.WARP_pos[stage][2]
			end
			
			d.new_jump_party(DUNGEON_MAP_INDEX, warp_x, warp_y)
			
			local map_idx = d.get_map_index()

			party.setf("dungeon_index", map_idx)
			d.setf("party_leader_pid", party.get_leader_pid())
			
			-- Stage 1: Just spawn DUNGEON_MAN and wait
			if stage == 1 then
				d.set_item_group("fd_pass_ticket", 1, PASS_TICKET, 1)
				d.spawn_mob_ac_dir(DUNGEON_MAN, setting.DUNGEON_MAN_pos[1], setting.DUNGEON_MAN_pos[2], 1)
				d.setf("level", 0)

				return
			end
			
			-- Stages 2-10: Start immediately
			d.setf("dungeon_enter", 1)
			d.setf("dungeon_start_time", get_global_time())
			
			-- Remove tickets from all party members
			local pids = { party.get_member_pids() }

			for i = 1, table.getn(pids) do
				q.begin_other_pc_block(pids[i])

				pc.remove_item(PASS_TICKET, 1)
				pc.setf("snow_dungeon", "ticket_delete", 1)

				q.end_other_pc_block()
			end
			
			-- Start timers
			server_timer("snow_dungeon_45m_left_timer", 15 * 60, map_idx)
			server_timer("snow_dungeon_30m_left_timer", 15 * 60, map_idx)
			
			-- Level-specific initialization
			if stage == 2 then
				d.setf("level", 2)
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_2f.txt")
			elseif stage == 3 then
				d.setf("level", 3)
				d.regen_file(MOB_REGEN_FILE_PATH .. "id_3f.txt")

				server_timer("snow_dungeon_killed_A_1", 6, map_idx)
			elseif stage == 4 then
				d.setf("level", 4)
				d.regen_file(MOB_REGEN_FILE_PATH .. "id_4f.txt")

				server_timer("snow_dungeon_killed_A_1", 6, map_idx)
			elseif stage == 5 then
				d.setf("level", 5)
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_5f.txt")
				
				local vis = { 0, 0, 0, 0, 0 }

				for i = 1, 5 do
					local ran = number(1, 5)
					local st = 0

					for j = 1, 50 do
						st = st + 1

						if st > 5 then st = 1 end

						if vis[st] == 0 then
							ran = ran - 1

							if ran == 0 then
								vis[st] = 1
								
								d.set_unique("stone5_" .. st, d.spawn_mob(LEVEL5_STONE, setting.LEVEL5_STONE_pos[i][1], setting.LEVEL5_STONE_pos[i][2]))
								
								break
							end
						end
					end
				end
			elseif stage == 6 then
				d.setf("level", 6)
				d.regen_file(MOB_REGEN_FILE_PATH .. "id_6f.txt")
				d.set_unique("stage6_npc", d.spawn_mob(20379, 747, 517))

				server_timer("snow_dungeon_stage6_npc_guard", 10, map_idx)
				server_timer("snow_dungeon_killed_A_1", 6, map_idx)
			elseif stage == 7 then
				d.setf("level", 7)
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_7f.txt")
				
				local vis = { 0, 0, 0, 0 }

				for i = 1, 3 do vis[i] = 0 end

				for i = 1, 4 do
					local ran = number(1, 4)
					local st = 0

					for j = 1, 50 do
						st = st + 1

						if st > 4 then st = 1 end

						if vis[st] == 0 then
							ran = ran - 1

							if ran == 0 then
								vis[st] = 1
								
								d.set_unique("boss7_" .. st, d.spawn_mob(LEVEL7_BOSSMOB, setting.LEVEL7_BOSSMOB_pos[i][1], setting.LEVEL7_BOSSMOB_pos[i][2]))
								
								break
							end
						end
					end
				end
				
				for i = 1, 4 do
					local vid = d.get_unique_vid('boss7_' .. i)
					
					if vid ~= 0 then
						npc.set_damage_immunity_with_conditions(vid, {{ type = 0, value = GICHEON_BUFF }})
					end
				end

				server_timer("snow_dungeon_killed_B_1", 6, map_idx)
			elseif stage == 8 then
				d.setf("level", 8)
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_8f.txt")
			elseif stage == 9 then
				d.setf("level", 9)
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_9f.txt")
				d.spawn_mob_with_immunity(LEVEL9_TARGET, setting.LEVEL9_TARGET_pos[1][1], setting.LEVEL9_TARGET_pos[1][2], {{ type = 6, value = 1 }, { type = 6, value = 3 }})
			elseif stage == 10 then
				d.setf("level", 10)
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_boss.txt")
				d.spawn_mob(FINAL_BOSS, setting.boss_pos[1], setting.boss_pos[2])
			end
		end

		function clear_timer(inx)
			clear_server_timer("snow_dungeon_ticket_remove", inx)
			clear_server_timer("snow_dungeon_0m_left_timer", inx)
			clear_server_timer("snow_dungeon_1m_left_timer", inx)
			clear_server_timer("snow_dungeon_5m_left_timer", inx)
			clear_server_timer("snow_dungeon_10m_left_timer", inx)
			clear_server_timer("snow_dungeon_15m_left_timer", inx)
			clear_server_timer("snow_dungeon_30m_left_timer", inx)
			clear_server_timer("snow_dungeon_45m_left_timer", inx)
			clear_server_timer("snow_dungeon_end_timer", inx)
			clear_server_timer("snow_dungeon_level2_start", inx)
			clear_server_timer("snow_dungeon_level3_start", inx)
			clear_server_timer("snow_dungeon_level4_start", inx)
			clear_server_timer("snow_dungeon_level5_start", inx)
			clear_server_timer("snow_dungeon_level6_start", inx)
			clear_server_timer("snow_dungeon_level7_start", inx)
			clear_server_timer("snow_dungeon_level8_start", inx)
			clear_server_timer("snow_dungeon_level9_start", inx)
			clear_server_timer("snow_dungeon_killed_A_1", inx)
			clear_server_timer("snow_dungeon_killed_A_2", inx)
			clear_server_timer("snow_dungeon_killed_B_1", inx)
			clear_server_timer("snow_dungeon_killed_B_2", inx)
			clear_server_timer("snow_dungeon_leader_out_timer", inx)
		end

		function is_snowd(idx)
			return idx >= DUNGEON_MAP_INDEX * 10000 and idx < (DUNGEON_MAP_INDEX + 1) * 10000
		end

		function level_clear()
			d.clear_regen()
			d.purge_area(520000, 155000, 612000, 228600)
		end

		when login begin
			local idx = pc.get_map_index()
			local setting = snow_dungeon.setting()

			if idx == DUNGEON_MAP_INDEX then
				timer("snow_dungeon_warp_timer", 5)
			elseif snow_dungeon.is_snowd(idx) then
				pc.set_warp_location(ENTRY_MAP_INDEX, setting.outside_entry_pos[1], setting.outside_entry_pos[2])

				if d.getf("dungeon_enter") == 0 then
					if get_global_time() - pc.getf("snow_dungeon", "exit_time") < ENTER_LIMIT_TIME * 60 then
						notice_multiline(gameforge.snow_dungeon._010_notice, d.notice)
						say(gameforge.snow_dungeon._020_say)
						timer("snow_dungeon_warp_timer", 5)
					elseif pc.count_item(PASS_TICKET) < 1 then
						notice_multiline(gameforge.snow_dungeon._030_notice, d.notice)
						say(gameforge.snow_dungeon._040_say)
						timer("snow_dungeon_warp_timer", 5)
					elseif pc.get_level() < 100 then
						notice_multiline(string.format(gameforge.snow_dungeon._050_notice, 100), d.notice)
						say(string.format(gameforge.snow_dungeon._060_say, 100))
						timer("snow_dungeon_warp_timer", 5)
					end
				else
					if pc.getf("snow_dungeon", "ticket_delete") == 0 then
						if party.is_party() and party.is_leader() then
							clear_server_timer("snow_dungeon_leader_out_timer", idx)
						end

						pc.remove_item(PASS_TICKET, 1)
						pc.setf("snow_dungeon", "ticket_delete", 1)
					end
				end
			else
				pc.setf("snow_dungeon", "ticket_delete", 0)
			end
		end

		when logout begin
			local idx = pc.get_map_index()

			if snow_dungeon.is_snowd(idx) then
				if d.getf("dungeon_enter") == 1 then
					pc.setf("snow_dungeon", "exit_time", get_global_time())
				end

				if party.is_leader() then
					server_timer("snow_dungeon_leader_out_timer", 5 * 60, d.get_map_index())
				end
			end
		end

		when snow_dungeon_warp_timer.timer begin
			local setting = snow_dungeon.setting()

			pc.warp(setting.outside_entry_pos[1] * 100, setting.outside_entry_pos[2] * 100, ENTRY_MAP_INDEX)
		end

		when DUNGEON_MAN.chat.gameforge.snow_dungeon._590_npcChat with pc.get_map_index() >= DUNGEON_MAP_INDEX * 10000 and pc.get_map_index() < (DUNGEON_MAP_INDEX + 1) * 10000 and d.getf("level") == 0 begin
			if party.is_leader() then
				char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "STARTED")

				d.setf("level", 1)
				d.regen_file(MOB_REGEN_FILE_PATH .. "id_1f.txt")

				server_timer("snow_dungeon_30m_left_timer", 15 * 60, get_server_timer_arg())
				server_timer("snow_dungeon_killed_A_1", 6, d.get_map_index())
				server_timer("snow_dungeon_45m_left_timer", 15 * 60, d.get_map_index())

				d.say_diff_by_item_group("fd_pass_ticket", gameforge.snow_dungeon._070_say, gameforge.snow_dungeon._080_say)

				server_timer("snow_dungeon_ticket_remove", 5, d.get_map_index())

				party.setf("dungeon_index", d.get_map_index())
				d.setf("party_leader_pid", party.get_leader_pid())
			else
				say_title(mob_name(DUNGEON_MAN) .. ": ")
				say(gameforge.snow_dungeon._090_say)
			end
		end

		when snow_dungeon_ticket_remove.server_timer begin
			if d.select(get_server_timer_arg()) then
				d.exit_all_by_item_group("fd_pass_ticket")
				d.delete_item_in_item_group_from_all("fd_pass_ticket")
				d.setqf2("snow_dungeon", "ticket_delete", 1)
				d.setf("dungeon_enter", 1)
				d.setf("dungeon_start_time", get_global_time())

				notice_multiline(gameforge.snow_dungeon._120_notice, d.notice)
			end
		end

		when ENTRY_MAN.chat."GM: Reset timers" with pc.is_gm() begin
			-- GM-only quick reset option
			say_title(mob_name(ENTRY_MAN) .. ": ")
			say("Reset timers for Nemere Watchtower?")

			local gm_sel = select("Reset", "Cancel")

			if gm_sel == 1 then
				if party.is_party() then
					local map_idx = party.getf("dungeon_index")

					if d.find(map_idx) then
						-- Clear all dungeon timers for this party instance
						snow_dungeon.clear_timer(map_idx)

						if d.select(map_idx) then
							-- Reset dungeon flags to idle
							d.setf("level", 0)
							d.setf("dungeon_enter", 0)
							-- Unset tracked leader if any
							d.setf("party_leader_pid", 0)
						end
					end

					-- Reset per-player flags for all party members
					local pids = { party.get_member_pids() }

					for i = 1, table.getn(pids) do
						q.begin_other_pc_block(pids[i])

						pc.setf("snow_dungeon", "ticket_delete", 0)
						pc.setf("snow_dungeon", "exit_time", 0)

						q.end_other_pc_block()
					end

					-- Clear party reference to existing dungeon
					party.setf("dungeon_index", 0)

					say_title(mob_name(ENTRY_MAN) .. ": ")
					say("Per-character dungeon cooldown states have been reset.")
				else
					-- Solo GM reset
					pc.setf("snow_dungeon", "ticket_delete", 0)
					pc.setf("snow_dungeon", "exit_time", 0)

					say_title(mob_name(ENTRY_MAN) .. ": ")
					say("Your dungeon cooldown states have been reset.")
				end
			end
		end

		when ENTRY_MAN.chat."GM: Start at stage" with pc.is_gm() begin
			-- Check all party members have passage tickets
			local pids = { party.get_member_pids() }

			-- Check all party members are level 100+
			local has_low_level = false

			for i = 1, table.getn(pids) do
				q.begin_other_pc_block(pids[i])

				if pc.get_level() < 100 then
					has_low_level = true
				end

				q.end_other_pc_block()

				if has_low_level then
					break
				end
			end

			if has_low_level then
				say_title(mob_name(ENTRY_MAN) .. ": ")
				say(string.format(gameforge.snow_dungeon._050_notice, 100))
			elseif pc.is_riding() then
				say_title(mob_name(ENTRY_MAN) .. ": ")
				say(gameforge.snow_dungeon._620_say)
			else
				-- Check for ninja and shaman in party (no nested other_pc_block)
				local has_ninja = false
				local has_shaman = false

				for i = 1, table.getn(pids) do
					q.begin_other_pc_block(pids[i])

					local job = pc.get_job()

					if job == 1 then
						has_ninja = true
					end

					if job == 3 and pc.get_skill_group() == 1 then
						has_shaman = true
					end

					q.end_other_pc_block()
				end

				if not has_ninja or not has_shaman then
					say_title(mob_name(ENTRY_MAN) .. ": ")
					say(gameforge.snow_dungeon._170_say)
				elseif not party.is_party() then
					say_title(mob_name(ENTRY_MAN) .. ": ")
					say("You must be in a party.")
				elseif not party.is_leader() then
					say_title(mob_name(ENTRY_MAN) .. ": ")
					say("Only the party leader can do this.")
				else			
					say_title(mob_name(ENTRY_MAN) .. ": ")
					say("Select stage to start:")
					
					local sel = select(
						"1. Clear room",
						"2. Frost Keys",
						"3. Clear room",
						"4. Dual-wave (Blessing)",
						"5. Arctic Cubes",
						"6. Metin of Cold (Shaman)",
						"7. Szel (Dragon's Aid)",
						"8. Frostflower Key",
						"9. Pillar (Ninja/Shaman)",
						"10. Nemere",
						"Cancel"
					)
					
					if sel >= 1 and sel <= 10 then
						local members_without_ticket = {}
						local members_riding = {}
						local members_cooling_down = {}

						for i = 1, table.getn(pids) do
							q.begin_other_pc_block(pids[i])

							if pc.is_riding() then
								table.insert(members_riding, pc.get_name())
							end

							if pc.count_item(PASS_TICKET) < 1 then
								table.insert(members_without_ticket, pc.get_name())
							end

							if get_global_time() - pc.getf("snow_dungeon", "exit_time") < ENTER_LIMIT_TIME * 60 then
								table.insert(members_cooling_down, pc.get_name())
							end

							q.end_other_pc_block()
						end

						if table.getn(members_riding) > 0 then
							say_title(mob_name(ENTRY_MAN) .. ": ")
							say(gameforge.snow_dungeon._630_say)
						elseif table.getn(members_without_ticket) > 0 and sel == 1 then
							say_title(mob_name(ENTRY_MAN) .. ": ")
							say(gameforge.snow_dungeon._610_notice)
							say("")

							for i = 1, table.getn(members_without_ticket) do
								say(string.format("  - %s", members_without_ticket[i]))
							end
						elseif table.getn(members_cooling_down) > 0 then
							say_title(mob_name(ENTRY_MAN) .. ": ")
							say(gameforge.snow_dungeon._600_say)
						else
							snow_dungeon.start_at_level(sel)
						end
					end
				end
			end
		end

		when ENTRY_MAN.chat.gameforge.snow_dungeon._100_npcChat with pc.get_map_index() == ENTRY_MAP_INDEX begin
			if party.is_party() then
				local party_check = 0

				if d.find(party.getf("dungeon_index")) then
					party_check = (d.getf_from_map_index("party_leader_pid", party.getf("dungeon_index")) == party.get_leader_pid())
				end

				if d.find(party.getf("dungeon_index")) and party_check then
					local dungeon_level = d.getf_from_map_index("level", party.getf("dungeon_index"))
					local setting = snow_dungeon.setting()

					if dungeon_level == 0 then
						dungeon_level = 1
					end

					if pc.get_level() < 100 then
						say_title(mob_name(ENTRY_MAN) .. ": ")
						say(gameforge.snow_dungeon._050_notice)
					elseif pc.is_riding() then
						say_title(mob_name(ENTRY_MAN) .. ": ")
						say(gameforge.snow_dungeon._620_say)
					elseif get_global_time() - pc.getf("snow_dungeon", "exit_time") < 5 * 60 then
						pc.warp(setting.WARP_pos[dungeon_level][1] * 100, setting.WARP_pos[dungeon_level][2] * 100, party.getf("dungeon_index"))
					elseif get_global_time() - d.getf_from_map_index("dungeon_start_time", party.getf("dungeon_index")) < 5 * 60 then
						if pc.count_item(PASS_TICKET) < 1 then
							say_title(mob_name(ENTRY_MAN) .. ": ")
							say(gameforge.snow_dungeon._040_notice)
						else
							pc.warp(setting.WARP_pos[dungeon_level][1] * 100, setting.WARP_pos[dungeon_level][2] * 100, party.getf("dungeon_index"))
						end
					else
						say_title(mob_name(ENTRY_MAN) .. ": ")
						say(gameforge.snow_dungeon._110_say)
					end
				else
					if party.is_leader() then
						-- Check all party members have passage tickets
						local pids = { party.get_member_pids() }

						-- Check all party members are level 100+
						local has_low_level = false

						for i = 1, table.getn(pids) do
							q.begin_other_pc_block(pids[i])

							if pc.get_level() < 100 then
								has_low_level = true
							end

							q.end_other_pc_block()

							if has_low_level then
								break
							end
						end

						if has_low_level then
							say_title(mob_name(ENTRY_MAN) .. ": ")
							say(string.format(gameforge.snow_dungeon._050_notice, 100))
						elseif pc.is_riding() then
							say_title(mob_name(ENTRY_MAN) .. ": ")
							say(gameforge.snow_dungeon._620_say)
						else
							-- Check for ninja and shaman in party (no nested other_pc_block)
							local has_ninja = false
							local has_shaman = false

							for i = 1, table.getn(pids) do
								q.begin_other_pc_block(pids[i])

								local job = pc.get_job()

								if job == 1 then
									has_ninja = true
								end

								if job == 3 and pc.get_skill_group() == 1 then
									has_shaman = true
								end

								q.end_other_pc_block()
							end

							if not has_ninja or not has_shaman then
								say_title(mob_name(ENTRY_MAN) .. ": ")
								say(gameforge.snow_dungeon._170_say)
							else
								say_title(mob_name(ENTRY_MAN) .. ": ")
								say(gameforge.snow_dungeon._130_say)

								local warp = select(gameforge.snow_dungeon._140_select, gameforge.snow_dungeon._150_select)

								if warp == 1 then
									local members_without_ticket = {}
									local members_riding = {}
									local members_cooling_down = {}

									for i = 1, table.getn(pids) do
										q.begin_other_pc_block(pids[i])

										if pc.is_riding() then
											table.insert(members_riding, pc.get_name())
										end

										if pc.count_item(PASS_TICKET) < 1 then
											table.insert(members_without_ticket, pc.get_name())
										end

										if get_global_time() - pc.getf("snow_dungeon", "exit_time") < ENTER_LIMIT_TIME * 60 then
											table.insert(members_cooling_down, pc.get_name())
										end

										q.end_other_pc_block()
									end

									if table.getn(members_riding) > 0 then
										say_title(mob_name(ENTRY_MAN) .. ": ")
										say(gameforge.snow_dungeon._630_say)
									elseif table.getn(members_without_ticket) > 0 then
										say_title(mob_name(ENTRY_MAN) .. ": ")
										say(gameforge.snow_dungeon._610_notice)
										say("")

										for i = 1, table.getn(members_without_ticket) do
											say(string.format("  - %s", members_without_ticket[i]))
										end
									elseif table.getn(members_cooling_down) > 0 then
										say_title(mob_name(ENTRY_MAN) .. ": ")
										say(gameforge.snow_dungeon._600_say)
									else
										party.setf("snow_dungeon_boss_kill_count", 0)
										snow_dungeon.make_dungeon()
									end
								end
							end
						end
					else
						say_title(mob_name(ENTRY_MAN) .. ": ")
						say(gameforge.snow_dungeon._160_say)
					end
				end
			else
				say_title(mob_name(ENTRY_MAN) .. ": ")
				say(gameforge.snow_dungeon._170_say)
			end
		end

		when snow_dungeon_killed_A_1.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()

				if d.count_monster() <= 0 then
					if d.getf("level") == 1 then
						notice_multiline(gameforge.snow_dungeon._180_notice, d.notice)
						server_timer("snow_dungeon_level2_start", 10, d.get_map_index())
					elseif d.getf("level") == 3 then
						notice_multiline(gameforge.snow_dungeon._190_notice, d.notice)
						server_timer("snow_dungeon_level4_start", 10, d.get_map_index())
					elseif d.getf("level") == 4 then
						if d.getf("level4_boss_gen") == 0 then
							char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL4_boss_gen STARTED")

							d.setf("level4_boss_gen", 1)
							d.spawn_group_with_immunity(LEVEL4_TARGET_GROUP, setting.LEVEL4_TARGET_pos[1], setting.LEVEL4_TARGET_pos[2], 1, true, 1, {{ type = 0, value = HOSIN_BUFF }})
							d.regen_file(MOB_REGEN_FILE_PATH .. "id_4f.txt")
							server_timer("snow_dungeon_killed_A_2", 6, get_server_timer_arg())
						elseif d.getf("level4_boss_gen") == 1 then
							d.setf("level4_boss_gen", 0)

							notice_multiline(gameforge.snow_dungeon._200_notice, d.notice)
							server_timer("snow_dungeon_level5_start", 10, d.get_map_index())
						end
					elseif d.getf("level") == 6 then
						notice_multiline(gameforge.snow_dungeon._210_notice, d.notice)
						d.spawn_mob_with_immunity(LEVEL6_TARGET, setting.LEVEL6_TARGET_pos[1], setting.LEVEL6_TARGET_pos[2], {{ type = 6, value = 3 }})
					end
				else
					server_timer("snow_dungeon_killed_A_2", 6, get_server_timer_arg())
				end
			end
		end
		when snow_dungeon_killed_A_2.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()

				if d.count_monster() <= 0 then
					if d.getf("level") == 1 then
						notice_multiline(gameforge.snow_dungeon._180_notice, d.notice)
						server_timer("snow_dungeon_level2_start", 10, d.get_map_index())
					elseif d.getf("level") == 3 then
						notice_multiline(gameforge.snow_dungeon._190_notice, d.notice)
						server_timer("snow_dungeon_level4_start", 10, d.get_map_index())
					elseif d.getf("level") == 4 then
						if d.getf("level4_boss_gen") == 0 then
							char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL4_boss_gen STARTED")

							d.setf("level4_boss_gen", 1)
							d.spawn_group_with_immunity(LEVEL4_TARGET_GROUP, setting.LEVEL4_TARGET_pos[1], setting.LEVEL4_TARGET_pos[2], 1, true, 1, {{ type = 0, value = HOSIN_BUFF }})
							d.regen_file(MOB_REGEN_FILE_PATH .. "id_4f.txt")

							server_timer("snow_dungeon_killed_A_1", 6, get_server_timer_arg())
						elseif d.getf("level4_boss_gen") == 1 then
							d.setf("level4_boss_gen", 0)

							notice_multiline(gameforge.snow_dungeon._200_notice, d.notice)
							server_timer("snow_dungeon_level5_start", 10, d.get_map_index())
						end
					elseif d.getf("level") == 6 then
						notice_multiline(gameforge.snow_dungeon._210_notice, d.notice)
						d.spawn_mob_with_immunity(LEVEL6_TARGET, setting.LEVEL6_TARGET_pos[1], setting.LEVEL6_TARGET_pos[2], {{ type = 6, value = 3 }})
					end
				else
					server_timer("snow_dungeon_killed_A_1", 6, get_server_timer_arg())
				end
			end
		end

		when snow_dungeon_level2_start.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()

				char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL 2 started")

				d.setf("level", 2)
				d.jump_all(setting.WARP_pos[2][1], setting.WARP_pos[2][2])
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_2f.txt")

				notice_multiline(gameforge.snow_dungeon._220_notice, d.notice)
			end
		end

		when kill with snow_dungeon.is_snowd(pc.get_map_index()) and d.getf("level") == 2 begin
			local i = number(1, 100)
			if i == 1 then
				game.drop_item(LEVEL2_REALKEY, 1)
			end
		end

		when LEVEL2_REALKEY.use with d.getf("level") == 2 and snow_dungeon.is_snowd(pc.get_map_index()) begin
			if pc.get_job() == 3 then
				if d.getf("level2_clear") == 0 then
					local j = number(1, 5)
					if j == 1 then
						item.remove()
						snow_dungeon.level_clear()
						notice_multiline(gameforge.snow_dungeon._230_notice, d.notice)
						server_timer("snow_dungeon_level3_start", 10, d.get_map_index())
						d.setf("level2_clear", 1)
					else
						say(gameforge.snow_dungeon._240_say)
						item.remove()
					end
				end
			else
				say(gameforge.snow_dungeon._250_say)
			end
		end

		when snow_dungeon_level3_start.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()
				char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL 3 started")
				d.setf("level", 3)
				d.jump_all(setting.WARP_pos[3][1], setting.WARP_pos[3][2])
				d.regen_file(MOB_REGEN_FILE_PATH .. "id_3f.txt")
				server_timer("snow_dungeon_killed_A_1", 6, d.get_map_index())
				notice_multiline(gameforge.snow_dungeon._260_notice, d.notice)
			end
		end

		when snow_dungeon_level4_start.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()
				char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL 4 started")
				d.setf("level", 4)
				d.jump_all(setting.WARP_pos[4][1], setting.WARP_pos[4][2])
				d.regen_file(MOB_REGEN_FILE_PATH .. "id_4f.txt")
				server_timer("snow_dungeon_killed_A_1", 6, d.get_map_index())
				notice_multiline(gameforge.snow_dungeon._270_notice, d.notice)
			end
		end


		when snow_dungeon_level5_start.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()

				char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL 5 started")

				d.setf("level", 5)
				d.jump_all(setting.WARP_pos[5][1], setting.WARP_pos[5][2])
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_5f.txt")

				notice_multiline(gameforge.snow_dungeon._280_notice, d.notice)
				notice_multiline(gameforge.snow_dungeon._290_notice, d.notice)

				local vis = { 0, 0, 0, 0, 0 }

				for i = 1, 5 do
					local ran = number(1, 5)
					local st = 0

					for j = 1, 50 do
						st = st + 1
						if st > 5 then
							st = 1
						end

						if vis[st] == 0 then
							ran = ran - 1

							if ran == 0 then
								vis[st] = 1
								d.set_unique("stone5_" .. st, d.spawn_mob(LEVEL5_STONE, setting.LEVEL5_STONE_pos[i][1], setting.LEVEL5_STONE_pos[i][2]))

								break
							end
						end
					end
				end
			end
		end

		when kill with snow_dungeon.is_snowd(pc.get_map_index()) and d.getf("level") == 5 begin
			local i = number(1, 100)

			if i == 1 then
				game.drop_item(LEVEL5_REALKEY, 1)
			end
		end

		when LEVEL5_STONE.take with snow_dungeon.is_snowd(d.get_map_index()) and item.vnum == LEVEL5_REALKEY and d.getf("level") == 5 begin
			local setting = snow_dungeon.setting()
			if npc.get_vid() == d.get_unique_vid("stone5_1") then
				npc.purge()
				item.remove()

				say(gameforge.snow_dungeon._300_say)

				d.setf("stonekill", 2)
				if d.count_monster() < LEVEL5_GEN_LIMIT then
					d.regen_file(MOB_REGEN_FILE_PATH .. "id_5f.txt")
				end
			elseif npc.get_vid() == d.get_unique_vid("stone5_2") then
				if d.getf("stonekill") == 2 then
					npc.purge()
					item.remove()

					say(gameforge.snow_dungeon._310_say)

					d.setf("stonekill", 3)

					if d.count_monster() < LEVEL5_GEN_LIMIT then
						d.regen_file(MOB_REGEN_FILE_PATH .. "id_5f.txt")
					end
				else
					item.remove()
					say(gameforge.snow_dungeon._320_say)
				end
			elseif npc.get_vid() == d.get_unique_vid("stone5_3") then
				if d.getf("stonekill") == 3 then
					npc.purge()
					item.remove()

					say(gameforge.snow_dungeon._330_say)

					d.setf("stonekill", 4)

					if d.count_monster() < LEVEL5_GEN_LIMIT then
						d.regen_file(MOB_REGEN_FILE_PATH .. "id_5f.txt")
					end
				else
					item.remove()
					say(gameforge.snow_dungeon._320_say)
				end
			elseif npc.get_vid() == d.get_unique_vid("stone5_4") then
				if d.getf("stonekill") == 4 then
					npc.purge()
					item.remove()

					say(gameforge.snow_dungeon._340_say)

					d.setf("stonekill", 5)
					if d.count_monster() < LEVEL5_GEN_LIMIT then
						d.regen_file(MOB_REGEN_FILE_PATH .. "id_5f.txt")
					end
				else
					item.remove()
					say(gameforge.snow_dungeon._320_say)
				end
			else
				if d.getf("stonekill") == 5 then
					npc.purge()
					item.remove()
					notice_multiline(gameforge.snow_dungeon._350_notice, d.notice)
					snow_dungeon.level_clear()
					server_timer("snow_dungeon_level6_start", 10, d.get_map_index())
				else
					item.remove()
					say(gameforge.snow_dungeon._320_say)
					end
				end
			end

		when snow_dungeon_level6_start.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()

				char_log(pc.get_channel_id() .. "" .. 	d.get_map_index(), "NW", "LEVEL 6 started")

				d.setf("level", 6)
				d.jump_all(setting.WARP_pos[6][1], setting.WARP_pos[6][2])
				d.regen_file(MOB_REGEN_FILE_PATH .. "id_6f.txt")
				d.set_unique("stage6_npc", d.spawn_mob(20379, 747, 517))

				server_timer("snow_dungeon_stage6_npc_guard", 10, d.get_map_index())
				server_timer("snow_dungeon_killed_A_1", 6, d.get_map_index())

				notice_multiline(gameforge.snow_dungeon._360_notice, d.notice)
			end
		end

		when LEVEL6_TARGET.kill with snow_dungeon.is_snowd(d.get_map_index()) and d.getf("level") == 6 begin
			notice_multiline(gameforge.snow_dungeon._370_notice, d.notice)
			snow_dungeon.level_clear()

			server_timer("snow_dungeon_level7_start", 10, d.get_map_index())
		end

		when snow_dungeon_level7_start.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()

				char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL 7 started")

				d.setf("level", 7)
				d.jump_all(setting.WARP_pos[7][1], setting.WARP_pos[7][2])
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_7f.txt")

				notice_multiline(gameforge.snow_dungeon._380_notice, d.notice)
				notice_multiline(gameforge.snow_dungeon._390_notice, d.notice)

				local vis = { 0, 0, 0, 0 }

				for i = 1, 3 do
					vis[i] = 0
				end

				for i = 1, 4 do
					local ran = number(1, 4)
					local st = 0

					for j = 1, 50 do
						st = st + 1

						if st > 4 then
							st = 1
						end

						if vis[st] == 0 then
							ran = ran - 1

							if ran == 0 then
								vis[st] = 1
								d.set_unique("boss7_" .. st, d.spawn_mob(LEVEL7_BOSSMOB, setting.LEVEL7_BOSSMOB_pos[i][1], setting.LEVEL7_BOSSMOB_pos[i][2]))

								break
							end
						end
					end
				end

				-- Apply Dragon's Aid requirement (Gicheon buff) to all stage 7 bosses
				for i = 1, 4 do
					local vid = d.get_unique_vid('boss7_' .. i)

					if vid ~= 0 then
						npc.set_damage_immunity_with_conditions(vid, {{ type = 0, value = GICHEON_BUFF }})
					end
				end

				server_timer("snow_dungeon_killed_B_1", 6, d.get_map_index())
			end
		end

		when snow_dungeon_killed_B_1.server_timer begin
			if d.select(get_server_timer_arg()) then
				for i = 1, 3 do
					if not d.is_unique_dead("boss7_" .. i) then
						if d.unique_get_hp_perc("boss7_" .. i) < 50 then
							d.purge_unique("boss7_" .. i)
							notice_multiline(gameforge.snow_dungeon._400_notice, d.notice)
						end
					end
				end

				if d.is_unique_dead("boss7_4") then
					snow_dungeon.level_clear()

					char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL7_BOSSMOB KILLED")

					notice_multiline(gameforge.snow_dungeon._410_notice, d.notice)
					server_timer("snow_dungeon_level8_start", 10, d.get_map_index())
				else
					server_timer("snow_dungeon_killed_B_2", 3, get_server_timer_arg())
				end
			end
		end

		when snow_dungeon_killed_B_2.server_timer begin
			if d.select(get_server_timer_arg()) then
				for i = 1, 3 do
					if not d.is_unique_dead("boss7_" .. i) then
						if d.unique_get_hp_perc("boss7_" .. i) < 50 then
							d.purge_unique("boss7_" .. i)
							notice_multiline(gameforge.snow_dungeon._400_notice, d.notice)
						end
					end
				end

				if d.is_unique_dead("boss7_4") then
					snow_dungeon.level_clear()

					char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL7_BOSSMOB KILLED")

					notice_multiline(gameforge.snow_dungeon._410_notice, d.notice)
					server_timer("snow_dungeon_level8_start", 10, d.get_map_index())
				else
					server_timer("snow_dungeon_killed_B_1", 3, get_server_timer_arg())
				end
			end
		end

		when snow_dungeon_stage6_npc_guard.server_timer begin
			if d.select(get_server_timer_arg()) then
				-- Keep NPC 20379 present during stage 6; respawn if purged
				if d.getf("level") == 6 then
					local vid = d.get_unique_vid("stage6_npc")

					if vid == 0 then
						local new_vid = d.spawn_mob(20379, 747, 517)

						d.set_unique("stage6_npc", new_vid)
					end

					server_timer("snow_dungeon_stage6_npc_guard", 10, d.get_map_index())
				end
			end
		end

		when snow_dungeon_level8_start.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()

				char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL 8 started")

				d.setf("level", 8)
				d.jump_all(setting.WARP_pos[8][1], setting.WARP_pos[8][2])
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_8f.txt")

				notice_multiline(gameforge.snow_dungeon._420_notice, d.notice)
			end
		end

		when kill with snow_dungeon.is_snowd(pc.get_map_index()) and d.getf("level") == 8 begin
			local i = number(1, 100)

			if i == 1 then
				game.drop_item(LEVEL8_REALKEY, 1)
			end
		end

		when LEVEL8_REALKEY.use with snow_dungeon.is_snowd(d.get_map_index()) and d.getf("level") == 8 begin
			if pc.get_job() == 1 or pc.get_job() == 3 then
				if d.getf("level8_clear") == 0 then
					if number(1, 5) == 1 then

						item.remove()
						snow_dungeon.level_clear()

						notice_multiline(gameforge.snow_dungeon._430_notice, d.notice)
						server_timer("snow_dungeon_level9_start", 10, d.get_map_index())

						d.setf("level8_clear", 1)

						if party.is_party() then
							party.setf("snow_dungeon_room_enter", 9)
						end

					else
						say(gameforge.snow_dungeon._240_say)
						item.remove()
					end
				end
			else
				say(gameforge.snow_dungeon._440_say)
			end
		end

		when snow_dungeon_level9_start.server_timer begin
			if d.select(get_server_timer_arg()) then
				local setting = snow_dungeon.setting()

				char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "LEVEL 9 started")

				d.setf("level", 9)
				d.jump_all(setting.WARP_pos[9][1], setting.WARP_pos[9][2])
				d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_9f.txt")
				d.spawn_mob_with_immunity(LEVEL9_TARGET, setting.LEVEL9_TARGET_pos[1][1], setting.LEVEL9_TARGET_pos[1][2], {{ type = 6, value = 1 }, { type = 6, value = 3 }})

				notice_multiline(gameforge.snow_dungeon._450_notice, d.notice)
			end
		end

		when LEVEL9_TARGET.kill with snow_dungeon.is_snowd(pc.get_map_index()) and d.getf("level") == 9 begin
			local setting = snow_dungeon.setting()

			snow_dungeon.level_clear()
			d.spawn_mob_ac_dir(DUNGEON_MAN, 849, 641, 1)
		end

		when DUNGEON_MAN.chat.gameforge.snow_dungeon._460_npcChat with d.getf("level") == 9 and pc.get_map_index() >= DUNGEON_MAP_INDEX * 10000 and pc.get_map_index() < (DUNGEON_MAP_INDEX + 1) * 10000 begin
			local setting = snow_dungeon.setting()

			if not party.is_leader() then
				say(gameforge.snow_dungeon._090_say)
			else
				--if pc.get_level() < 104 then
					--say(gameforge.snow_dungeon._470_say)
					--server_timer("snow_dungeon_end_timer", 10, d.get_map_index())
				--else
					--if pc.getf("main_quest_flame_lv103", "__status")==main_quest_flame_lv103.__COMPLETE__ then
					--if pc.getf("main_quest_lv1", "__status")==main_quest_lv1.__COMPLETE__ then
						say_title(mob_name(DUNGEON_MAN) .. ": ")
						say(gameforge.snow_dungeon._480_say)

						local warp = select(gameforge.snow_dungeon._140_select, gameforge.snow_dungeon._150_select)

						if warp == 1 then
							d.setf("level", 10)
							d.jump_all(setting.WARP_pos[10][1], setting.WARP_pos[10][2])
							d.set_regen_file(MOB_REGEN_FILE_PATH .. "id_boss.txt")
							d.spawn_mob(FINAL_BOSS, setting.boss_pos[1], setting.boss_pos[2])

							notice_multiline(gameforge.snow_dungeon._490_notice, d.notice)
						end
					--else
						--say(gameforge.snow_dungeon._500_say)
						--notice_multiline(gameforge.snow_dungeon._510_notice, d.notice)
						--server_timer("snow_dungeon_end_timer", 10, d.get_map_index())
					--end
				--end
			end
		end

		when FINAL_BOSS.kill with snow_dungeon.is_snowd(d.get_map_index()) and d.getf("level") == 10 begin
			char_log(pc.get_channel_id() .. "" .. d.get_map_index(), "NW", "BOSS KILLED")

			notice_multiline(gameforge.snow_dungeon._520_notice, d.notice)
			notice_multiline(gameforge.snow_dungeon._530_notice, d.notice)

			server_timer("snow_dungeon_end_timer", 60, d.get_map_index())

			snow_dungeon.level_clear()

			if party.is_party() then
				party.setf("snow_dungeon_boss_kill_count", 1)
			end
		end

		when snow_dungeon_45m_left_timer.server_timer begin
			if d.select(get_server_timer_arg()) then
				notice_multiline(string.format(gameforge.snow_dungeon._540_notice, 45), d.notice)
				notice_multiline(gameforge.snow_dungeon._550_notice, d.notice)

				server_timer("snow_dungeon_30m_left_timer", 15 * 60, get_server_timer_arg())
			end
		end

		when snow_dungeon_30m_left_timer.server_timer begin
			if d.select(get_server_timer_arg()) then
				notice_multiline(string.format(gameforge.snow_dungeon._540_notice, 30), d.notice)
				notice_multiline(gameforge.snow_dungeon._550_notice, d.notice)

				server_timer("snow_dungeon_15m_left_timer", 15 * 60, get_server_timer_arg())
			end
		end

		when snow_dungeon_15m_left_timer.server_timer begin
			if d.select(get_server_timer_arg()) then
				notice_multiline(string.format(gameforge.snow_dungeon._540_notice, 15), d.notice)
				notice_multiline(gameforge.snow_dungeon._550_notice, d.notice)

				server_timer("snow_dungeon_5m_left_timer", 10 * 60, get_server_timer_arg())
			end
		end

		when snow_dungeon_5m_left_timer.server_timer begin
			if d.select(get_server_timer_arg()) then
				notice_multiline(string.format(gameforge.snow_dungeon._540_notice, 5), d.notice)
				notice_multiline(gameforge.snow_dungeon._550_notice, d.notice)

				server_timer("snow_dungeon_1m_left_timer", 4 * 60, get_server_timer_arg())
			end
		end

		when snow_dungeon_1m_left_timer.server_timer begin
			if d.select(get_server_timer_arg()) then
				notice_multiline(string.format(gameforge.snow_dungeon._540_notice, 1), d.notice)
				notice_multiline(gameforge.snow_dungeon._550_notice, d.notice)

				server_timer("snow_dungeon_0m_left_timer", 60, get_server_timer_arg())
			end
		end

		when snow_dungeon_0m_left_timer.server_timer begin
			local setting = snow_dungeon.setting()

			if d.select(get_server_timer_arg()) then
				notice_multiline(gameforge.snow_dungeon._560_notice, d.notice)
				notice_multiline(gameforge.snow_dungeon._510_notice, d.notice)

				server_timer("snow_dungeon_end_timer", 10, d.get_map_index())
			end
		end

		when snow_dungeon_end_timer.server_timer begin
			local setting = snow_dungeon.setting()

			if d.select(get_server_timer_arg()) then
				d.setf("party_leader_pid", 0)

				snow_dungeon.clear_timer(d.get_map_index())

				d.set_warp_location(ENTRY_MAP_INDEX, setting.outside_entry_pos[1], setting.outside_entry_pos[2])
				d.exit_all()
			end
		end

		when snow_dungeon_leader_out_timer.server_timer begin
			local setting = snow_dungeon.setting()

			if d.select(get_server_timer_arg()) then
				say_in_map(get_server_timer_arg(), gameforge.snow_dungeon._570_say .. gameforge.snow_dungeon._580_say)
				server_timer("snow_dungeon_end_timer", 10, d.get_map_index())
			end
		end
	end
end