#　ダイスロール関連

require 'darkhall/const'
require 'darkhall/roll_table'
require 'darkhall/action'


module DarkHall
	class CheckDice
		attr_reader :border
	
		def initialize(border)
			@border = border.to_i
		end
		
		def roll
			return diceroll('3d33', @border)
		end
		
		alias check roll
		
		def success_rate
			if @border <= 20 then
				ROLL_TABLE[20] * 0.01
			elsif @border >= 80 then
				ROLL_TABLE[80] * 0.01
			else
				ROLL_TABLE[@border] * 0.01
			end
		end
		
		def success_percentage
			(success_rate * 100).round
		end
		
		def failure_rate
			1.00 - success_rate
		end
		
		def failure_percentage
			(failure_rate * 100).round
		end
	end
	
	class DoubleDice
		attr_reader :base, :reducing, :balance
	
		def initialize(base, red, balance = 0.5)
			@base = base.to_i
			@reducing = red.to_i
			@balance = balance
		end
		
		def imbalance
			1.0 - @balance
		end
		
		def roll
			b = @base - rand((@base * imbalance).to_i)
			r = @reducing - rand((@reducing * imbalance).to_i)
			
			return fold_in_range(b - r)
		end
		
		def expectation_min
			fold_in_range((@base * @balance).to_i - (@reducing * @balance).to_i)
		end
		
		def expectation_max
			fold_in_range(@base - @reducing)
		end
		
		def min
			fold_in_range((@base * @balance).to_i - @reducing)
		end
		
		def max
			fold_in_range(@base - (@reducing * @balance).to_i)
		end
		
		def center
			((expectation_min + expectation_max) / 2.0).round
		end
		
		def to_s
			sprintf("%d - %d - %d - %d - %d", min, expectation_min, center, expectation_max, max)
		end
		
		def expected_range_caption
			range_caption
		end
		
		def range_caption
			sprintf("%d - %d - %d - %d", min, expectation_min, expectation_max, max)
		end
		
		private
		def fold_in_range(num)
			if num < 1 then
				return 1
			else
				return num
			end
		end
		
	end

	module Roll
		CRITICAL = 3
		SUCCESS = 2
		FAIL = 1
		FUMBLE = 0

		class Dice
		
			def initialize
			end
			
			def critical_border(border)
				return 20
			end
			
			def fumble_border(border)
				return [border + 50, 80].min
			end
			
			def roll(border)
				result = diceroll('3d33')
				if result >= fumble_border(border) then
					return FUMBLE
				elsif result <= critical_border(border) then
					return CRITICAL
				elsif result <= border then
					return SUCCESS
				else
					return FAIL
				end
			end
		end
	
		def Roll.check_3d33(border)
			border = 80 if border >= 80
			border = 20 if border <= 20
			
			return diceroll('3d33', border)
			
		end
		
		def Roll.randomize(param)
			return (param * (80 + rand(40)) / 100.0).to_i
		end
	
		def Roll.attack_hit_border(attacker, defender)
			border = 50
			
			border += (attacker.weapon_hitting - defender.avoid)
			border -= 10 if defender.guarding?
			
			return border
		end
		
		
		def Roll.find_treasure?
			border = 90
			border += (GS.party.alive_members.map{|x| x.kind_of?(Explorer)}.size * 2)
		
			return check_3d33(border)
		end

		def Roll.detect_trap?(actor, level)
			border = 70
			return check_3d33(border)
		end

		def Roll.remove_trap?(actor, level)
			border = 60
			return check_3d33(border)
		end
		

		def Roll.attack_damage(attacker, defender, hit)
			result = 0
			hit.times do
				atk = attacker.attack
				df = defender.defense
				
				
				damage = double_roll(atk, df)
				# 防御していればダメージ減少
				damage * 0.7 if defender.action.kind_of?(GuardAction)
				damage = [damage, 1].max
				
				
				
				result += damage
			end
			
			return result.to_i
		end
		
		
		def Roll.magic_damage(attacker, defender, damage_rate, casting_ct = nil)
			casting_ct ||= attacker.ct
			atk = 0
			atk += attacker.magic_attack
			atk *= damage_rate
			df = defender.defense
			
			damage = double_roll(atk, df)
			damage *= 0.7 if defender.action.kind_of?(GuardAction)
			# CT補正
			damage = damage * attacker.ct / 100
			damage = [damage, 1].max
				
			return damage.to_i
		end
		
		def Roll.magic_value(actor, rate, casting_ct = nil)
			casting_ct ||= actor.ct
			atk = 0
			atk += actor.magic_attack
			atk *= rate
			
			value = double_roll(atk, atk / 3)
			# CT補正
			value = value * actor.ct / 100
			value = [value, 1].max
				
			return value.to_i
		end
		
		def Roll.add_status?(target, status_symbol, border)
			return check_3d33(border - target.status_resist(status_symbol))
		end
		
		
	end

	
	#def double_roll(p1, p2)
	#	return ((p1/2 + rand(p1/2 + 1)) - (p2/2 + rand(p2/2 + 1)))
	#end
	
	# obsolete
	def double_roll(p1, p2, balance = 0.5)
		dice = DoubleDice.new(p1, p2, balance)
		return dice.roll
	end
	
	def diceroll(dice, border = nil)
		result = 0
		number, max = dice.split("d")
		number = 1 if number.empty?
		max = 6 if max.empty?
		number = number.to_i
		max = max.to_i
	
		number.times do
			result = result + rand(max) + 1
		end
	
		if border then
			return (result <= border.to_i)
		else
			return result
		end
	end
	
	include Roll

end
