# キャラクタクラス
require 'darkhall/spell'
require 'darkhall/model'
require 'darkhall/savedata'

module DarkHall


	class Character < StorableObject
	
		attr_accessor :hp, :mp, :dead, :added_status
		attr_accessor :position, :last_hp, :last_ct
		attr_accessor :shield_used, :charge
		attr_reader :action, :round_action, :ai_memory
	
		def initialize
			@hp = 0
			@mp = {}
			@dead = false
			@action = nil
			@round_action = nil
			@added_status = []
			@shield_used = false
			@charge = 0
			@ai_memory = {}
		end
		
		def type_caption
			self.class.to_s
		end
		
		def hp_rate
			hp.to_f / hp_max
		end
		
		def hp_max_base
			hp_max
		end
		
		def hp_max_penalty
			0
		end
		
		def use_mp(value, spell)
			@mp[spell] -= value
			on_use_mp(value)
		end

		
		def usable_mp?(cost, spell_id)
			return(@mp.include?(spell_id) && @mp[spell_id] >= cost)
		end
		
		def usable_ct?(cost)
			return(@ct >= cost)
		end
		
		def forward?
			return @position == POS_FORWARD
		end
		
		def back?
			return @position == POS_BACK
		end
		
		def standing?
			return false if self.dead?
			return false if self.status.find{|x| !(x.standing)}
			return true
		end
		
		def guarding?
			@action.kind_of?(GuardAction)
		end
		
		def blocking?
			@action.kind_of?(BlockAction)
		end
		
		def position_caption
			case @position
			when POS_FORWARD
				_("F")
			when POS_BACK
				_("B")
			else
				" "
			end
		end
		
		def ai_act?
			true
		end
		
		def condition_caption
			if self.dead?
				"$[badcolor]----------------"
			elsif @action then
				"[#{@action.caption}]"
			else
				condition_caption_base
			end
		end
		
		def condition_caption_base
			captions = @added_status.map{|x| x.name if x.visible? }.compact
			
			return(captions.empty? ? "" : captions.join('/'))
		end

		
		def on_battle_start
			@shield_used = false
			@action = nil
			@charge = 0
			@ai_memory.clear
		end
		
		def on_battle_end
		end
		
		def on_round_end
			@shield_used = false
			update_last_parameters
			clear_action
		end
		
		def on_use_weapon(hitting_number)
		end
		
		def on_use_skill(skill_symbol)
		end
		
		# 盾を使ったとき
		def on_use_shield
			@shield_used = true unless self.guarding?
		end
		
		def on_use_mp(mp_cost)
			status.each{|x| x.on_use_mp(self, mp_cost)}
		end
		
		# 盾を使える状態にあるかどうか
		def shield_usable?
			return false unless self.shield
			return false if self.dead?
			return false if @shield_used
			return false if @round_action && @round_action.unguarding?
			return false if find_state(FeintState)

			return true
		end
		
		def set_action(action)
			@action = action
			@round_action = action
		end
		
		def finish_action
			@action = nil
		end
		
		def clear_action
			@round_action = nil
			@action = nil
		end
		

		
		def get_mastery(type, data_id)
			return 0.0
		end
		

		def get_ability(name)
			return self.send(name.to_s.downcase)
		end
		
		def arrow
			nil
		end

		# obsolete
		def attack
			return weapon_power
		end
		
		# obsolete
		def magic_attack
			return magic_power
		end
		
		# 致傷力
		def weapon_power
			re = (self.weapon ? self.weapon.power(self) : 0)
			status.each do |state|
				re += state.attack_bonus
			end

			re
		end
		
		# 武器の命中値
		def weapon_hitting
			r = self.tec
			status.each do |state|
				r += state.hitting_bonus
			end
			
			r
		end
		
		# パーフェクトガード発生確率(nilなら発動しない)
		def perfect_guard_border
			nil
		end

		
		
		
		
		
		# 術威力
		def magic_power
			pow = psy
			pow *= weapon.magic_power_rate if weapon
			return pow.to_i
		end
		
		# 術制御
		def magic_control
			wil + magic_control_bonus
		end
		
		def magic_control_bonus
			(weapon ? weapon.magic_control_bonus : 0)
		end
		
		
		# 術バランス補正(術制御が霊感に対して大きいほど安定)
		def magic_balance_bonus
			(magic_control - psy) * 0.025
		end

		
		
		
		def magic_boost?
			status.find{|x| x.kind_of?(MagicBoostState)}
		end
		
		# 攻撃回数
		def weapon_hitting_number
			return(self.weapon.hitting_number)
		end
		
		alias hitting_number weapon_hitting_number
		
		# 回避値
		def avoid
			re = self.agl
			self.status.each do |state|
				re += state.avoid_bonus
			end
			
			re += temporary_avoid_bonus

			re
		end
		
		def temporary_avoid_bonus
			re = 0
			re += AVOID_BONUS_ON_GUARDING if guarding?
			re -= AVOID_PENALTY_ON_UNGUARDING if @action && @action.unguarding?
			
			re
		end
		
		def constant_avoid
			avoid - temporary_avoid_bonus
		end
		
		# 行動速度
		def speed
			re = self.agl
			self.status.each do |state|
				re += state.speed_bonus
			end
			
			re
		end
		
		
		def clean_hitting_bonus
			status.map{|x| x.clean_hitting_bonus}.total || 0
		end
		
		def mp_cost_reducing
			status.map{|x| x.mp_cost_reducing_bonus}.total || 0
		end


		def get_damage_resist(damage_types)
			return (damage_types.map{|x| self.damage_resists[x] || RES_NORMAL}.min || RES_NORMAL)
		end

		def get_state_resist(state_cls)
			self.state_resists[state_cls] || RES_NORMAL
		end
		


		
		
		def add_state(state)
			# 重複した場合
			if (already = find_added_state(state.class)) then
				case state.lapping_type
				when State::LT_STACK
					if already then
						state.level += already.level
						remove_state(state.class)
					end
				when State::LT_OVERRIDE
					if state.level <= already.level then
						return false
					end
				when State::LT_NONE
					return false
				end
			end
			
			@added_status << state.dup
			
			# 行動不可にするステートの場合は、そのラウンドの行動をキャンセル
			if state.deactive then
				clear_action
			end
			return state
		end
		
		def remove_state(state_class)
			@added_status.delete_if{|x| x.kind_of?(state_class)}
		end
		
		def find_state(state_class)
			self.status.find{|x| x.kind_of?(state_class)}
		end
		
		def find_added_state(state_class)
			@added_status.find{|x| x.kind_of?(state_class)}
		end

		
		def status
			return @added_status
		end


		def update_last_parameters
			@last_hp = @hp
			@last_ct = @ct
		end
		
		# 無効化判定
		def protection_check(damage_types)
			nil
		end
		
		# キャラクターにHPダメージを与える
		def damage(value, killing = true)
			@hp -= value
			
			dead_check(value) if killing
			return self
		end
		
		def life_damage(value, killing = true)
			damage(value, killing)
		end
		

		
		def dead_check(damage)
			if @hp <= 0 then
				LOGGER.puts "\t#{name}は倒れた"
				dead_sequence
			end
		end
		
		# 一撃必殺
		def kill
			damage(100000)
		end
		
		

		
		# キャラクターに衝撃（CTダメージ）を与える
		def ct_damage(value)
			@ct = (@ct * ((100 - value) / 100.0)).to_i
			@ct = CT_MINIMUM if @ct < CT_MINIMUM
		end
		alias impact ct_damage
		
		def ct_auto_recovery
			recover_ct(8 + rand(4))
		end
		
		def recover_hp(value)
			@hp += value
			@hp = self.hp_max if @hp > self.hp_max
		end
		
		# Return: success?
		def revive
			if self.dead? then
				@dead = false
				@hp = 0

				return true
			else
				return false
			end
		end

		
		
		def recover_mp(value, spell = nil)
			if spell then
				@mp[spell] += value
				@mp[spell] = 0 if @mp[spell] < 0
				@mp[spell] = self.mp_max[spell] if @mp[spell] > self.mp_max[spell]
				
			else
				@mp.each_key do |spell|
					recover_mp(value, spell)
				end
			end
		end
		
		

		
		def dead_sequence
			@dead = true
			clear_action

		end
		
		
		def active?
			return false if @dead
			return false if status.find{|x| x.deactive}
			return true
		end
		
		def alive?
			!(@dead)
		end
		
		def dead?
			@dead
		end
		
		def deadly?
			@hp <= 0
		end
		
		def undead
			false
		end
		
		
		def str; v = str_base + str_bonus; (v < 1 ? 1 : v); end
		def tec; v = tec_base + tec_bonus; (v < 1 ? 1 : v); end
		def agl; v = agl_base + agl_bonus; (v < 1 ? 1 : v); end
		def wil; v = wil_base + wil_bonus; (v < 1 ? 1 : v); end
		def psy; v = psy_base + psy_bonus; (v < 1 ? 1 : v); end
		
		def str_base; get_ability_base(STR); end
		def tec_base; get_ability_base(TEC); end
		def agl_base; get_ability_base(AGL); end
		def wil_base; get_ability_base(WIL); end
		def psy_base; get_ability_base(PSY); end

		def str_bonus; get_ability_bonus(STR); end
		def tec_bonus; get_ability_bonus(TEC); end
		def agl_bonus; get_ability_bonus(AGL); end
		def wil_bonus; get_ability_bonus(WIL); end
		def psy_bonus; get_ability_bonus(PSY); end



		def dump
			hash = super
			hash['hp'] = @hp
			hash['mp'] = @mp
			hash['dead'] = @dead
			hash['added_status'] = @added_status
			return hash
		end
		
		def self.create_from_mpac_model(hash)
			obj = self.new
			obj.hp = hash['hp']
			obj.mp = {}
			hash['mp'].each do |key, value|
				obj.mp[key] = value
			end
			obj.dead = hash['dead']
			obj.added_status = hash['added_status']
			obj.update_last_parameters
			return obj
		end

	end
	
	DUMMY_CHARACTER = Character.new
	
end
	
	
	
	
