	#　ステータスクラス

module DarkHall

	TG_MEMBER = :member
	TG_PARTY = :party
	TG_ENEMY = :enemy
	TG_NONE = :none

	class Effect
	
		bool_attr_accessor :camp_usable, :battle_usable, :town_usable
		attr_accessor :fast
		attr_accessor :messages, :self_use_messages

		def initialize(parameters = {})
			init_params
			return unless parameters
			parameters.each_pair do |key, value|
				instance_variable_set("@#{key.to_s}", value)
			end
		end
		
		def init_params
			@messages = []
			@self_use_messages = []
			@fast = false
			init_usability(false, false, false)
		end	

		
		
		def init_usability(town, camp, battle)
			@town_usable = town
			@camp_usable = camp
			@battle_usable = battle
			return self
		end
		
		def get_message(actor, targets)
			if not @self_use_messages.empty? and (targets == [actor] or targets.nil?) then
				msgs = @self_use_messages
			else
				msgs = @messages
			end
		
			return Message.new if msgs.empty?
			msg = Util.random_pick(msgs)
			body = Util.eval_text(msg, {:actor => (actor ? actor.name : nil), :target => self.target_name(targets)})
			return Message.new(body)
		end
		
		# obsolete
		def target_name(targets)
			Util.targets_caption(targets)
		end
		
		def target_type
			return TG_NONE
		end
		
		
		def operate(actor, targets = nil, base_msg = nil)
			raise "actor and targets are both nil. (must be not nil)" if actor.nil? and targets.nil?
			
			# actorがnilの場合は、自動的にtargetsのうち一体をダミーとする
			if actor.nil? then
				actor = targets.first
			end
		end

	end
	
	
	
	class SpecialEffect < Effect
		attr_accessor :proc
		def init_params
			super
			@proc = nil
		end
		
		def operate(actor, targets = nil, base_msg = nil)
			super
			re = catch(:continue){
				proc.call(actor)
			}
			
			return(base_msg || get_message(actor, targets))
		end
	end

	# 対象メンバーを違う場所へすっ飛ばす
	class MemberTereportEffect < Effect
		def init_params
			super
			init_usability(false, true, true)
		end
		
		def operate(actor, members, base_msg = nil)
			super
			msg = (base_msg || get_message(actor, members))
			
			points = GS.party.floor.tereport_points
			if points.empty? then
				msg << _('しかし何も起きなかった')
			else
				new_party = Party.new			
				point = points[rand(points.size)]
				new_party.x = point[0]
				new_party.y = point[1]
				new_party.floor_id = GS.party.floor_id
				GS.parties << new_party
				
				members.each do |member|
					GS.party.leave_member(GS.members.index(member))
					new_party.join_member(GS.members.index(member))
					msg << _('%{target}はダンジョン内のどこかへ転送された！').evaluate(:target => member.name)
				end

				
				if GS.party.members.empty? then
					new_party = GS.parties.last
					GS.parties.delete(GS.current_party)
					GS.current_party_id = GS.parties.index(new_party)
				end
				
				PARTY_WINDOW.update
				DUNGEON_WINDOW.update
			end
			
			return msg
		end
	end
	
	class PartyTereportEffect < Effect
		def init_params
			super
			init_usability(false, true, true)
		end
		
		def target_type
			TG_PARTY
		end
		
		def operate(actor, dummy_members, base_msg = nil)
			super
			msgs = []
			msgs << (base_msg || get_message(actor, members))
			
			if (points = GS.party.floor.tereport_points).empty? then
			else
				point = Util.random_pick(GS.party.floor.tereport_points)
				GS.party.x = point[0]
				GS.party.y = point[1]
			
				PARTY_WINDOW.update
				DUNGEON_WINDOW.update
			end
			
			return msgs
		end
	end
	
	
	class EnemyCallEffect < Effect
		attr_accessor :enemy_id
		def init_params
			super
			init_usability(false, false, true)
			@enemy_id = 'SmallVine'
		end
		
		def operate(actor, dummy, base_msg = nil)
			super
			msg = _("%{actor}は仲間を呼んだ！\n\n遠くから敵が近づいてくる気配がする……！")
			$battle.called_enemy_ids << @enemy_id
			
			return Util.eval_text(msg, :actor => actor.name)
		end
	end


	
	# 状態異常を与える
	# AttackEffectと違い、対象が複数でもメッセージは一度しか表示されない
	class EnhanceEffect < Effect
		attr_accessor :state_data
		bool_attr_accessor :magic
		
		def init_params
			super
			@state_data = []
			@magic = false
		end
		
		def operate(actor, targets, base_msg = nil)
			super
			re = []
			base_msg ||= get_message(actor, targets)
			text_params = {:actor => actor.name, :targets => Util.targets_caption(targets)}

				
			if magic? and targets.find{|x| x.find_state(ElementalProtectionState)} and
			rand(100) < 80 then
				return(base_msg + [_("しかし呪文の効果は祈りによって打ち消された")])
			end
			
			
			@state_data.each do |state_class, level, border_base|
				if state_class == CurseState && $battle.praying? then
					return(base_msg + Util.eval_text(_('呪いは祈りによって打ち消された'), text_params))
				end
				
				case level
				when :magic_power
					level = actor.magic_power
				when :magic_control # 術制御比例
					level = actor.magic_control
				end
				state = state_class.new(level.to_i)
				LOGGER.puts "\t#{state.name} (Lv#{state.level})"
				
				added_characters = []
				targets.each do |target|
					# 死亡していればスキップ
					next if target.dead?

					LOGGER.puts "\t→#{target.name}"

					border = border_base
					res = target.get_state_resist(state_class)
					border += RES_STATE_BORDER_BONUS_TABLE[res] if border
					
					if border then
						if border <= 0 then
							suc = false
							LOGGER.puts "\t\t絶対失敗"

						else
							dice = CheckDice.new(border)
							suc = dice.roll
							LOGGER.puts "\t\t成功率#{dice.success_percentage}% (目標値:#{dice.border}) - #{suc ? '成功' : '失敗'}"
						end
					else
						suc = true
						LOGGER.puts "\t\t絶対成功"
					end
					
					if suc and target.add_state(state) then
						added_characters << target
					end
				end
				
				if border_base then
					if targets.first.kind_of?(Enemy) then
						# 敵グループを対象としている場合は、成否メッセージをまとめて表示
						if added_characters.empty? then
							re << (base_msg + [_('%{target}には効果がなかった').evaluate(:target => Util.targets_caption(targets))])
						else
							re << (base_msg + [state.get_some_of_enemy_group_added_message(targets, added_characters.size)])
						end
					else
						# パーティーメンバーを対象としている場合は、一人ずつ成否を表示
						re << Message.new(base_msg.lines.dup)
						targets.each do |tg|
							# 死亡していればスキップ
							next if tg.dead?
						
							if tg.in?(added_characters) then
								re.last << state.get_added_message(tg)
							else
								re.last << _('%{target}には効果がなかった').evaluate(:target => tg.name)
							end
							
							# 6行以上になっていれば分割
							if re.last.lines.size > 5 then
								old = re.pop
								new_1 = Message.new(old.lines.slice!(0...5))
								new_2 = base_msg + Message.new(old.lines)
								re << new_1 << new_2
							end
						end
					end
				else
					# 絶対成功ならまとめて表示
					re << (base_msg + [state.get_group_added_message(targets)])
				end
				
			end
			
			re

			
				
		end
	end
	
	class PartyEnhanceEffect < EnhanceEffect
		def init_params
			super
			init_usability(false, true, true)
		end
		
		def target_type
			TG_PARTY
		end
		
		def operate(actor, dummy = nil, base_msg = nil)
			super(actor, GS.party.alive_members, base_msg)
		end
	end

	
	class EnemyGroupEnhanceEffect < EnhanceEffect
		def init_params
			super
			init_usability(false, false, true)
		end	
		
		def target_type
			TG_ENEMY
		end
	end
	
	
	# ダメージや状態異常を与える
	class AttackEffect < Effect
		attr_accessor :fixed_damage
		attr_accessor :damage_rate
		attr_accessor :use_abilities
		attr_accessor :fixed_damage
		attr_accessor :through_defense
		attr_accessor :shield_guardable
		attr_accessor :hitting_number
		attr_accessor :hitting_border_base
		attr_accessor :hitting_type
		attr_accessor :damage_types
		attr_accessor :state_data
		attr_accessor :ghost_only
		
		def init_params
			super
			init_usability(false, false, true)
			@fixed_damage = nil
			@damage_rate = nil
			@use_abilities = []
			@through_defense = false
			@damage_types = []
			@shield_guardable = true
			@hitting_number = nil
			@hitting_border_base = nil
			@hitting_type = nil
			@state_data = []
			@ghost_only = false
		end
		
				
		
		def operate(actor, targets, base_msg = nil)
			super
			actor ||= targets.first
			messages = []
			base_msg ||= get_message(actor, targets)
			text_params = {:actor => actor.name}
			
			LOGGER.puts "\t攻撃力: #{get_attack(actor)}"

			targets.each do |target|
				LOGGER.puts("\t→#{target.name}")
				text_params[:target] = target.name
				downside_lines = []
				
				# 死亡していればスキップ
				next if target.dead?
			
			
				# クリーンヒットロール
				clean = check_clean_hit(actor, target)
				
				
				# クリーンヒットのメッセージ表示と、命中回数の計算
				damage_messages = []
				if clean and damaging? then
					damage_messages << Util.eval_text(_('クリーンヒット！'), text_params)

					LOGGER.puts("\t\tクリーンヒット")
					hit_number = calc_hit_number(actor, target, true)
				else
					hit_number = calc_hit_number(actor, target)
				end
				
				# 属性メッセージ
				rate = get_damage_resist_rate(actor, target)
				#if rate > 1.0 then
				#	damage_messages << 'よく効いているようだ！'
				#elsif rate < 1.0
				#	damage_messages << 'あまり効きが良くないようだ…' 
				#end
				
				
				# 命中回数0回のときの処理
				if hit_number == 0 then
					downside_lines.clear
					
					if target.kind_of?(Grappler) and actor.forward? and self.kind_of?(WeaponAttackEffect) then
						downside_lines << Util.eval_text(_('%{target}は攻撃を素早くいなした！'), text_params)
						$battle.actions.unshift(CounterAttackAction.new(target, actor))
					else
						downside_lines << Util.eval_text(_('%{target}には命中しなかった'), text_params)
					end
					
					#messages << (base_msg + downside_lines)
					Game.message(base_msg + downside_lines)
					LOGGER.puts("\t\t#{target.name}には命中しなかった")
					
					next # 命中しなかった場合は盾防御・状態異常などの判定をスキップ
				end


				# クリティカルヒット
				if actor.arrow and actor.arrow.data_id == 'PoisonArrow' and not target.critical_guard? then
					target.kill
					downside_lines << Util.eval_text(_('毒矢が急所を撃ち抜いた！'), text_params)
					downside_lines << Util.eval_text(_('%{target}は力尽きた……'), text_params)
					LOGGER.puts("\t\tクリティカルヒット")
					msg = base_msg + downside_lines
					msg.effect_type = Message::Effect::ENEMY_DAMAGE
					msg.clean_hit = true
					msg.target_window = target.window
					Game.message(msg)
					next 
				end

				
				# 耐性・クリーンヒットのメッセージはまとめて表示
				unless damage_messages.empty? then
					downside_lines << damage_messages.join("　")
				end
				
				# 無効化処理
				protector = target.protection_check(get_damage_types(actor))
				if protector then
					downside_lines.clear
					text_params[:protector] = protector
					downside_lines << Util.eval_text(_('%{target}の%{protector}が攻撃を防いだ！'), text_params)
					
					#messages << (base_msg + downside_lines)
					Game.message(base_msg + downside_lines)
					LOGGER.puts("\t\t#{target.name}のプロテクション（#{protector}）が発動")
					
					next
				end
				
				# 対霊体処理
				if @ghost_only and not target.ghost_body? then
					downside_lines << Util.eval_text(_('%{target}には効果がなかった'), text_params) if downside_lines.empty?
					Game.message(base_msg + downside_lines)
					
					next
				end
				
				# 盾の判定（クリーンヒット時は無視）
				shield_guard = false
				if not clean and damaging? and @shield_guardable and target.shield_usable? and
				(shield_guard = check_shield_guard(actor, target)) then
					text_params[:shield] = target.shield.data.name
					
					# パーフェクトガード発生判定
					border = target.perfect_guard_border
					if border and CheckDice.new(border).roll then
						downside_lines << Util.eval_text(_('完璧な防御！'), text_params)
						downside_lines << Util.eval_text(_('%{shield}が攻撃を受け止めた！'), text_params)
						msg = base_msg + downside_lines
						if target.kind_of?(Member) then
							msg.effect_type = Message::Effect::MEMBER_DAMAGE
						else
							msg.effect_type = Message::Effect::ENEMY_DAMAGE
							msg.target_window = target.window
						end
						msg.perfect_guard = true
						Game.message(msg)
						next
					else
						downside_lines << Util.eval_text(_('%{shield}が攻撃を受け止めた！'), text_params)
						target.on_use_shield
					end
				end

				# 特殊状態による追加防護力
				guards = []
				target.status.each do |state|
					if state.protect_targets.find{|x| get_damage_types(actor).include?(x)} then
						guards << state
						messages << state.get_guard_message(target)
						LOGGER.puts("\t\t#{state.name}により防護+#{state.extra_defense}")
					end
				end
				
				extra_defense = 0
				guards.each{|x| extra_defense += x.extra_defense}
				dp = get_defense(target, shield_guard, extra_defense)
				LOGGER.puts("\t\t防護力: #{dp} (軽減=#{Calc.def2red(dp)})")


				
				# ダメージ
				#value = 0
				#buf = []
				
				
				#(hit_number || 1).times do |i|
				#	dmg = calc_damage(actor, target, clean, shield_guard, extra_defense)
				#	buf << dmg
				#	value += dmg
				#end
				
				damage_list = calc_damage(actor, target, (hit_number || 1), clean, shield_guard, extra_defense)
				
				if damage_list then
					value = damage_list.total
					LOGGER.puts "\t\tダメージ: #{damage_list.join(' + ')}"
					
					target.damage(value)
					if actor.kind_of?(Member) then
						if target.dead? then
							actor.profiles[MPT::Kill] += 1
							Game.increment_player_record(PRT::EnemyKill, target.data_id)
						end
					end
					
					text_params[:value] = value
					if hit_number then
						text_params[:hit] = hit_number
						downside_lines << Util.eval_text(_('%{target}に%{hit}回命中し、%{value}のダメージ'), text_params)
					else
						downside_lines << Util.eval_text(_('%{target}に%{value}のダメージ'), text_params)
					end
					
					
					# 重傷＆死亡メッセージ
					if target.dead? then
						downside_lines << Util.eval_text(_('%{target}は力尽きた……'), text_params)
					elsif target.deadly? then
						downside_lines << Util.eval_text(_('%{target}は倒れそうになるのを堪えた'), text_params)
					end
					
					# 怯み
					if target.alive? && clean then
						target.finish_action
						downside_lines << Util.eval_text(_('%{target}はバランスを崩した'), text_params)
					end
					
					# 状態異常チェック
					if target.alive? then
						target.status.each do |state|
							downside_lines << state.on_damaged(target, value)
						end
					end
				else
					value = 0
					LOGGER.puts "\t\tダメージ0"
				end

				
				# 状態異常付加
				status = target.status
				# @state_data.each do |state_class, |
				
				@state_data.each do |state_class, level, border|
					if state_class == CurseState && target.find_state(ElementalProtectionState) then
						downside_lines << Util.eval_text(_('%{target}への呪いは祈りによって打ち消された').evaluate(text_params), text_params)
						next
					end
					
					case level
					when :magic_power
						level = actor.magic_power
					when :magic_control # 術制御比例
						level = actor.magic_control
					end
					state = state_class.new(level.to_i)
					
					res = target.get_state_resist(state_class)
					border += RES_STATE_BORDER_BONUS_TABLE[res] if border
					if border.nil? then
						suc = true
						LOGGER.puts("\t\t#{state.name} : 絶対成功")
					elsif border <= 0 then
						suc = false
						LOGGER.puts("\t\t#{state.name} : 絶対失敗")
						
					else
						dice = CheckDice.new(border)
						LOGGER.puts("\t\t#{state.name} : 成功率=#{dice.success_percentage}%")
						suc = dice.roll
					end

					if suc and target.add_state(state) then
						downside_lines << state.get_added_message(target) if target.alive?
						LOGGER.puts("\t\t成功 (Lv#{state.level})")
					else
						LOGGER.puts("\t\t失敗")
					end
					
				end
				
				if downside_lines.empty? then
					downside_lines << Util.eval_text(_('%{target}には効果がなかった'), text_params)
				end
				
				msg = base_msg + downside_lines
				if damaging? then
					if target.kind_of?(Member) then
						msg.effect_type = Message::Effect::MEMBER_DAMAGE
					else
						msg.effect_type = Message::Effect::ENEMY_DAMAGE
						msg.target_window = target.window
					end
					
					
					if value == 0 then
						msg.perfect_guard = true
					else
						msg.clean_hit = clean
						msg.shield_guard = shield_guard
					end
				end
				
				PARTY_WINDOW.update
				Game.message(msg)
				
				#messages << msg

			end
			
			
			
			return messages

		end
		
		def damaging?
			@fixed_damage or @damage_rate
		end
		
		
		def get_attack(actor)
			re = 0
			
			if @fixed_damage then
				re += @fixed_damage
			end
			
			if @damage_rate then
				abl = 0
				@use_abilities.each do |x|
					abl += actor.get_ability(x)
				end
				re += (abl * @damage_rate / @use_abilities.size).to_i
			end
			
			re
		end
		
		def get_defense(target, shield_guard = false, extra_defense = 0)
			if @through_defense then
				extra_defense
			elsif shield_guard then
				target.defense + target.shield.extra_defense + extra_defense
			else
				target.defense + extra_defense
			end
		end
		
		# ダメージ計算
		def calc_damage(actor, target, hit_number, clean_hit = false, shield_guard = false, extra_defense = 0)
			if damaging? then
				re = []
				dice = get_damage_dice(actor, target, clean_hit, shield_guard, extra_defense)
				
				LOGGER.puts "\t\tダメージダイス: #{dice.to_s}"
				
				hit_number.times do
					re << dice.roll
				end
				
				rate = get_damage_resist_rate(actor, target)
				unless rate == 1.0 then
					re.map!{|x| x *= rate}
					LOGGER.puts "\t\t属性によりダメージ#{rate}倍" 
				end
				
				if target.guarding? || target.blocking? then
					re.map!{|x| x *= 0.7}
					LOGGER.puts "\t\t防御状態のためダメージ0.7倍"
				end
				
				re.map!{|x|	(x > 0 ? x.to_i : 0)}
				return re
			else
				return nil
			end
		end
		
		# 属性耐性による倍率
		def get_damage_resist_rate(actor, target)
			res = target.get_damage_resist(self.get_damage_types(actor))
			return RES_DAMAGE_RATE_TABLE[res]
		end
		
		
		def get_damage_types(actor)
			@damage_types
		end
		

		# 外れたなら0、命中したならその命中回数、回数が問題にならない成功ならnil
		def calc_hit_number(actor, target, clean_hit = false)
			border = get_hitting_border(actor, target)
			
			# 対霊体処理（攻撃が非常に当たりにくい）
			if border and check_ghost_body_effect(actor, target) then
				LOGGER.puts "\t\t霊体に対しての攻撃は当たりにくい"
				border = 25
			end
			
			if border then
				case @hitting_type
				when :weapon_hitting
					LOGGER.puts "\t\t命中目標値=#{border} (命中#{actor.weapon_hitting} : 回避#{target.avoid})"
				when :magic_control
					LOGGER.puts "\t\t命中目標値=#{border} (術命中#{actor.magic_control} : 回避#{target.avoid})"
				else
					LOGGER.puts "\t\t命中目標値=#{border} (定値)"
				end
			end


			dice = CheckDice.new(border)
			
			hitting_number = get_hitting_number(actor)

		
			# 攻撃回数が設定されているか？
			if hitting_number then
				# 命中判定(border=nil、クリーンヒット時、対象が行動できないときは絶対成功)
				if border.nil? or clean_hit or not target.active? then
					hit_number = hitting_number
					LOGGER.puts "\t\t絶対命中 : #{hitting_number}回攻撃"
				else
					hit_number = 0
					hitting_number.times do
						hit_number += 1 if dice.roll
					end
					
					LOGGER.puts "\t\t命中率#{dice.success_percentage}% : #{hitting_number}回攻撃 : #{hit_number}回命中"
				end

			else
				# 成功判定(border=nilは絶対成功)
				if border.nil? then
					hit_number = nil
					LOGGER.puts "\t\t絶対成功"

				elsif dice.roll then
					hit_number = nil
					LOGGER.puts "\t\t命中率#{dice.success_percentage}% : 成功"

				else
					hit_number = 0
					LOGGER.puts "\t\t命中率#{dice.success_percentage}% : 失敗"

				end
			end
			
			return hit_number

		end
		
		def get_hitting_border(actor, target)
			if @hitting_border_base then
				re = @hitting_border_base
				case @hitting_type
				when :weapon_hitting
					re += actor.weapon_hitting
					re -= target.avoid
				when :magic_control
					re += actor.magic_control
					re -= target.avoid
				end
			else
				re = nil
			end
			
			re
		end
		
		def get_hitting_number(actor)
			@hitting_number
		end
		
		def check_ghost_body_effect(actor, target)
			if target.ghost_body? and !(GS.party.prayer) then
				return true
			end
			
			return false
		end
		
		def check_clean_hit(actor, target)
			dice = get_clean_hit_check_dice(actor, target)

			if dice then
				
				if dice.roll then
					LOGGER.puts "\t\tクリーンヒット率 #{dice.success_percentage}% => 発動！"
					return true
				else
					LOGGER.puts "\t\tクリーンヒット率 #{dice.success_percentage}% => 通常命中"
					return false
				end
			else
				return false
			end
		end

		def check_shield_guard(actor, target)
			
			if target.shield_usable? then
				if target.action.kind_of?(GuardAction)
					LOGGER.puts "\t\t盾：#{target.shield.name} (ガード状態/100%) => 成功！ 防護力+#{target.shield.extra_defense}"
					return true  # ガード中は絶対成功
				else
				
					dice = get_shield_check_dice(actor, target)
					if dice.roll then
						LOGGER.puts "\t\t盾:#{target.shield.name} (#{dice.success_percentage}%) => 成功！ 防護力+#{target.shield.extra_defense}"
						return true
					else
						LOGGER.puts "\t\t盾:#{target.shield.name} (#{dice.success_percentage}%) => 失敗"
						return false
					end
				end
			else
				return false
			end
		end
		
		def get_clean_hit_check_dice(actor, target)
			res = target.get_damage_resist(get_damage_types(actor))
			border = RES_CLEAN_HIT_BORDER_TABLE[res]
			if border then
				border += ((actor.tec - target.agl) / 2).to_i
				border += actor.clean_hitting_bonus
				dice = CheckDice.new(border)
				return dice
			else
				return nil
			end
		end
		
		def get_shield_check_dice(actor, target)
			border = target.shield.guard_border
			border -= ((actor.tec - target.tec) / 2).to_i if actor
			if target.respond_to?(:get_shield_mastery) then
				mastery = target.get_shield_mastery
				border += (mastery * 0.05).to_i
				border += 3 if mastery >= 100.0
			end
			return CheckDice.new(border)
		end
		
		def get_damage_dice(actor, target, clean_hit = false, shield_guard = false, extra_defense = 0)
			base = get_attack(actor)
			if base then
				red = Calc.def2red(get_defense(target, shield_guard, extra_defense))
				
				return DoubleDice.new(base, red, get_balance(actor, clean_hit))
			else
				return nil
			end
		end
		
		def get_balance(actor, clean_hit = false)
			(clean_hit ? 0.9 : 0.5)
		end
		
	end
	
	class SingleAttackEffect < AttackEffect
		def target_type
			TG_ENEMY
		end
		
		def operate(actor, targets, base_msg = nil)
			super(actor, [targets.first], base_msg)
		end
	end
	
	class StateDamageEffect < AttackEffect
		def init_params
			super
			@through_defense = true
			@shield_guardable = false
		end
		
	end
	
	
	class GroupAttackEffect < AttackEffect
		def target_type
			TG_ENEMY
		end
	end
	
	class WeaponAttackEffect < AttackEffect
		
		def init_params
			super
			@damage_rate = 1.0
			@hitting_border_base = 50
			@hitting_type = :weapon_hitting
			@grouping = false
		end
		
		def target_type
			return TG_ENEMY
		end
		
		def operate(actor, targets, base_msg = nil)
			
			if @grouping then
				real_targets = targets
			else
				real_targets =  [targets.first]
			end
			re = super(actor, real_targets, base_msg)
			actor.on_use_weapon(actor.hitting_number, real_targets)
			
			re
		end
		
		#def get_message(actor, targets)
		#	if actor.find_state(HidingState) then
		#		msg = actor.weapon.get_sneak_attack_message
		#	else
		#		msg = actor.weapon.get_attack_message
		#	end
		#	
		#	return Message.new(eval_text(msg, :actor => actor.name, :target => self.target_name(targets)))
		#end


	
		def get_attack(actor)
			atk = attack_bonus(actor, @damage_rate)
			atk += @fixed_damage if @fixed_damage
			
			if actor.weapon.data.kind_of?(BowModel) and actor.arrow then
				atk *= actor.arrow.damage_rate
			end
			return atk
		end
		
		def get_damage_types(actor)
			actor.weapon.damage_types
		end
		
		def get_hitting_number(actor)
			actor.hitting_number
		end
				
		def attack_bonus(actor, rate)
			(actor.weapon_power * rate).to_i
		end
		
		
		def use_skill(actor)
			if defined?(actor.weapon_mastery) then
				symbol = actor.weapon.data_id
				if actor.masterable?(actor.weapon) then
					actor.weapon_mastery[symbol] ||= 0.0
					actor.weapon_mastery[symbol] += 0.2
					LOGGER.log(UseWeaponLog, actor, 0.2)
				end
			end
		end

		def check_ghost_body_effect(actor, target)
			if actor.weapon.ghost_slayer? then
				return false
			else
				super
			end
		end

		
		
	end
	
	class RanpageEffect < WeaponAttackEffect
		def get_hitting_number(actor)
			super * 2
		end
	end
	
	class DoubleRanpageEffect < WeaponAttackEffect
		def init_params
			super
			@grouping = true
		end
	end

	
	class FeintEffect < SingleAttackEffect
		def init_params
			super
			@state_data << [FeintState, nil, nil]
		end
	end


	class SmashEffect < WeaponAttackEffect
		def init_params
			super
			@state_data << [SmashedState, nil, 60]
		end
		
		def get_hitting_number(actor)
			1
		end
		
		#def get_message(actor, targets)
		#	msg = actor.weapon.get_smash_message
		#	return eval_text(msg, :actor => actor.name, :target => self.target_name(targets))
		#end
		
		def get_attack(actor)
			(super * (1.2 + 0.2 * (actor.hitting_number - 1))).to_i
		end
	end
	
	class CounterAttackEffect < WeaponAttackEffect
		
		def get_hitting_number(actor)
			1
		end
		
		#def get_message(actor, targets)
		#	msg = actor.weapon.get_smash_message
		#	return eval_text(msg, :actor => actor.name, :target => self.target_name(targets))
		#end
		
		def get_attack(actor)
			(super * 2.0).to_i
		end
		
		def get_clean_hit_check_dice(actor, target)
			CheckDice.new(999)
		end
	end

	
	class ChargeAttackEffect < WeaponAttackEffect
		def initialize(level, params = {})
			super(params)
			@level = level
		end
		
		def get_attack(actor)
			(super * ChargingState::DAMAGE_RATE_BONUS_TABLE[@level - 1]).to_i
		end
		
		def get_hitting_border(actor, target)
			super + ChargingState::HITTING_BONUS_TABLE[@level - 1]
		end

	end
	
	class MultiShotEffect < WeaponAttackEffect
		def initialize(params = {})
			super(params)
			@grouping = true
		end
		
		def get_hitting_number(actor)
			1
		end
				
		def get_attack(actor)
			(super * 0.75).to_i
		end
		
		def get_hitting_border(actor, target)
			super - 8
		end

	end

	
	class SharpAttackEffect < WeaponAttackEffect
		def initialize(ability_type, params = {})
			super(params)
			
			case ability_type
			when STR
				@state_data << [StrBonusState, -15, 999]
			when TEC
				@state_data << [TecBonusState, -15, 999]
			when AGL
				@state_data << [AglBonusState, -15, 999]
			when WIL
				@state_data << [WilBonusState, -15, 999]
			when PSY
				@state_data << [PsyBonusState, -15, 999]
			else
				raise "unknown ability type - #{ability_type.inspect}"
			end
		end
		
		def get_hitting_number(actor)
			1
		end

		def get_hitting_border(actor, target)
			super + 5
		end
	end
	

	

	
	class MagicAttackEffect < AttackEffect
		
		def init_params
			super
			@damage_rate = nil
			@hitting_type = :magic_control
		end

		def get_attack(actor)
			atk = (@damage_rate ? (actor.magic_power * @damage_rate).to_i : 0)
			atk += @fixed_damage if @fixed_damage
			return atk
		end
		
		def operate(actor, targets, base_msg = nil)
			if actor.kind_of?(Enemy) and targets.find{|x| x.find_state(ElementalProtectionState)} and
			rand(100) < 80 then
				msg = base_msg || get_message(actor, targets)
				return(msg + [_("しかし呪文の効果は祈りによって打ち消された")])
			else
				super
			end
		end
		
		def get_balance(actor, clean_hit = false)
			b = super
			b += actor.magic_balance_bonus
			
			return Util.fold_in_range(b, (0.1)..(0.9))
			
		end

		

		

	end
	
	class MagicSingleAttackEffect < MagicAttackEffect
		def target_type
			return TG_ENEMY
		end
		
		def operate(actor, targets, base_msg = nil)
			super(actor, [targets.first], base_msg)
		end
		

	end
	
	class MagicGroupAttackEffect < MagicAttackEffect
		def target_type
			return TG_ENEMY
		end
		

	end

	
	# HP・MP・CT・状態異常の回復
	# 回復しないパラメータにはnilを入れる
	class RecoverEffect < Effect
		attr_accessor :hp_fixed_recovery, :mp_fixed_recovery
		attr_accessor :state_data, :add_state_data, :target_type
		bool_attr_accessor :damaged_member_only # ダメージを受けているメンバーに対してのみ使用可能
		
		def init_params
			super
			@hp_fixed_recovery = nil
			@mp_fixed_recovery = nil
			@state_data = []
			@add_state_data = []
			@damaged_member_only = false
			init_usability(true, true, true)
		end
		

		def calc_recover_hp(actor)
			dice = get_hp_recovery_dice(actor)
			if dice then
				LOGGER.puts "\t\t回復量ダイス: #{dice.to_s}"
				
				return dice.roll
			else
				return nil
			end
		end
		
		def get_hp_recovery_dice(actor)
			return nil unless @hp_fixed_recovery
						
			recovery = @hp_fixed_recovery
			return DoubleDice.new(recovery * 2, recovery, get_balance(actor))
		end
		
		
		def get_balance(actor)
			0.6
		end
		
		
		
		def operate(actor, targets = GS.party.members, base_msg = nil)
			super
			msgs = []
			base_msg = base_msg || get_message(actor, targets)
			text_params = {:actor => actor.name}
			
			targets.each do |target|
				downside_lines = []
				text_params[:target] = target.name
				
				# HP回復
				value = calc_recover_hp(actor)
				if value and target.hp < target.hp_max then
					LOGGER.puts "\t\t回復量: #{value}"
					target.recover_hp(value)
					target.update_last_parameters
					text_params[:value] = value
					downside_lines << Util.eval_text(_('%{target}のHPが%{value}回復した'), text_params)
				end
				# 状態異常治療
				@state_data.each do |cls, level|
					already = target.added_status.find{|x| x.class == cls}
					next unless already
					
					downside_lines << already.get_recover_message(target)
					target.added_status.delete(already)
				end
				
				# 状態異常付加
				@add_state_data.each do |state_class, level, *extra_args|
					case level
					when :magic_control # 術制御比例
						level = actor.magic_control
					end
					state = state_class.new(level, *extra_args)
					target.add_state(state)
					
					downside_lines << state.get_added_message(target)
				end

				downside_lines << Util.eval_text(_('%{target}には効果がなかった'), text_params) if downside_lines.empty?
				msgs << (base_msg + Message.new(downside_lines))
			end
			
			
			
			return msgs
		end

	end
	
	
	
	
	module MagicRecoverEffect
		attr_accessor :hp_recovery_rate, :mp_recovery_rate
		
		def init_params
			super
			@hp_recovery_rate = nil
			@mp_recovery_rate = nil
		end
		
		def set_hp_recovery(fixed, rate)
			@hp_fixed_recovery = fixed
			@hp_recovery_rate = rate
		end

		def get_hp_recovery_dice(actor)
			return nil unless @hp_fixed_recovery && @hp_recovery_rate
			
			recovery = @hp_fixed_recovery + (actor.magic_power * @hp_recovery_rate).to_i
			return DoubleDice.new((recovery * 1.5).to_i, (recovery * 0.5).to_i, get_balance(actor))
		end

		def get_balance(actor)
			b = super
			b += actor.magic_balance_bonus
			return Util.fold_in_range(b, (0.1)..(0.9))
		end

		
		
	end
	
	class MagicSingleRecoverEffect < RecoverEffect
		include MagicRecoverEffect
		def init_params
			super
			@target_type = TG_MEMBER
		end
	end

	
	class MagicSelfRecoverEffect < RecoverEffect
		include MagicRecoverEffect
		def init_params
			super
			@target_type = TG_NONE
		end
		
		def operate(actor, dummy = nil, base_msg = nil)
			super(actor, [actor], base_msg)
		end
		
	end
	
	class MagicGroupRecoverEffect < RecoverEffect
		include MagicRecoverEffect
		
		def target_type
			TG_PARTY
		end
		
		def operate(actor, targets = GS.party.alive_members, base_msg = nil)
			super(actor, targets, base_msg)
		end

		
		
	end

	

	

	
	
	
	class MapVisionEffect < Effect
		def init_params
			super
			@camp_usable = true
		end
		
		def operate(actor, *dummy)
			super
			Game.message(get_message(actor, []))
			Phase.change(DungeonMapPhase.new)
			Game.operation_loop
			Phase.back
			return nil
		end
	end
	
	class CompassEffect < Effect
		def init_params
			super
			@camp_usable = true
			@town_usable = false
		end
		
		def operate(actor, targets, base_message)
			super
			dir = DIR_NAMES[GS.party.direction]
			msg = _("呪われた羅針盤は\n%{floor} / 座標 %{x}, %{y} / %{dir}の方角\nを示している")
			Game.message(msg.evaluate(:floor => GS.party.floor.name, :x => GS.party.x, :y => GS.party.y, :dir => dir))
			return(nil)
		end
	end
	
	class AlarmEffect < Effect
		attr_accessor :alarm_type
	
		def operate(*dummy)
			super
			
			GS.party.alarm_type = @alarm_type
			Game.message(_("辺りをつんざくような警報音が鳴り響いた！\n敵の群れが近づいてくる気配がする……"))
			return(nil)
		end
	end


	
end
