require 'rubyplus'

# バトル
module DarkHall

	PARTY_SIDE = 1
	ENEMY_SIDE = 2

	class Battle
		attr_accessor :actions
		attr_accessor :round, :escape_try_count
		attr_accessor :dead_enemies
		attr_accessor :escape_border_base
		attr_writer :troop_escape_trying
		
		attr_reader :last_round_operated_actions
		attr_reader :last_round_reserved_actions
		attr_accessor :last_action
		attr_accessor :called_enemy_ids
		
		bool_attr_accessor :troop_escape_failured
		bool_attr_accessor :on_stasis
		bool_attr_accessor :praying
		
		attr_reader :starting_members
		attr_reader :number_bonus_rate
		
		
		def initialize
			@round = 1
			@escape_try_count = 0
			@actions = []
			@dead_enemies = []
			@praying = false
			@on_stasis = false
			@troop_escape_trying = false
			@troop_escape_failured = false
			@called_enemy_ids = []
			
			GS.party.members.each do |member|
				member.on_battle_start
			end
			
			@starting_members = GS.party.alive_members.dup
			
			if (number = $troop.all_enemies.size - 3) >= 1 then
				@number_bonus_rate ||= 0.0
				@number_bonus_rate += number * 0.03
			end
			
			if (number = $troop.groups.size - 1) >= 1 then
				@number_bonus_rate ||= 0.0
				@number_bonus_rate += number * 0.05
			end
			
			@last_round_operated_actions = []
			@last_round_reserved_actions = []
			@last_action = nil
			
			round_log
		end
		
		def total_exp
			re = 0
			
			# 倒した敵の経験値
			@dead_enemies.each do |enemy|
				re += enemy.exp
			end
		
			# ダメージを与えている敵の経験値
			# 本来の経験値の（HP減少率×0.5）倍
			$troop.all_enemies.each do |enemy|
				if enemy.alive? then
					re += (enemy.exp * (1.0 - enemy.hp_rate) * 0.5).round
				end
			end
			
			re
		end
		
		def total_gold
			re = 0
			@dead_enemies.each do |enemy|
				re += enemy.gold
			end
			
			re
		end
		
		
		
		def win?
			groups = $troop.groups.map{|x| x.compact}
			groups.each do |group|
				return false unless group.empty?
			end
			
			return true
		end
		
		def lose?
			GS.party.alive_members.empty?
		end

		
		def party_side?
			return(@side == PARTY_SIDE)
		end
		
		def enemy_side?
			return(@side == ENEMY_SIDE)
		end
		
		def on_round_start
			@last_round_reserved_actions.clear
			@last_round_operated_actions.clear
			
			GS.party.alive_members.each do |member|
				if member.forward? then
					member.profiles[MPT::ForwardRound] += 1
				elsif member.back? then
					member.profiles[MPT::BackRound] += 1
				end
			end
		end
		
		def on_round_end
			@round += 1
			
			if @on_stasis then
				LOGGER.puts "[クリンナップ](空間停滞中)"
				Game.message(_('停滞の呪文により、時の流れが止まっている'))
				
				@on_stasis = false
			else
				LOGGER.puts "[クリンナップ]"
				$battle.characters.each do |chara|
					chara.status.each do |state|
						LOGGER.puts("#{chara.name}:#{state.name || state.class.to_s} Lv=#{state.level} Rest=#{state.rest_round}")
						state.on_round_end(chara)
						PARTY_WINDOW.update
						chara.update_last_parameters
	
					end
				end
			end
			
			$battle.characters.each do |chara|
				chara.on_round_end
			end
			
			old_backs = $troop.back_groups
			
			added = false
			unless @called_enemy_ids.empty? then
				while (id = @called_enemy_ids.shift) do
					$troop.add_enemies(id, :front => true)
					added = true
				end
			end
			
			$troop.all_enemies.find_all{|x| x.window.nil?}.each do |enemy|
				enemy.window = EnemyGraphicWindow.new(enemy)
				$enemy_windows.unshift(enemy.window)
			end
			
			$troop.update_formation
			if added then
				msg = _('新たな敵が戦闘に加わった！')
			elsif $troop.back_groups.size < old_backs.size then
				msg = _('奥の敵が前に進み出た！')
			else
				msg = nil
			end
			
			if msg then
				INFORMATION_WINDOW.make_surface(200).update(msg).centering.show
				Game.fade_out_enemy_windows or Game.wait(10)

				Game.set_enemy_positions
				
				# 敵の表示順を再整理
				$windows -= $enemy_windows
				
				$enemy_windows.clear
				$troop.groups.each do |enemies|
					enemies.each do |enemy|
						$enemy_windows.unshift(enemy.window)
					end
				end

				$windows += $enemy_windows
				INFORMATION_WINDOW.show

				Game.fade_in_enemy_windows or Game.wait(10)
				Game.wait(15)
				INFORMATION_WINDOW.hide
			end
			ENEMY_LIST_WINDOW.update

			
			#GS.party.members.each do |member|
			#	if member.spells.include?(:Recovery) && member.spell_caster? then
			#		member.recover_hp(2 + rand(4))
			#	end

			#end

			round_log
		end
		
		
		ESCAPE_SUCCESS_BORDER_MIN = 40
		def party_escape_success_border
			border = 75
			border -= (@round * 6)
			border += (GS.party.agl - $troop.agl)
			border -= ($troop.groups.size * 4)
			border += (@escape_try_count * 8)
			if @round == 1 then
				border += (GS.party.alive_members.map{|x| x.fast_escaping_bonus}.total || 0)
			end
			border = ESCAPE_SUCCESS_BORDER_MIN if border < ESCAPE_SUCCESS_BORDER_MIN 
			return border
		end
		
		def party_escape_success_dice
			CheckDice.new(party_escape_success_border)
		end
		
		def troop_escape_success_border
			border = 45
			border += ($troop.agl - GS.party.agl)
			border = ESCAPE_SUCCESS_BORDER_MIN if border < ESCAPE_SUCCESS_BORDER_MIN 
			return border
		end
		
		def troop_escape_trying_border
			20 + (GS.party.level - $troop.level) * 4 + (GS.party.alive_members.map{|x| x.enemy_ousting_bonus}.total || 0)
		end
		
		def troop_escape_trying_dice
			CheckDice.new(troop_escape_trying_border)
		end

		
		def troop_escape_trying?
			@troop_escape_trying and @round == 1 and not troop_escape_failured?
		end
		

		
		def round_log
		end
		
		def characters
			r = GS.party.members
			$troop.groups.each{|x| r += x}
			return r
		end
		

	end
end
