module DarkHall
	class BattleStartPhase < Phase
		def initialize(msg)
			@appearing_message = msg
		end
	
		def on_enter(from)
			$battle = Battle.new
			$section = BATTLE
			
			
			SE.encount
			INFORMATION_WINDOW.align = AL_CENTER
			INFORMATION_WINDOW.make_surface(@appearing_message).update.centering
			ENEMY_LIST_WINDOW.make_surface.update
			DUNGEON_WINDOW.update
		
			# 敵グラウインドウセット
			
			$troop.update_formation
			$enemy_windows.clear
			
			$troop.groups.each do |enemies|
				enemies.each do |enemy|
					enemy.window = EnemyGraphicWindow.new(enemy)
					$enemy_windows.unshift(enemy.window)
				end
			end
			
			Game.set_enemy_positions
			

			
			$windows = [DUNGEON_WINDOW, PARTY_WINDOW] + $enemy_windows
			INFORMATION_WINDOW.show if @appearing_message
			
			if $troop.kind_of?(BossTroop) then
				#BGM.play_in_loop(:BossBattleIntro, :BossBattleMain)
				BGM.play(:BossBattle)
			else
				BGM.play(:Battle)
			end
			
			
			Game.fade_in_enemy_windows or Game.wait(10)
			Game.wait(10)
			
			
			# 死霊実体化処理
			if (prayer = GS.party.prayer) and not (ghosts = $troop.all_enemies.find_all{|x| x.ghost_body}).empty? then
				ghosts.each do |ghost|
					ghost.sealed_ghost_body = true
				end
				$enemy_windows.each{|x| x.reset_alpha}
				Game.message([_("%{member}の力により、死霊たちの姿が実体化した！").evaluate(:member => prayer.name)])
			end

			
			Game.reporter.on_battle_start
			
			# 敵が1ラウンド目で逃走を試みるかどうか
			LOGGER.puts "PTLv#{GS.party.level} - 敵Lv#{$troop.level}"
			LOGGER.puts "PT敏捷:#{GS.party.agl} - 敵敏捷:#{$troop.agl}"
			LOGGER.puts "敵の逃走率: #{$battle.troop_escape_trying_dice.success_percentage}%"
			$battle.troop_escape_trying = ($troop.sometime_escape? and Roll.check_3d33($battle.troop_escape_trying_border))
			if $battle.troop_escape_trying? then
				LOGGER.puts "敵の逃走トライ"
				Game.message([_("敵は逃げ出そうとしている！")])
			end
			
			LOGGER.info "戦闘開始！"
			Phase.change(BattleCommandPhase.new)
			
		end
	end
	
	

=begin
	class BattleCommandMemberSelectPhase < Phase
		include MemberSelectPhase
		def on_enter(from)
			super
			$windows = [ENEMY_LIST_WINDOW, DATA_WINDOW, PARTY_WINDOW]

			DATA_WINDOW.texts = [["逃走成功率", "70%"]]
			DATA_WINDOW.make_surface(200, 1).dock_beside(ENEMY_LIST_WINDOW, :bottom)
			PARTY_WINDOW.add_extra_item(:party, "パーティーコマンド(P)", SDL::Key::F)
			PARTY_WINDOW.update_surface
		end
		
		def on_select(id)
			if id == :party then
				Phase.change(BattlePartyCommandPhase.new)
			else
				$member_index = id
			end
		end
	end
