module DarkHall

	
	RR_COMMON = 1
	RR_UNCOMMON = 2
	RR_RARE = 3
	


	
	class TreasureTable
		attr_reader :content
	
		def initialize
			@content = {}
		end
		
		def table(level, type)
			@content[level] ||= {}
			@content[level][type] ||= []
			@current_list = @content[level][type]
			yield
			@current_list = nil
		end
		
		

		def item(rate, samples)
			@current_list.fill(samples, @current_list.size, rate)
		end
		
		def gold(rate)
			@current_list.fill([nil], @current_list.size, rate)
		end
		
		def pick(level, type)
			list = @content[level][type]
			return nil unless list
			
			inner_list = Util.random_pick(list)
			picked = Util.random_pick(inner_list)
			
			return picked
		end
		
		
		
		def setup
		
			weapons = {}
			DB.treasure_table[TRT::WEAPON].each_with_index do |ids, rank|
				if ids then
					weapons[rank] = ids.map{|x| Weapon.new(x)}
					weapons[rank].each{|x| x.unidentify}
				end
			end
			
			armors = {}
			DB.treasure_table[TRT::ARMOR].each_with_index do |ids, rank|
				if ids then
					armors[rank] = ids.map{|x| DB.find_item(x).kind_of?(ShieldModel) ? Accessory.new(x) : Armor.new(x)}
					armors[rank].each{|x| x.unidentify}
				end
			end
			
			accessories = {}
			DB.treasure_table[TRT::ACCESSORY].each_with_index do |ids, rank|
				if ids then
					accessories[rank] = ids.map{|x| Accessory.new(x)}
					accessories[rank].each{|x| x.unidentify}
				end
			end
		
			items = {}
			DB.treasure_table[TRT::ITEM].each_with_index do |ids, rank|
				if ids then
					items[rank] = ids.map{|x| DB.find_item(x).kind_of?(BundleItemModel) ? BundleItem.new(x, 0) : Item.new(x)}
					items[rank].each{|x| x.unidentify}
				end
			end
		
			potions = {}
			DB.treasure_table[TRT::POTION].each_with_index do |ids, rank|
				if ids then
					potions[rank] = ids.map{|x| Item.new(x)}
					potions[rank].each{|x| x.unidentify}
				end
			end
			
			
		
		
			table(1, TRT::WEAPON){
				item 6, weapons[1]
				item 2, weapons[2]
				gold 2
			}
	
			table(2, TRT::WEAPON){
				item 2, weapons[1]
				item 5, weapons[2]
				item 1, weapons[3]
				gold 2
			}
			
			table(3, TRT::WEAPON){
				item 2, weapons[2]
				item 1, weapons[3]
				gold 1
			}
			
			table(4, TRT::WEAPON){
				item 3, weapons[2]
				item 3, weapons[3]
				item 1, weapons[4]
				gold 2
			}
			
			table(5, TRT::WEAPON){
				item 3, weapons[3]
				item 2, weapons[4]
				gold 2
			}
	
			table(6, TRT::WEAPON){
				item 3, weapons[3]
				item 4, weapons[4]
				item 1, weapons[5]
				gold 2
			}
			
			#d20 + lv*4
	
	
			
			table(1, TRT::ARMOR){
				item 3, armors[1]
				item 1, armors[2]
				gold 1
			}
			
			table(2, TRT::ARMOR){
				item 2, armors[1]
				item 2, armors[2]
				gold 1
			}
			
			table(3, TRT::ARMOR){
				item 4, armors[2]
				item 1, armors[3]
				gold 2
			}
	
			table(4, TRT::ARMOR){
				item 1, armors[2]
				item 1, armors[3]
				gold 1
			}
			
	
			table(5, TRT::ARMOR){
				item 2, armors[2]
				item 4, armors[3]
				gold 2
			}
	
			table(6, TRT::ARMOR){
				item 4, armors[3]
				item 1, armors[4]
				gold 2
			}
	
	
	
			
			table(1, TRT::ACCESSORY){
				gold 5
				item 1, accessories[1]
			}
			
			table(2, TRT::ACCESSORY){
				gold 3
				item 2, accessories[1]
			}
			
			table(3, TRT::ACCESSORY){
				gold 3
				item 6, accessories[1]
				item 1, accessories[2]
			}
			
			table(4, TRT::ACCESSORY){
				gold 2
				item 6, accessories[1]
				item 2, accessories[2]
			}
	
			table(5, TRT::ACCESSORY){
				gold 3
				item 1, accessories[2]
			}
			
			table(6, TRT::ACCESSORY){
				gold 2
				item 2, accessories[2]
			}
	
	
	
			table(1, TRT::ITEM){
				gold 3
				item 2, items[1]
				item 1, potions[1]
			}
	
			table(2, TRT::ITEM){
				gold 2
				item 1, items[1]
				item 1, items[2]
				item 1, potions[1]
			}
			
			table(3, TRT::ITEM){
				gold 2
				item 3, items[1]
				item 2, items[2]
				item 1, items[3]
				item 2, potions[1]
			}
	
			table(4, TRT::ITEM){
				gold 2
				item 1, items[1]
				item 1, items[2]
				item 1, items[3]
				item 5, potions[1]
			}
			
			table(5, TRT::ITEM){
				gold 2
				item 1, items[1]
				item 1, items[2]
				item 1, items[3]
			}
	
			table(6, TRT::ITEM){
				gold 2
				item 1, items[2]
				item 2, items[3]
				item 3, potions[1]
			}
			
			table(5, TRT::POTION){
				gold 1
				item 3, potions[1]
			}
	
			table(6, TRT::POTION){
				gold 1
				item 3, potions[1]
				item 1, potions[2]
			}

		end
	end
	
	TREASURE_TABLE = TreasureTable.new
	
	
	class TreasureBox < StorableObject
		attr_accessor :level, :type, :lock_level, :traps, :gold, :item
	
		def initialize(level, type = nil, rarity = nil)
			@level = level
			@type = type || Util.random_pick(TRT.constants)
			if rarity then
				@rarity = rarity
			else
				case rand(15)
				when 0..10
					@rarity = RR_COMMON
				when 11..13
					@rarity = RR_UNCOMMON
				when 14
					@rarity = RR_RARE
				else
					raise "unknown rarity"
				end
			end
			set_lock
			set_traps
			set_treasure
		end
		
		def set_lock
			if diceroll('d100', 60) then
				@lock_level = [@level * 2 + rand(4) - 2, 1].max
			end
		end
		
		def set_traps(trap_types = nil)
			if trap_types then
				@traps = trap_types
			else
				table = []
				# 宝箱レベル×2を基準として、近いレベルの罠ほどでやすい
				TRAP_LEVELS.each_pair do |type, trap_level|
					diff = (@level * 2 - trap_level).abs
					next if diff >= 5
					(5 - diff).times{ table << type }
				end
			
				# 罠個数判定
				@traps = []
				case diceroll('d100')
				when 0...80
					@traps << table[rand(table.size)]

				end
				@traps.uniq!
			end
		end
		

		def set_treasure
			@item = nil
			
			if @type == TRT::BIG_GOLD then
				expect = @level * 20
			else
				treasure = TREASURE_TABLE.pick(@level, @type)
				if treasure then
					@item = treasure.dup
					if @item.data.kind_of?(ArrowModel) then
						@item.number = 3 + rand(4)
					elsif @item.kind_of?(Weapon) or @item.kind_of?(Armor) then
						@item.set_prefix
					end
					expect = @level * 5
				else
					expect = (@level + 2) * 5
				end
			end
			
			@gold = DoubleDice.new(expect * 2, expect, 0.6).roll
			
			return self
		end
		
		def content_description
			if @item then
				"#{@gold}枚の金貨と、#{@item.name}が入っている"
			else
				"#{@gold}枚の金貨が入っている"
			end
		end
		
		
		def debug_info_texts
			texts = []
			texts << ["宝箱Lv", @level]
			texts << ["施錠Lv", @lock_level || "鍵なし"]
			texts << ["罠", self.trap_names.join("/")]
			texts << ["金品", @gold]
			texts << ["アイテム", (@item ? @item.name : "")]
			return texts
		end
		
		def locked?
			return (@lock_level ? true : false)
		end
		
		def unlocking_hint(unlocker)
			return "鍵はかかっていない" unless self.locked?
		
			diff = @lock_level - unlocker.skill_levels[SKILL::UNLOCK]
			if diff >= 10 then
				return "とても開きそうにない鍵"
			elsif diff >= 6 then
				return "かなり複雑な鍵"
			elsif diff > 2 then
				return "少し複雑な鍵"
			elsif diff > -2 then
				return "開けられそうな鍵"
			else
				return "易しい鍵"
			end
		end
		
		# 鍵を開けられるかどうかの判定（実際に鍵は開けない）
		def try_unlock(unlocker)
			diff = @lock_level - unlocker.skill_levels[SKILL::UNLOCK]
			return Roll::Dice.new.roll(50 - diff * 3)
		end
		
		# 鍵を開ける
		def unlock
			@lock_level = nil
		end
		
		# 罠の種類を推察する
		def detect_traps(detector)
			guess_traps = []
			dice = Roll::Dice.new
			@traps.each do |trap_symbol|
				diff = TRAP_LEVELS[trap_symbol] - detector.skill_levels[SKILL::REMOVE_TRAP]
				result = dice.roll(80 - diff * 2)
				if result >= Roll::SUCCESS then
					guess_traps << trap_symbol
				# ファンブルの場合は罠の種類を誤解する
				elsif result == Roll::FUMBLE then
					trap_set = TRAP_LEVELS.dup
					trap_set.delete_if{|k, v| v <= detector.skill_levels[SKILL::REMOVE_TRAP]} # レベルが低い罠に限定
					trap_set.delete_if{|k, v| @traps.include?(k)} # 重複回避
					guess_traps << trap_set.keys[rand(trap_set.size)] unless trap_set.empty?
				end
			end
			names = guess_traps.map{|x| TRAP_NAMES[x]}
			return (names.empty? ? "罠は仕掛けられていない？" : "#{names.join("、")}？")
		end
		
		# 確実に罠を解析する
		def analysis_traps
			names = @traps.map{|x| TRAP_NAMES[x]}
			return (names.empty? ? "罠は仕掛けられていない" : "#{names.join("、")}")
		end
		
		# 罠を外せるかどうかの判定（実際に罠は外さない）
		def try_remove_trap(remover, trap_symbol)
			dice = Roll::Dice.new
			diff = TRAP_LEVELS[trap_symbol] - remover.skill_levels[SKILL::REMOVE_TRAP]
			border = 50 - diff * 3
			LOGGER.puts("罠解除判定\n\t罠: %s (L%d)\n\t開錠レベル: %d\n\t成功率: %d%%" % [trap_names.join('/'), TRAP_LEVELS[trap_symbol], remover.skill_levels[SKILL::REMOVE_TRAP], success_rate(border)])
			return dice.roll(border)
		end
		
		def get_remove_trap_dice(remover, trap_symbol)
			diff = TRAP_LEVELS[trap_symbol] - remover.skill_levels[SKILL::REMOVE_TRAP]
			border = 50 - diff * 4
			return CheckDice.new(border)
		end
		

		
		# 罠を外す
		def remove_trap(symbol)
			@traps.delete(symbol)
		end
		
		# 罠の発動を回避できるかどうかの判定
		def try_avoid_operating_trap(remover, border_base)
			dice = Roll::Dice.new
			@traps.each do |trap_symbol|
				diff = TRAP_LEVELS[trap_symbol] - remover.skill_levels[SKILL::REMOVE_TRAP]
				return trap_symbol if Roll::FAIL <= dice.roll(border_base - diff * 2)
			end
			return nil
		end
		
		def trap_names
			return @traps.map{|x| TRAP_NAMES[x]}
		end
		
		def dump
			hash = super
			hash['level'] = @level
			hash['type'] = @type
			hash['lock_level'] = @lock_level
			hash['gold'] = @gold
			hash['item'] = @item
			hash['traps'] = @traps.map{|x| x.to_s}
			return hash
		end
		
		def self.create_from_mpac_model(hash)
			obj = self.new(hash['level'], hash['type'])
			obj.lock_level = hash['lock_level']
			obj.gold = hash['gold']
			obj.item = hash['item']
			obj.traps = hash['traps'].map{|x| x}
			return obj
		end

	end
end