=end





	class BattleCommandPhase < Phase
		def on_enter(from)
			super
			@command_window = SELECT_WINDOW
			
			#if $battle.troop_escape_trying? then
			#	@escape_window = TextWindow.new
			#	@escape_window.align = AL_CENTER
			#	@escape_window.text =  _("敵は逃走しようとしている！")
			#	@escape_window.set_good_width.make_surface
			#	@escape_window.centering
			#else
				@escape_window = DoubleTextWindow.new
				texts = @escape_window.texts.clear
				texts << _("ラウンド%{n}") % {:n => $battle.round}
				if $battle.troop_escape_trying? then
					texts << [_("敵は逃げ出そうとしている")]
				else
					rate = sprintf("%d%%", $battle.party_escape_success_dice.success_percentage)
					
					texts << [_("逃走成功率"), rate]
				end
				@escape_window.make_surface(160, 2).dock_beside(ENEMY_LIST_WINDOW, :bottom)
				@escape_window.right = ENEMY_LIST_WINDOW.right
			#end
			
			@escape_window.update
			
			#$windows = [DUNGEON_WINDOW, PARTY_WINDOW, @escape_window, ENEMY_LIST_WINDOW] + $enemy_windows + [@command_window]
			$windows = [DUNGEON_WINDOW, PARTY_WINDOW, @escape_window] + $enemy_windows + [@command_window]

			
			ENEMY_LIST_WINDOW.update

			items = @command_window.select_items.clear
			if $battle.troop_escape_trying? then
				items << SelectItem.new(:block_and_fight, _("阻止して戦う(F)"), SDL::Key::F)
			else
				items << SelectItem.new(:fight, _("戦う(F)"), SDL::Key::F)
			end
			#items << SelectItem.new(nil, "自動戦闘(A)", SDL::Key::A)
			items << SelectItem.new(:order, _("隊列変更(O)"), SDL::Key::O)
			#items << SelectItem.new(:enemy_inspect, _("敵の状態(I)"), SDL::Key::I) if GS.party.find_member(Academian)
			#items << SelectItem.new(:status, "ステータス(S)", SDL::Key::S)
			
			if $battle.troop_escape_trying? then
				items << SelectItem.new(:pass_to_escape, _("逃がす(E)"), SDL::Key::E)
			else
				items << SelectItem.new(:escape, _("逃走(E)"), SDL::Key::E)
			end
			
			items << SelectItem.new(:enemy_data, "＊敵データ表示") if Game.debug_mode?
			items << SelectItem.new(:win, "＊無条件勝利") if Game.debug_mode?
			items << SelectItem.new(:raise, "＊強制エラー") if Game.debug_mode?
			@command_window.make_surface(180, items.size).dock_beside(PARTY_WINDOW, :top)
			@command_window.reset_index.warp
			#@command_window.right = PARTY_WINDOW.right
			
			PARTY_WINDOW.update
			LOGGER.puts "[コマンド入力]"
			
		end
		
		def on_select(id)
			case id
			when :block_and_fight
				params = {:party => GS.party.name}
				if Roll.check_3d33($battle.troop_escape_success_border) then
					BGM.fade_out
					msg = _("%{party}は逃げ道を阻もうとした\nしかし間に合わず、敵は逃げ出してしまった……")
					message(msg.evaluate(params))
					
					Phase.change(BattleResultPhase.new(BR_TROOP_ESCAPE))
					return
				else
					msg = _("%{party}はうまく敵の逃げ道を阻んだ\n先制攻撃のチャンス！")
					message(msg.evaluate(params))
					$battle.troop_escape_failured = true
					Phase.change(BattleCommandPhase.new)
				end
				on_select(:fight)

			when :fight
				$member_index = 0
				
				archers = GS.party.find_all_members(Archer)
				archers.each do |archer|
					if (state = archer.status.find{|x| x.kind_of?(ChargingState)}) && state.at_release_round? then
						archer.set_action(ReleaseArrowAction.new(archer, state.attack_targets, state.level))
					end
				end
				
				Phase.change(BattleMemberCommandFirstPhase.new)
			when :order
				Phase.change(BattleOrderChangePhase.new)
			when :pass_to_escape
				ENEMY_LIST_WINDOW.hide
				DATA_WINDOW.hide
				BGM.fade_out
				message _('敵は素早く逃げ出した……')
				Phase.change(BattleResultPhase.new(BR_TROOP_ESCAPE))
			when :escape
				text_params = {:party => GS.party.name}
				if Roll.check_3d33($battle.party_escape_success_border) then
					ENEMY_LIST_WINDOW.hide
					DATA_WINDOW.hide
					BGM.fade_out
					message(eval_text(_('%{party}は逃げ出した……'), text_params))
					GS.party.alive_members.each{|x| x.profiles[MPT::Escape] += 1}
					GS.player_profiles[PPT::Escape] += 1
					Phase.change(BattleResultPhase.new(BR_PARTY_ESCAPE))
				else
					GS.party.members.each{|x| x.remove_state(HidingState)}
					PARTY_WINDOW.update
					message(eval_text(_("%{party}は逃げ出そうとした\nしかし逃げ道を阻まれた！"), text_params))
					$battle.escape_try_count += 1
					Phase.change(BattleRoundPhase.new(true))
				end
			when :enemy_inspect
				Phase.change(EnemyInspectPhase.new($troop.groups.first))
			when :state_test
				status = []
				status << PoisonState.new
				status << SmashedState.new
				status << SleepState.new
				status << ParalyzedState.new
				status << BlindState.new

				items = status.map{|x| SelectItem.new(status.index(x), x.name)}
				index = Game.select(items)
				if index != :cancel then
					state = status[index]
					member_index = Game.member_select(_("だれに？"))
					if member_index then
						GS.party.members[member_index].add_state(state.dup)
						PARTY_WINDOW.update
					end
				end
				SELECT_WINDOW.show
				
			when :enemy_data
				enemy = $troop.groups.first.first
				texts = []
				texts << [enemy.name, ""]
				texts << ["HP", "#{enemy.hp}/#{enemy.hp_max}"]
				texts << ["特性値", "#{enemy.str}/#{enemy.tec}/#{enemy.agl}/#{enemy.wil}/#{enemy.psy}"]
				texts << ["致傷力", enemy.weapon_power]
				texts << ["攻撃回数", enemy.hitting_number]
				texts << ["命中", enemy.weapon_hitting]
				texts << ["回避", enemy.avoid]
				texts << ["所持exp&金貨", "#{enemy.exp}/#{enemy.gold}"]
				Game.show_debug_data_window(texts)
			when :status
				Phase.change(BattleStatusMemberSelectPhase.new)
			when :win
				Phase.change(BattleResultPhase.new(BR_WIN))
			when :raise
				raise('forced exception in battle')
			when :state
				select = Game.member_select("だれに？")
			end
		end
		
	end
	
	module EnemySelectPhase
		def on_enter(from)
			super
			$windows = [DUNGEON_WINDOW, PARTY_WINDOW] + $enemy_windows + [ENEMY_LIST_WINDOW]
			ENEMY_LIST_WINDOW.show.reset_index.warp
		end
	end

	


	
	class BattleStatusMemberSelectPhase < Phase
		def initialize
			super(_("だれの？"), 0)
		end
		
		def on_enter(from)
			super
			$windows = [ENEMY_GRAPHIC_WINDOW, ENEMY_LIST_WINDOW, INFORMATION_WINDOW, PARTY_WINDOW]
		end
		
		
		def on_select(id)
			super
			if id == :bar then
				
			else
				$member_index = id
				Phase.change(BattleStatusPhase.new)
				
			end
		end
		
		def on_cancel
			Phase.change(BattleCommandPhase.new)
		end
	end
	
	class BattleStatusPhase < Phase
		include BackablePhase
		include MemberChangablePhase
		
		def on_enter(from)
			super
			$windows = [DUNGEON_WINDOW, PARTY_WINDOW] + $enemy_windows + [ENEMY_LIST_WINDOW, STATUS_WINDOW]
			STATUS_WINDOW.make_surface.centering(true)
		end
		
		def on_enter_key
			
			Phase.change(StatusCommandPhase.new)
		end
		
		def on_cancel
			STATUS_WINDOW.break_surface
			Phase.change(BattleStatusMemberSelectPhase.new)
		end
	end
	
	
	module BattleMemberCommandPhase
		def decide_action(action)
			Game.current_member.set_action(action)
			$member_index += 1
			Phase.change(BattleMemberCommandFirstPhase.new)
		end
	end
	
	class BattleMemberCommandFirstPhase < Phase
		include BattleMemberCommandPhase
		def on_enter(from)
			loop do
				if $member_index >= GS.party.members.size then
					PARTY_WINDOW.update
					
					if GS.party.members.find{|x| x.commandable?} then
						# 最終確認
						$windows = [DUNGEON_WINDOW, PARTY_WINDOW] + $enemy_windows + [ENEMY_LIST_WINDOW]
						items = []
						items << SelectItem.new(:decide, _('戦闘開始(D)'), SDL::Key::D)
						items << SelectItem.new(:cancel, _('キャンセル'))
						if Game.select(items, :silent => true) == :decide then
							LOGGER.puts "全員の入力完了"
							Phase.change(BattleRoundPhase.new)
							return
						else
							SE.cancel
							on_cancel
						end
					else
						LOGGER.puts "行動可能者がいないため最終確認はスキップ"
						Phase.change(BattleRoundPhase.new)
						return
					end
				end
			
				if Game.current_member.commandable? then
					break
				else
					LOGGER.puts "#{Game.current_member.name}は行動選択不可なのでスキップ"
					$member_index += 1
				end
			end
		
			#($member_index...(GS.party.members.size)).each do |i|
			#	GS.party.members[i].action = nil
			#end
			
			super
			@command_window = SELECT_WINDOW
			$windows = [DUNGEON_WINDOW, PARTY_WINDOW] + $enemy_windows + [WARNING_WINDOW, ENEMY_LIST_WINDOW, @command_window, NAME_WINDOW]
			WARNING_WINDOW.reset.dock_beside(ENEMY_LIST_WINDOW, :bottom)

			# メンバー名
			NAME_WINDOW.make_surface(150, 1)
=begin
			# メンバー
			@member_windows = []
			GS.party.members.each do |member|
				window = MemberWindow.new
				window.width = 180
				window.height = 80
				window.texts.clear << [member.name, ""] << ["HP", "#{member.hp} / #{member.hp_max}"]
				window.texts << ["CT", "#{member.ct}%"]
				window.make_surface
				@member_windows << window
			end
			
			@member_windows.each_index do |i|
				window = @member_windows[i]
				
				if i >= 3 then
					window.left = 8 + 16 + (i - 3) * (window.width + 8)
					window.bottom = SCREEN_HEIGHT - 8
				else
					window.left = 8 + i * (window.width + 8)
					window.bottom = SCREEN_HEIGHT - 8 - window.height - 8
				end
				
				#window.show
			end
=end

			# コマンド
			self.set_command
			@command_window.make_surface(NAME_WINDOW.width, 7)
			last_id = Game.current_member.last_select_ids[SelectType::BattleCommand]
			if last_id and @command_window.select_items.map{|x| x.id}.compact.include?(last_id) then
				@command_window.set(last_id)
				@command_window.regulate_index
				
				# 記憶されているコマンドが選択不能ならリセット
				if @command_window.current_item.disabled? then
					@command_window.reset_index
				end
			else
				@command_window.reset_index
			end
			self.on_change
			# 配置
			
			@command_window.dock_beside(PARTY_WINDOW, :top)
			@command_window.right = PARTY_WINDOW.right
			NAME_WINDOW.dock_beside(@command_window, :top, -1)
			NAME_WINDOW.update(Game.current_member.name)
			base_window = PARTY_WINDOW
			status = Game.current_member.status.find_all{|x| x.visible?}
			status[0..3].each do |state|
				window = TextWindow.new.make_surface(160, 1)
				window.update(state.caption).dock_beside(base_window, :top)
				window.left = base_window.left
				$windows << window
				base_window = window
			end
			
			@command_window.show.warp

		end
		
		def set_command
			member = GS.party.members[$member_index]
			items = @command_window.select_items.clear
	
			# 攻撃系コマンド
			if member.find_state(HidingState) then
				items << SelectItem.new(:attack, _("奇襲(A)"), SDL::Key::A)
			else
				items << SelectItem.new(:attack, _("攻撃(A)"), SDL::Key::A)
			end
			
			case member
			when Fighter
				items << SelectItem.new(:ranpage, _("猛襲(R)"), SDL::Key::R)
				if member.weapon.data.kind_of?(AutoBowModel) then
					items.last.disable(_("自動弓では使用できない"))
				end
				items << SelectItem.new(:feint, _("フェイント(F)"), SDL::Key::F)
			when Grappler
				items << SelectItem.new(:sharp_attack, _("精密打撃(S)"), SDL::Key::S)
				
			when HeavyFighter
				items << SelectItem.new(:smash, _("強打(S)"), SDL::Key::S)
				if member.weapon.data.kind_of?(AutoBowModel) then
					items.last.disable(_("自動弓では使用できない"))
				end

			when Archer
				items << SelectItem.new(:charge, _("チャージ(C)"), SDL::Key::C)
				unless member.weapon.data.kind_of?(BowModel) then
					items.last.disable(_("弓以外では使用できない"))
				end
			#when Explorer
			#	items << SelectItem.new(:hide, "隠れる(H)", SDL::Key::H)
			#when Magician
			#	items << SelectItem.new(:concentrate, "集中(C)", SDL::Key::C)
			end
			
			if member.hp <= 0 and not member.find_state(HidingState) then
				# 潜伏状態のときは特例で攻撃できる
				items.each{|x| x.disable(_("HPが0以下の時は攻撃できない"))}
			elsif member.back? and not member.weapon.long_range  then
				items.each{|x| x.disable(_("後列からは攻撃できない"))}
			elsif (member.weapon.data.kind_of?(BowModel) and member.arrows.empty?) or
			(member.weapon.data.kind_of?(AutoBowModel) and member.bolts.empty?) then
				items.each{|x| x.disable(_("矢を持っていない"))}
			end

			
			# そのほかのコマンド
			case member
			when Explorer
				items << SelectItem.new(:hide, _("隠れる(H)"), SDL::Key::H)
				items.last.disable(_('すでに身を隠している')) if member.find_state(HidingState) 
			when Prayer
				items << SelectItem.new(:pray, _("祈る(P)"), SDL::Key::P)
			end
			
			items << SelectItem.new(:guard, _("身を守る(G)"), SDL::Key::G)
			items << SelectItem.new(:block, _("ブロック(B)"), SDL::Key::B)
			items.last.disable(_("後列からはブロック不可")) if member.back?
			if member.spell_caster? then
				items << SelectItem.new(:magic, _("呪文を唱える(C)"), SDL::Key::C)
				items.last.disable(_("呪文未修得")) if member.spells.empty?
				if member.kind_of?(Magician) then
					items << SelectItem.new(:magic_boost, _("ブースト(Ctrl+C)"), [:ctrl, SDL::Key::C])
				end
				items.last.disable(_("呪文未修得")) if member.spells.empty?
			end
			
			items << SelectItem.new(:item, _("アイテム(I)"), SDL::Key::I)
			items.last.disable(_("使用可能なアイテムがない")) unless member.items.find{|x| x.battle_usable?}
			items << SelectItem.new(:cancel, _("キャンセル"))
			

		end
		
		def on_change
			member = Game.current_member
			item = SELECT_WINDOW.select_items[SELECT_WINDOW.index]
			if item.disabled? then
			
				WARNING_WINDOW.update(item)
			else
				WARNING_WINDOW.update(nil)
			end
			
		end
		
		def on_select(id)
			Game.current_member.last_select_ids[SelectType::BattleCommand] = id
			case id
			when :attack
				Phase.change(AttackTargetSelectPhase.new)
			when :ranpage
				Phase.change(RanpageTargetSelectPhase.new)
			when :feint
				Phase.change(FeintTargetSelectPhase.new)
			when :sharp_attack
				Phase.change(SharpAttackSelectPhase.new)
			when :smash
				Phase.change(SmashTargetSelectPhase.new)
			when :charge
				Phase.change(ChargingLevelSelectPhase.new)
			when :hide
				decide_action(HideAction.new(Game.current_member))
			when :pray
				decide_action(PrayAction.new(Game.current_member))
			when :magic
				Phase.change(BattleSpellSelectPhase.new)
			when :magic_boost
				if Game.current_member.magic_boost? then
					Game.current_member.added_status.delete_if{|x| x.kind_of?(MagicBoostState)}
				else
					Game.current_member.add_state(MagicBoostState.new)
				end
				Phase.change(BattleMemberCommandFirstPhase.new)
			when :guard
				decide_action(GuardAction.new(Game.current_member))
			when :block
				decide_action(BlockAction.new(Game.current_member))
			when :item
				Phase.change(BattleItemSelectPhase.new)
			when :cancel
				self.on_cancel
			end
		end
		
		def on_cancel
			
			loop do
				$member_index -= 1

				if $member_index <= -1 then
					Phase.change(BattleCommandPhase.new)
					break
					
				elsif Game.current_member.commandable? then
					Game.current_member.clear_action
					Phase.change(BattleMemberCommandFirstPhase.new)
					break
				end
			end
		end
	end

	class BattleItemSelectPhase < Phase
		include BattleMemberCommandPhase

		include ItemSelectPhase
		def on_enter(from)
			@item_window = BattleItemWindow.new.make_surface
			@item_window.update(true)

			DESCRIPTION_WINDOW.show
			@item_window.dock_beside(DESCRIPTION_WINDOW, :bottom)
			@item_window.show.reset_index.warp
			on_change
		end
		
		
		def on_select(id)
			item = Game.current_member.items[id]
			act = nil
			catch(:cancel){
				
			
				case item.effect.target_type
				when TG_MEMBER
					member_index = Game.member_select(_('だれに？'))
					throw(:cancel) unless member_index
					act = ItemUseAction.new(Game.current_member, [GS.party.members[member_index]], item)
				else
					act = ItemUseAction.new(Game.current_member, nil, item)
				end
			}

			decide_action(act)
		end
		

		def on_change
			self.update_item_information(Game.current_member.items[@item_window.current_id]) if @item_window.current_id
		end
		
		
		def on_cancel
			Phase.back
		end
	end

	
	# パーティーメンバーの並び順の変更
	class BattleOrderChangePhase < Phase
		include OrderChangePhase
		
		def on_enter(from)
			super
			$windows.delete DUNGEON_WINDOW
			$windows.unshift ENEMY_LIST_WINDOW
			$windows = $enemy_windows + $windows
			$windows.unshift DUNGEON_WINDOW
			@new_order_window.show
			@old_order_window.show
			
		end
	end
	
	class ChargingLevelSelectPhase < Phase
		include BattleMemberCommandPhase
		attr_reader :main_window
		
		def on_enter(from)
			super
			
			member = Game.current_member
			
			@main_window = MultiColumnWindow.new.make_surface(540, 4).centering
			columns = @main_window.columns.clear
			columns << ColumnItem.new("", [], 240)
			columns << ColumnItem.new("ROUND", ChargingState::RELEASE_ROUND_TABLE, 40, AL_RIGHT)
			columns << ColumnItem.new("HITTING", ChargingState::HITTING_BONUS_TABLE.map{|x| "+#{x}"}, 60, AL_RIGHT)
			columns << ColumnItem.new("DAMAGE", ChargingState::DAMAGE_RATE_BONUS_TABLE.map{|x| "#{(x * 100).to_i}%"}, 60, AL_RIGHT)
			
			items = @main_window.select_items.clear
			items << SelectItem.new(1, _("一呼吸おく(1)"), SDL::Key::K1)
			items << SelectItem.new(2, _("十分に狙いを定める(2)"), SDL::Key::K2)
			items << SelectItem.new(3, _("精神を統一して引き絞る(3)"), SDL::Key::K3)
			items << SelectItem.new(:cancel, "キャンセル")
			
			if (last = member.last_select_ids[SelectType::Charge]) then
				@main_window.update.set(last).warp
			else
				@main_window.update.reset_index.warp
			end
			$windows = [DUNGEON_WINDOW] + $enemy_windows + [PARTY_WINDOW, ENEMY_LIST_WINDOW, SELECT_WINDOW, NAME_WINDOW, @main_window]
		end
		
		def on_select(id)
			if id == :cancel then
				on_cancel
			else
				Game.current_member.last_select_ids[SelectType::Charge] = id
				Phase.change(ChargingTargetSelectPhase.new(id))
			end
		end
		
		def on_cancel
			Phase.change(BattleMemberCommandFirstPhase.new)
			SELECT_WINDOW.set(:charge)
		end
		
	end
	
	class SharpAttackSelectPhase < Phase
		include BattleMemberCommandPhase
		attr_reader :main_window
		
		def on_enter(from)
			super
			
			member = Game.current_member
			
			@main_window = MultiColumnWindow.new.make_surface(320, 6).centering
			columns = @main_window.columns.clear
			columns << ColumnItem.new("", [], 200)
			columns << ColumnItem.new("DOWN", ABILITY_TYPES.map{|x| ABILITY_CAPTIONS[x]}, 60, AL_LEFT)
			
			items = @main_window.select_items.clear
			items << SelectItem.new(STR, _("筋力を弱らせる(1)"), SDL::Key::K1)
			items << SelectItem.new(TEC, _("手先を震わす(2)"), SDL::Key::K2)
			items << SelectItem.new(AGL, _("動きを鈍らせる(3)"), SDL::Key::K3)
			items << SelectItem.new(WIL, _("集中を乱す(4)"), SDL::Key::K4)
			items << SelectItem.new(PSY, _("力の流れを乱す(5)"), SDL::Key::K5)
			items << SelectItem.new(:cancel, "キャンセル")
			@main_window.update.reset_index.warp
			$windows = [DUNGEON_WINDOW] + $enemy_windows + [PARTY_WINDOW, ENEMY_LIST_WINDOW, SELECT_WINDOW, NAME_WINDOW, @main_window]
		end
		
		def on_select(id)
			if id == :cancel then
				on_cancel
			else
				Game.current_member.last_select_ids[SelectType::SharpAttack] = id
				Phase.change(SharpAttackTargetSelectPhase.new(id))
			end
		end
		
		def on_cancel
			Phase.change(BattleMemberCommandFirstPhase.new)
			SELECT_WINDOW.set(:charge)
		end
		
	end

	
	class PraySelectPhase < Phase
		include BattleMemberCommandPhase
		
		def on_enter(from)
			super

			@main_window = SelectableWindow.new.make_surface(200, 6).centering
			items << SelectItem.new(:spellbreak, '対魔結界')
			items << SelectItem.new(:bluefire, '青の炎')
			items << SelectItem.new(:exorice, '死霊祓い')
			
			DESCRIPTION_WINDOW.show
			@main_window.show
		end
		
		def on_change
			case @main_window.current_id
			when :spellbreak
				DESCRIPTION_WINDOW.update('呪文や魔力による攻撃を防ぐ')
			when :exorice
				DESCRIPTION_WINDOW.update('悪魔・不死者など、魔に属する敵全員にダメージ')
			when :exorice
				DESCRIPTION_WINDOW.update('死霊を消滅させる')
			end
		end
	end
	
	
	
	class AttackTargetSelectPhase < Phase
		include BattleMemberCommandPhase
		include EnemySelectPhase
		include BackablePhase
		
		def on_enter(from)
			super
			
			member = Game.current_member
			unless member.arrows[member.arrow_index] then
				member.arrow_index = 0
			end
			
			DATA_WINDOW.make_surface(200, get_data_texts.size)
			@extra_data_window = DoubleTextWindow.new
			on_change
			DATA_WINDOW.show
			DATA_WINDOW.dock_beside(ENEMY_LIST_WINDOW, :bottom)
			@extra_data_window.dock_beside(DATA_WINDOW, :bottom)
			if Game.current_member.weapon.data.kind_of?(BowModel) then
				HELP_WINDOW.make_surface(DATA_WINDOW.width, 1).update([["←→", _("矢の選択")]])
				HELP_WINDOW.dock_beside(DATA_WINDOW, :bottom).show
			end
			
			WARNING_WINDOW.dock_beside(ENEMY_LIST_WINDOW, :bottom_right).show
			unless member.weapon.long_range then
				ENEMY_LIST_WINDOW.select_items.each do |item|
					if item.id >= FRONT_GROUP_MAX then
						item.disable(_('攻撃が届かない'))
					end
				end
				ENEMY_LIST_WINDOW.update_surface
			end

			ENEMY_LIST_WINDOW.show
		end
		
		def on_select(id)
			decide_action(AttackAction.new(Game.current_member, $troop.groups[id]))
		end
		
		def hide_hp_gauges
			$troop.all_enemies.each{|x| x.window.hp_visible = false}
		end
		
		def on_change
			DATA_WINDOW.update(get_data_texts)
			hide_hp_gauges
			
			if GS.party.find_member(Academian) then
				# HPゲージ表示
				$troop.groups[ENEMY_LIST_WINDOW.current_id].each{|x| x.window.hp_visible = true}
				
				# 耐性情報表示
				member = Game.current_member
				enemy = $troop.groups[ENEMY_LIST_WINDOW.current_id].first
				
				texts = []
				res = enemy.get_damage_resist(member.weapon.damage_types)
				if res != RES_NORMAL then
					if res < RES_NORMAL then
						texts << [_('効果の高い攻撃')]
					elsif res == RES_PERFECT then
						texts << [_('まったく効かない攻撃')]
					elsif res > RES_NORMAL then
						texts << [_('効きにくい攻撃')]
					end
				
					@extra_data_window.make_surface(texts, 1).update.show
					ENEMY_LIST_WINDOW.show
				else
					@extra_data_window.hide
				end
			end
		end
		
		def get_data_texts
			return [] unless ENEMY_LIST_WINDOW.current_id
		
			texts = []
			member = Game.current_member
			enemy = $troop.groups[ENEMY_LIST_WINDOW.current_id].first
			border = get_border(member, enemy)
			rate = Util.success_rate(border) if border
			
			texts << [member.weapon.name, ""]
			if member.weapon.data.kind_of?(BowModel) and member.arrow then
				texts << [member.arrows[member.arrow_index].name, ""]
			elsif Game.current_member.weapon.data.kind_of?(AutoBowModel) then
				texts << [member.bolts.first.name, ""]
			end

			texts << [_("攻撃回数"), get_hitting_number(member)]
			texts << [_("命中率"), "#{rate.round}%"] if border
			if Game.debug_mode? then
				texts << ["", sprintf("(命中%3s:回避%3s)", member.weapon_hitting, enemy.avoid)]
				#if (dice = get_effect_sample.get_clean_hit_check_dice(member, enemy)) then
				#	texts << ["", "(C.Hit #{dice.success_percentage}%)"]
				#end
				
				dice = get_effect_sample.get_damage_dice(member, enemy)
				if dice then
					texts << ["ダメージ予測", "#{dice.expectation_min}～#{dice.expectation_max}"]
					texts << ["", sprintf("(致傷%3s:軽減%3s)", dice.base, dice.reducing)]
				end
			end
			
			return texts
			
		end
		
		def on_leave(to)
			ENEMY_LIST_WINDOW.update
			hide_hp_gauges
			super
		end
		
		
		def on_left_key
			SE.cursor_move
			member = Game.current_member
			member.arrow_index -= 1
			member.arrow_index = member.arrows.size - 1 unless member.arrows[member.arrow_index]
			on_change
		end
		
		def on_right_key
			SE.cursor_move
			member = Game.current_member
			member.arrow_index += 1
			member.arrow_index = 0 unless member.arrows[member.arrow_index]
			on_change
		end
		
		def get_border(member, enemy)
			get_effect_sample.get_hitting_border(member, enemy)
		end
		
		def get_effect_sample
			WeaponAttackEffect.new
		end

		
		def get_hitting_number(member)
			return member.hitting_number
		end
		
	end
	
	class RanpageTargetSelectPhase < AttackTargetSelectPhase
		def get_hitting_number(member)
			member.hitting_number * 2
		end
		
		def on_select(id)
			decide_action(RanpageAction.new(Game.current_member, $troop.groups[id]))
		end

		def get_effect_sample
			RanpageEffect.new
		end
		
	end

	class FeintTargetSelectPhase < AttackTargetSelectPhase
		def on_select(id)
			decide_action(FeintAction.new(Game.current_member, $troop.groups[id]))
		end
		
		def on_enter(from)
			super
			DATA_WINDOW.hide
		end

		def get_effect_sample
			FeintEffect.new
		end
	end

	class SmashTargetSelectPhase < AttackTargetSelectPhase
		def get_hitting_number(member)
			return 1
		end
		def on_select(id)
			decide_action(SmashAction.new(Game.current_member, $troop.groups[id]))
		end

		def get_effect_sample
			SmashEffect.new
		end
	end
	
	

	class ChargingTargetSelectPhase < AttackTargetSelectPhase
		def initialize(charging_level)
			@charging_level = charging_level
		end
		
		def get_effect_sample
			ChargeAttackEffect.new(@charging_level)
		end
	
		def get_hitting_number(member)
			1
		end
		
		
		def get_border(member, enemy)
			return Roll.attack_hit_border(member, enemy) + ChargingState::HITTING_BONUS_TABLE[@charging_level - 1]
		end

		def on_select(id)
			decide_action(ChargingAction.new(Game.current_member, $troop.groups[id], @charging_level))
		end
		
		#def on_cancel
		#	Phase.change(ChargingLevelSelectPhase.new)
		#	$phase.main_window.set(@charging_level)
		#end
	end
	
	class SharpAttackTargetSelectPhase < AttackTargetSelectPhase
		def initialize(ability_type)
			@ability_type = ability_type
		end
		
		def get_effect_sample
			SharpAttackEffect.new(@ability_type)
		end
	
		def get_hitting_number(member)
			get_effect_sample.get_hitting_number(member)
		end
		
		
		def get_border(member, enemy)
			get_effect_sample.get_hitting_border(member, enemy)
		end

		def on_select(id)
			decide_action(SharpAttackAction.new(Game.current_member, $troop.groups[id], @ability_type))
		end
		
		#def on_cancel
		#	Phase.change(ChargingLevelSelectPhase.new)
		#	$phase.main_window.set(@charging_level)
		#end
	end



	
	
	class BattleSpellSelectPhase < SpellSelectPhase
		include BattleMemberCommandPhase
		def initialize(already_trick_selecting = false, default_spell = nil, default_trick = nil)
			@already_trick_selecting = already_trick_selecting
			@default_spell = default_spell
			@default_trick = default_trick
		end
		
		def on_enter(from)
			super
			$windows = [DUNGEON_WINDOW] + $enemy_windows + [PARTY_WINDOW, @trick_window, DESCRIPTION_WINDOW, @spell_window]
			@boost_window = TextWindow.new.make_surface(@trick_window.width).update
			@boost_window.dock_beside(@trick_window, :bottom)
			@boost_window.show
			@spell_window.show

			#@spell_window.set(@default_spell) if @default_spell
			#@trick_window.set(@default_trick) if @default_trick
			#@trick_window.show.regulate_index if @already_trick_selecting
			
			if (trick_id = Game.current_member.last_select_ids[SelectType::Trick]) then
				spell_id = DB.find_trick(trick_id).spell_id
				if @spell_window.select_items.map{|x| x.id}.find{|x| x == spell_id} then
					@spell_window.set(spell_id).warp
					@trick_window.set(trick_id)
					on_change
				end
			end
		end
		
		def update_sequence
			super
			return unless @boost_window
			if Game.current_member.magic_boost? then
				if trick_selecting? then
					id = @trick_window.select_items[@trick_window.index].real_id
					if id then
						@boost_window.update(TRICK_DATA[id].boost_description)
					else
						@boost_window.update("")
					end
				else
					@boost_window.update("")

				end
			end
		end
=begin
		def on_key_press(keycode)
			case keycode
			when SDL::Key::B
				SE.select
				if Game.current_member.magic_boost? then
					Game.current_member.remove_state(MagicBoostState)
				else
					Game.current_member.add_state(MagicBoostState.new)
				end
				Phase.change(BattleSpellSelectPhase.new(trick_selecting?, @spell_window.current_id, @trick_window.current_id))
			end
		end
=end

		def on_select_trick(id)
			Game.current_member.last_select_ids[SelectType::Trick] = id
		
			case DB.find_trick(id).target_type
			when TG_MEMBER
				index = Game.member_select(_('だれに？'))
				if index then
					decide_action(SpellCastAction.new(Game.current_member, [GS.party.members[index]], id))
				else
					@trick_window.show
				end
				
			when TG_PARTY
				if Game.alive_members_select then
					decide_action(SpellCastAction.new(Game.current_member, GS.party.alive_members, id))
				else
					@trick_window.show
				end
				
				
			when TG_ENEMY
				Phase.change(MagicTargetEnemySelectPhase.new(id))
			else
				decide_action(SpellCastAction.new(Game.current_member, GS.party.alive_members, id))
			end
		end

		
		def on_cancel
			if self.trick_selecting? then
				@spell_window.show
				self.on_change
			else
				Phase.change(BattleMemberCommandFirstPhase.new)
			end
			
		end
		
	end

	
	class MagicTargetEnemySelectPhase < Phase
		include BattleMemberCommandPhase
		include EnemySelectPhase
		include BackablePhase
		
		def initialize(trick_symbol)
			@trick_symbol = trick_symbol
		end
		
		def on_enter(from)
			super
			@data_window = DoubleTextWindow.new
			@data_window.make_surface(200, get_data_texts.size)
			on_change
			@data_window.show
			@data_window.dock_beside(ENEMY_LIST_WINDOW, :bottom)

			ENEMY_LIST_WINDOW.show
		end
		
		def on_change
			super
			@data_window.update(get_data_texts)
		end
		

		def get_data_texts
			texts = []
			member = Game.current_member
			
			return [] unless ENEMY_LIST_WINDOW.current_id
			
			enemy = $troop.groups[ENEMY_LIST_WINDOW.current_id].first
			trick = DB.find_trick(@trick_symbol)
			
			texts << [trick.name, ""]

			if trick.effect.kind_of?(AttackEffect) and trick.effect.damaging? then
				texts << [_("攻撃回数"), trick.effect.hitting_number || 1]
				
				border = trick.effect.get_hitting_border(member, enemy)
				texts << [_("命中率"), "#{CheckDice.new(border).success_percentage}%"] if border
				
				if Game.debug_mode? then
					texts << ["", sprintf("(術制御%3s:回避%3s)", member.magic_control, enemy.avoid)]
					#if (dice = trick.effect.get_clean_hit_check_dice(member, enemy)) then
					#	texts << ["", "(C.Hit #{dice.success_percentage}%)"]
					#end
					
					dice = trick.effect.get_damage_dice(member, enemy)
					if dice then
						texts << ["ダメージ"]
						texts << ['', dice.to_s]
						texts << ["", sprintf("(致傷%3s:軽減%3s)", dice.base, dice.reducing)]
					end
				end
			end
			
			return texts
			
		end

				
		def on_select(id)
			enemies = $troop.groups[id]
			raise unless enemies
			decide_action(SpellCastAction.new(Game.current_member, enemies, @trick_symbol))
		end
		
		
	end
	
	
	class BattleRoundPhase < Phase
		def initialize(party_escape_trying = false)
			@party_escape_trying = party_escape_trying
		end
	
		def on_enter(from)
			ENEMY_LIST_WINDOW.hide
		
			# 仲間のAI行動確定
			GS.party.members.each do |member|
				if member.ai_act? then
					member.set_ai_action
				end
			end
			
			# 敵の行動確定
			if not $battle.troop_escape_failured or $battle.round != 1 then
				$troop.groups.each do |group|
					group.each do |enemy|
						enemy.set_ai_action
					end
				end
			end
			
			if @party_escape_trying then
				$troop.all_enemies.each do |enemy|
					# 一定確率で行動をキャンセル
					if rand(100) < 25 then
						enemy.clear_action
						LOGGER.puts "\t逃走により#{enemy.name}の行動がキャンセルされました"
					end
				end
			end
			
			# アップキープ
			LOGGER.puts "[アップキープ]"
			$battle.on_round_start
			$battle.characters.each do |chara|
				chara.status.each do |state|
					LOGGER.puts("#{chara.name}:#{state.name || state.class.to_s} アップキープ処理")
					msg = catch(:continue){ state.on_round_start(chara) }
					PARTY_WINDOW.update
					message(msg) if msg
					chara.update_last_parameters
				end
			end
			
			# 祈る僧がいなければprayingフラグオフ（祈るメッセージ非表示処理のため）
			unless GS.party.alive_members.find{|x| x.action.kind_of?(PrayAction)} then
				$praying = false
			end
			
			LOGGER.puts "[メイン]"
			# 行動順確定
			$battle.actions = $battle.characters.map{|x| x.action}.compact
			
			#$battle.character_order.delete_if{|x| x.action.nil? || x.kind_of?(Prayer) || x.guarding? || x.blocking?}
			$battle.actions.sort!{|x, y| x.real_speed <=> y.real_speed}
			$battle.actions.reverse!
			LOGGER.puts "行動順確定"
			$battle.actions.each do |action|
				case action
				when QuickAction
					LOGGER.puts "\t#{action.actor.name} - #{action.caption} (quick)"
				when DelayedAction
					LOGGER.puts "\t#{action.actor.name} - #{action.caption} (delayed)"
				else
					LOGGER.puts "\t#{action.actor.name} - #{action.caption} (speed:#{action.speed})"
				end
				$battle.last_round_reserved_actions << action
			end
			
			$windows = [DUNGEON_WINDOW, PARTY_WINDOW] + $enemy_windows	
			PARTY_WINDOW.update
			

			
			GC.start
			
			# 各キャラの行動
			until $battle.actions.empty? do

				self.operate_action
				
				# 勝利チェック
				if $battle.win? then
					Phase.change(BattleResultPhase.new(BR_WIN))
					return
				end
	
				# 敗北チェック
				if $battle.lose? then
					Phase.change(WipeoutPhase.new)
					return
				end


			end
			
			$battle.on_round_end

			PARTY_WINDOW.update

			
			Phase.change(BattleCommandPhase.new)

		end
		
		def operate_action
			$battle.characters.each{|x| x.update_last_parameters}
			$current_action = $battle.actions.shift
			$current_action.actor.finish_action
			
			#MEMO: ここでのupdateは必要ないかも
			$troop.update
			PARTY_WINDOW.update

			
			if $current_action then
				
				$battle.last_action = $current_action
				msg = $current_action.operate
				PARTY_WINDOW.update
	
				if msg then
					Game.message(msg){|window|
						window.top = 16
					}
				end
				

				$troop.update
	
				ENEMY_LIST_WINDOW.update
				$enemy_windows.each{|x| x.update}
				
				# 行動履歴に記録
				$battle.last_round_operated_actions << $current_action

				
				# 行動順を再計算
				$battle.actions.sort!{|x, y| x.real_speed <=> y.real_speed}
				$battle.actions.reverse!
				

			end
		end
		
		
	end
	
	class BattleResultPhase < Phase
		def initialize(result)
			@result = result
		end
	
		def on_enter(from)
		
			total_exp = total_exp_base = ($battle.total_exp * GS.rule.enemy_exp_rate * (@result == BR_WIPEOUT ? 2.0 : 1.0)).to_i
			if $battle.number_bonus_rate then
				total_exp = (total_exp_base * (1.00 + $battle.number_bonus_rate)).to_i
			end
			
			startings = $battle.starting_members
			alives = GS.party.alive_members
			
			exp = (total_exp.to_f / startings.size).round
			exp_base = (total_exp_base.to_f / startings.size).round
			gold = ($battle.total_gold * GS.rule.enemy_gold_rate / startings.size).round
			
			if (not @result == BR_WIN) and (exp == 0 and gold == 0) then
				Phase.change(BattleEndPhase.new(@result))
				return
			end

			
			LOGGER.puts
			if $battle.number_bonus_rate then
				LOGGER.puts "敵数ボーナス: +#{($battle.number_bonus_rate * 100).to_i}%"
			end
			LOGGER.puts "獲得経験値:(#{total_exp_base} + #{total_exp - total_exp_base}) / #{startings.size} = #{exp}"
			LOGGER.puts "獲得金貨:#{$battle.total_gold} / #{startings.size} = #{gold}"

			startings.each do |member|
				member.get_exp(exp)
				member.get_gold(gold)
				GS.player_profiles[PPT::GotGoldFromEnemy] += gold
				Game.increment_player_record(PRT::GotExp, member.uuid, exp)
				Game.increment_player_record(PRT::GotGold, PPT::GotGoldFromEnemy, gold)
				member.profiles[MPT::Win] += 1
			end
			(GS.party.members - startings).each do |member|
				# last_gotの初期化
				member.get_exp(0)
				member.get_gold(0)
			end
			
			GS.player_profiles[PPT::Win] += 1

			BGM.fade_out
			
			#DESCRIPTION_WINDOW.set_position(:center, 16).update("#{GS.party.name}は敵を撃退した！")
			@caption_window = TextWindow.new
			@caption_window.text = _('戦闘メンバーは以下のものを獲得')
			@caption_window.align = AL_CENTER
			@caption_window.set_good_width
			@caption_window.make_surface(nil, 1).update
			@exp_window = DoubleTextWindow.new
			texts = [[_("経験値"), exp.to_s]]
			if exp > exp_base then
				texts << ['  (' + _('基礎値'), exp_base.to_s + ")"]
				texts << ['  (' + _('敵数ボーナス'), "+#{exp - exp_base})"]
			end
			@exp_window.make_surface(200, texts.size).update(texts)
			@gold_window = DoubleTextWindow.new.make_surface(200, 1)
			@gold_window.texts = [[_("金品"), gold.to_s]]
			@gold_window.update
			
			#@gold_window.update.dock_beside(@exp_window, :right)
			#@gold_window.top = @exp_window.top = 64
			@caption_window.centering; @exp_window.centering; @gold_window.centering
			Window.centering_y([@caption_window, @exp_window, @gold_window])
			$windows = [PARTY_WINDOW, DUNGEON_WINDOW, @caption_window, @exp_window, @gold_window]
			PARTY_WINDOW.update
			
		end
		
		def on_leave(to)
			@exp_window = nil
			@gold_window = nil
		end
		
		def on_enter_key
			Phase.change(BattleEndPhase.new(@result))
		end
	end
	

	class BattleEndPhase < Phase
		def initialize(result)
			@result = result
		end
	
		def on_enter(from)
			GS.party.members.each{|x| x.action = nil}
			$enemy_windows.clear
			
			troop_driven_out = (@result == BR_WIN or @result == BR_TROOP_ESCAPE)
			
			if troop_driven_out then
				i = GS.room_troops[GS.party.floor_id].index($troop)
				GS.room_troops[GS.party.floor_id][i] = nil if i
			else
				GS.party.back
			end
			GS.party.members.each do |member|
				member.added_status.delete_if{|x| x.battle_only?}
			end
			Game.save(FQ_BIG_CHANGE, "戦闘終了", true)
			Game.reporter.on_battle_end(@result)

			if troop_driven_out	and (treasure_box = GS.party.viewable_treasure_box) then
				Game.challange_treasure(treasure_box)
			end
			
			throw(:exit_operation_loop, troop_driven_out)
		end
	end

	class WipeoutPhase < Phase
		def on_enter(from)
			
			BGM.fade_out
			message(_("%{party}の意識が闇に飲み込まれていく……").evaluate(:party => GS.party.name))
			if $troop and ($troop.kind_of?(RoomTroop) or $troop.kind_of?(BossTroop)) then
				GS.party.back
			end

			GS.player_profiles[PPT::Wipeout] += 1
			

			Game.save(FQ_BIG_CHANGE, "全滅", true)
			if $section == Section::BATTLE then
				Phase.change(BattleResultPhase.new(BR_WIPEOUT))
			else
				GS.change_to_new_party
				Phase.change(TownMenuPhase.new)
			end

			
				
			
		end
	end

end