/*---------------------------------------------------------------------*//**
	未定義の関数を外部関数によって解決を試みる

	@param codeExtScriptOut	追加スクリプトコード(戻り値 false の場合有効)
	@param paramParse		解析汎用パラメータ
	@retval true	解析を終了してよし
					※	外部拡張ネイティブ関数追加によって解決した場合も
						この戻り値でよい
	@retval false	解析を続ける
					※	codeExtScriptOut に該当関数のスクリプトコードを
						設定して、解決を試みる
**//*---------------------------------------------------------------------*/
bool EsExternalExtension::resolveUndefinedFunctionByExtFunc(VcString* codeExtScriptOut, EsExtParam paramParse)
{
	// 関数呼び出しが解決しているか調べる
	s32 numUnresolvedFuncCall = 0;
	for(ListIterator<EsParsedFuncInfo*> itCall = _listParsedFuncInfo->iterator(); itCall.has(); itCall.next())
	{
		if(itCall.object()->getKind() != EsParsedFuncInfo::KIND_CALL)	{	continue;	}

		const VcString* nameCall = itCall.object()->getFuncName();
		bool isDefFind = false;

		// スクリプト内定義関数から探す
		for(ListIterator<EsParsedFuncInfo*> itDef = _listParsedFuncInfo->iterator(); itDef.has(); itDef.next())
		{
			if(itDef.object()->getKind() != EsParsedFuncInfo::KIND_DEF)	{	continue;	}

			if(nameCall->equals(itDef.object()->getFuncName()))
			{
				isDefFind = true;
				break;
			}
		}
		
		if(!isDefFind)
		{
			// 既に追加済みの外部拡張ネイティブ関数から探す
			for(ListIterator<EsExtNativeFunc*> itEnf = _listExtNativeFunc->iterator(); itEnf.has(); itEnf.next())
			{
				if(nameCall->equals(itEnf.object()->getName()))
				{
					isDefFind = true;
					break;
				}
			}
		}

		itCall.object()->setUnresolved(!isDefFind);	// 未解決フラグを立てる
		if(!isDefFind) { numUnresolvedFuncCall++; }
	}

	if(numUnresolvedFuncCall <= 0)	// 未解決の関数呼び出しはない
	{
		return true;	// 解析を終わって問題ない
	}

	// 外部のスクリプト追加、もしくは外部拡張ネイティブ関数追加で解決を試みる
	bool isEndParse = true;	// 特に処理が入らなければ解決を終了する
	for(ListIterator<EsParsedFuncInfo*> itCall = _listParsedFuncInfo->iterator(); itCall.has(); itCall.next())
	{
		if(itCall.object()->getKind() != EsParsedFuncInfo::KIND_CALL)	{	continue;	}
		if(!itCall.object()->isUnresolved())	{	continue;	}
		if(!resolveUndefinedFunction(codeExtScriptOut, itCall.object()->getFuncName(), paramParse))
		{
			isEndParse = false;
		}
	}

	return isEndParse;
}
/*---------------------------------------------------------------------*//**
	自動開始イベントの開始
**//*---------------------------------------------------------------------*/
bool StoryManager::beginAutoBeginEvent(s32 kind)
{
	bool isBegin = false;

	for(ListIterator<AutoBeginEventInfo*> it = _listAutoBeginEvi->iterator(); it.has(); it.next())
	{
		AutoBeginEventInfo* abevi = it.object();
		if(abevi->getKind() == kind)	// 同じ種別
		{
			// イベント起動原因と起動判定
			short cid = EventCause::CID_NULL;
			bool isCall = true;
			switch(kind)
			{
			case AutoBeginEventInfo::KIND_STORY_START:
				cid = EventCause::CID_STORYSTART;
				break;
			case AutoBeginEventInfo::KIND_LOAD_INTVEV_START:
				cid = EventCause::CID_INTVLEVSTART;
				break;
			case AutoBeginEventInfo::KIND_MAP_START:
				cid = EventCause::CID_MAPSTART;
				if(Game::getGame()->getMoveMap()->getCurMapId() != abevi->getMapId())
				{
					isCall = false;
				}
				break;
			}

			// イベント起動
			if(isCall)
			{
				u16 evid = abevi->getCallEvi()->getInfo(abevi->getActiveCallEviIndex())->getEvid();
				if(evid != 0)	// わざわざ起動しない設定で上書きすることもありうる
				{
					EvCause evcause(cid);
					EventMatter* matter = (EventMatter*)_evsysRef->begin(evid, 0, &evcause);
					if(matter != 0L)
					{
						isBegin = true;

						// イベントが複数定義されている場合は、次に送る
						if(abevi->getCallEvi()->getInfoNum() >= 2)
						{
							abevi->nextCallEvi(false);
						}
					}
				}
			}
		}
	}

	return isBegin;
}
/*---------------------------------------------------------------------*//**
	シリアライズ
**//*---------------------------------------------------------------------*/
bool StoryManager::serialize(Serializer* ser) const
{
	// 実行中の Act イベント ID を得る
	u16 evidActing = 0;
	EventData* evdat = Game::getGame()->getEventSys()->getEventData();	ASSERT(evdat != 0L);
	for(int imat = 0; imat < evdat->getEventMatterNum(); imat++)
	{
		EventMatter* matterWk = evdat->getEventMatter(imat);
		if((matterWk->getMatterType() == EMTYPE_ACT) && matterWk->isBegin())	// 開始済み ActMatter 判定
		{
			evidActing = matterWk->getEvId();
		}
	}

	// ストーリーの保存
	if(ser->isStructureMode())	// ストラクチャモード
	{
		SaveStructure* svst = (SaveStructure*)ser->getStructure();
		svst->_gamesvst._storyid = _storyid;										// ストーリー ID の書き込み
		svst->_gamesvst._isPlayedStoryStartupEvent = _isPlayedStoryStartupEvent;	// ストーリー開始イベント起動フラグの書き込み
		svst->_gamesvst._evidActing = evidActing;									// 実行中の Act イベント ID の書き込み
	}
	else						// ダイレクトモード
	{
		ser->store(&_storyid);						// ストーリー ID の書き込み
		ser->store(&_isPlayedStoryStartupEvent);	// ストーリー開始イベント起動フラグの書き込み
		ser->store(&evidActing);					// 実行中の Act イベント ID の書き込み
	}

	// 配置オブジェクトの状態を保存する
	if(ser->isStructureMode())	// ストラクチャモード
	{
		SaveStructure* svst = (SaveStructure*)ser->getStructure();
		if(!svst->storePlacementObjData(_listPlaceObj))
		{
			return false;
		}
	}
	else						// ダイレクトモード
	{
		s32 numPobj = _listPlaceObj->getCount();
		ser->store(&numPobj);
		for(ListIterator<PlacementObj*> it = _listPlaceObj->iterator(); it.has(); it.next())
		{
			const PlacementObj* pobj = it.object();
			pobj->serialize(ser);
		}
	}

	// ワールドマップのシリアライズ
	_wmap->serialize(ser);

	return true;
}
/*---------------------------------------------------------------------*//**
	ストーリーの解放
**//*---------------------------------------------------------------------*/
void StoryManager::releaseStory()
{
	// ストーリーを削除
	if(_stmod != 0L)
	{
		_stmod->destroy();
		delete _stmod;
		_stmod = 0L;
	}

	// マップ置換イベントを戻す
	EventData* evdat = _evsysRef->getEventData();
	for(ListIterator<OverrideEventMatter*> it = _listOvrdEvm->iterator(); it.has(); it.next())
	{
		const OverrideEventMatter* oem = it.object();
		if(oem->getKind() == OverrideEventMatter::KIND_MAP)	// タイプがマップのもののみ
		{
			evdat->unoverrideMatter(oem);
		}
	}
	_listOvrdEvm->removeAll();	// 置換イベント情報クリア

	// 配置オブジェクト情報クリア
	for(ListIterator<PlacementObj*> it = _listPlaceObj->iterator(); it.has(); it.next())
	{
		PlacementObj* pobj = it.object();
		if(pobj->getMapId() == Game::getGame()->getMoveMap()->getCurMapId())
		{
			Game::getGame()->getMap()->unplacePlacementObj(pobj);	// 配置解除
		}
	}
	_listPlaceObj->removeAll();

	// 自動起動イベントリストをクリア
	_listAutoBeginEvi->removeAll();

	// その他の値をクリア
	_storyid = 0L;
	_isPlayedStoryStartupEvent = false;
}
SRCR_BEGIN_NS

////////////////////////////////////////////////////////////////////////////
// クラス

//==========================================================================
// SaveStructure メソッド

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 外部サービス

/*---------------------------------------------------------------------*//**
	配置オブジェクトリストのセーブデータを保存する

	@param listPlaceObj 配置オブジェクトリスト
	@retval true 成功
	@retval false 失敗
**//*---------------------------------------------------------------------*/
bool SaveStructure::storePlacementObjData(const List<PlacementObj*>* listPlaceObj)
{
    // 末端を得る
    s32 idx = 0;
    while(idx < NUM_POBJ_MAX)
    {
        if(_pobjsvst[idx]._ucase == 0)	// 未記録
        {
            break;
        }
        idx++;
    }

    for(ListIterator<PlacementObj*> it = listPlaceObj->iterator(); it.has(); it.next())
    {
        if(idx >= NUM_POBJ_MAX)
        {
            ASSERT(idx < NUM_POBJ_MAX);
            return false;
        }
        const PlacementObj* pobj = it.object();
        if(!pobj->isNullState())	// 初期状態以外なら
        {
            PlacementObj::SaveStructure* pobjsvst = &_pobjsvst[idx];
            pobj->storeToStructure(pobjsvst);	// 保存
            idx++;
        }
    }
    ASSERT(idx <= NUM_POBJ_MAX);

    return true;
}
/*---------------------------------------------------------------------*//**
	配置オブジェクトリストへセーブデータを復元する

	@param listPlaceObj 配置オブジェクトリスト
	@retval true 成功
	@retval false 失敗
**//*---------------------------------------------------------------------*/
bool SaveStructure::restorePlacementObjData(List<PlacementObj*>* listPlaceObj) const
{
    for(ListIterator<PlacementObj*> it = listPlaceObj->iterator(); it.has(); it.next())
    {
        PlacementObj* pobj = it.object();

        for(int idx = 0; idx < NUM_POBJ_MAX; idx++)
        {
            const PlacementObj::SaveStructure* pobjsvst = &_pobjsvst[idx];
            if(isSamePlacementObj(pobjsvst, pobj))
            {
                pobj->restoreFromStructure(pobjsvst);	// 復元
                break;
            }
        }
    }

    return true;
}
/*---------------------------------------------------------------------*//**
	解析関数情報追加
**//*---------------------------------------------------------------------*/
void EsExternalExtension::addParsedFuncInfo(const VcString* nameFunc, bool isDef)
{
	if(_listParsedFuncInfo == 0L)	{	return;	}

	// 入力された関数の種類
	EsParsedFuncInfo::Kind kind = isDef ? EsParsedFuncInfo::KIND_DEF : EsParsedFuncInfo::KIND_CALL;

	// 重複チェック
	for(ListIterator<EsParsedFuncInfo*> it = _listParsedFuncInfo->iterator(); it.has(); it.next())
	{
		EsParsedFuncInfo* pfi = it.object();
		if(	(pfi->getKind() == kind) &&
			(pfi->getFuncName()->equals(nameFunc))	)
		{
			return;	// 重複
		}
	}

	// リストに追加する
	EsParsedFuncInfo* pfi = new EsParsedFuncInfo(nameFunc, kind);
	_listParsedFuncInfo->addTail(pfi);
}
/*---------------------------------------------------------------------*//**
	スキルフレーム処理 - 実行中
**//*---------------------------------------------------------------------*/
bool Char1504_Shika_EnemySpirit::execSkillAct(ExecRes* res, const ExecCtx* ec, s32 cntStep, f32 frmcntStep)
{
	const f32 FRAME_STEP = 0.76667f * FRAMERATE;

	if(cntStep == 1)
	{
		setBefaviorMaxFrame(FRAME_STEP);	// 最大の行動フレーム数設定
	}

	setBefaviorCurrentFrame(frmcntStep);	// 現在の行動フレーム数設定

	if(frmcntStep >= FRAME_STEP)	// 攻撃フレーム
	{
		const CharLogicData* cldat = getCharLogicData(); ASSERT(cldat != 0L);
		// 範囲内の対象をリストアップ
		f32 lenEffctvSq = cldat->getSkillRange() * cldat->getSkillRange();
		List<Unit*> listUnits;
		CalcUtils::collectUnitFanRange(
			&listUnits,
			getThisUnit()->getPosition(),
			getThisUnit()->getDirection()->y(),
			Unit::UNITFLAG_PC,
			lenEffctvSq,
			TFW_COS45	);	// ±45°以内
		// リストアップしたユニットにクラスタを投げる
		Unit* unitTrg = 0L;
		for(ListIterator<Unit*> it = listUnits.iterator(); it.has(); it.next())
		{
			unitTrg = it.object();
			break;
		}

#if 1
		TransStat tstat;
		EleneStat eestatSkill(cldat->getSkillOqlElene(), cldat->getSkillCurElene());
		tstat.setupForSkill(getThisUnit(), &eestatSkill);
		MagicInfluencer::serveGeneralMc(getThisUnit(), unitTrg, &tstat, GameParticleDef::PTCLK_SKILL_SHOCK_WAVE);
#else
		MagicSys* mgcsys = Game::getGame()->getMagicSys(); ASSERT(mgcsys != 0L);
		MagicClusterCreateParam mccprm(MagicClusterType::SERVED, GameParticleDef::PTCLK_SKILL_SHOCK_WAVE);
		EleneStat eestatSkill(cldat->getSkillOqlElene(), cldat->getSkillCurElene());
		Vector3F pos(*getThisUnit()->getCenterPos());
		mccprm._unitOwnrRef = getThisUnit();
		mccprm._unitMainTrgRef = unitTrg;
		mccprm._pos = &pos;
		mccprm._tstat.setupForSkill(getThisUnit(), &eestatSkill);
		mccprm._lifeframe = cldat->getSkillCurElene()->getWater() / Elene::ELENE_VALID_FIGURE;
		mccprm._isNoOnlyTrgColl = true;
		u16 mcidNew = mgcsys->appearCluster(&mccprm);
		if(mcidNew == 0)		{	return true;	}	// 成功ではないが終えるために次のステップへ
		MagicCluster* mcNew = mgcsys->getCluster(mcidNew);
		if(mcNew == 0L)			{	return true;	}	// 成功ではないが終えるために次のステップへ
		TFW_SET_FLAG(*mcNew->ctrlFlags(), MagicCluster::CTRLF_DIR_TO_ROTZ, true);	// 方向を Z 軸回転に反映させる

		// クラスタ発射
		/*
		f32 acc = cldat->getSkillCurElene()->getWind() * (0.1f / (f32)Elene::ELENE_VALID_FIGURE);
		if(acc < 0.033f)	{	acc = 0.033f;	}
		Vector3F accMc(0.0, 0.0, acc);
		Matrix4F mtxRot;
		mtxRot.rotateY(getThisUnit()->getDirection()->y());
		mtxRot.mult(&accMc, &accMc);
		mcNew->accelerate(&accMc);
		*/
		f32 speed = cldat->getSkillCurElene()->getWind() * (0.1f / (f32)Elene::ELENE_VALID_FIGURE);
		if(speed < 0.033f)	{ speed = 0.033f; }
		Vector3F velMc(0.0f, 0.0f, speed);
		Matrix4F mtxRot;
		mtxRot.rotateY(getThisUnit()->getDirection()->y());
		mtxRot.mult(&velMc, &velMc);
		mcNew->setInitialVelocity(&velMc);
		mcNew->reflectPosture();
#endif

		resetBefaviorFrame();		// 行動フレームリセット
		return true;
	}

	return false;	// 継続する
}
/*---------------------------------------------------------------------*//**
	デシリアライズ
**//*---------------------------------------------------------------------*/
bool StoryManager::deserialize(Serializer* ser)
{
	// ストーリーデータの読み込み
	s32 storyid = 0;
	u16 evidActing = 0;
	bool isPlayedStoryStartupEvent = false;
	bool isEvIntvl = TFW_IS_FLAG(Game::getGame()->getSaveSys()->getSaveData()->getLoadTimeSaveFlags(), SaveData::SVF_EVENT_INTVL);
	if(ser->isStructureMode())	// ストラクチャモード
	{
		const SaveStructure* svst = (SaveStructure*)ser->getStructure();
		storyid = svst->_gamesvst._storyid;										// ストーリー ID 値の読み込み
		isPlayedStoryStartupEvent = svst->_gamesvst._isPlayedStoryStartupEvent;	// ストーリー開始イベント起動フラグの読み込み
		evidActing = svst->_gamesvst._evidActing;								// 実行中の Act イベント ID の読み込み
	}
	else						// ダイレクトモード
	{
		ser->restore(&storyid);						// ストーリー ID 値の読み込み
		ser->restore(&isPlayedStoryStartupEvent);	// ストーリー開始イベント起動フラグの読み込み
		ser->restore(&evidActing);					// 実行中の Act イベント ID の読み込み
	}

	// Volume 1 Lite 版はストーリーが 10203 まで(この実装はあまり美しくない….オーバーライドによる実装を要検討【2010/10/29 r-kishi】)
	#if defined(_ENLIGHT_V01_LITE)
		if(storyid > 10203)
		{
			storyid	= 10203;
			isPlayedStoryStartupEvent = false;
			Game::getGame()->getSaveSys()->getSaveData()->setSaveF(SaveIdDef::SFID_ST10203_CORPO_SAY_TOGETHER, false);	// [St10203] アサダウン後コルポ合流時のイベントを見ていない
		}
	#endif

	// ストーリーのロード
	loadStory(storyid);	// ストーリーを読み込む
	_isPlayedStoryStartupEvent = isPlayedStoryStartupEvent;

	// 配置オブジェクトの状態を読み込む
	if(ser->isStructureMode())	// ストラクチャモード
	{
		SaveStructure* svst = (SaveStructure*)ser->getStructure();
		if(!svst->restorePlacementObjData(_listPlaceObj))
		{
			return false;
		}
	}
	else						// ダイレクトモード
	{
		s32 numPobj = 0;
		ser->restore(&numPobj);
		ASSERT(_listPlaceObj->getCount() == numPobj);
		ListIterator<PlacementObj*> it = _listPlaceObj->iterator();
		for(int i = 0; i < numPobj; i++)
		{
			if(!it.has())
			{
				ASSERT(false);
				return false;
			}
			PlacementObj* pobj = it.object();
			pobj->deserialize(ser);
			it.next();
		}
	}

	// ワールドマップのデシリアライズ
	_wmap->deserialize(ser);

	// イベント途中セーブデータは再開時イベントをセットする
	if(isEvIntvl && (evidActing != 0))
	{
		reserveEventForResume(evidActing, true);
	}

	return true;
}
/*---------------------------------------------------------------------*//**
	マップ変更後通知
**//*---------------------------------------------------------------------*/
void StoryManager::notifyChangedMap(bool isDeserializeCase)
{
	Map* map = Game::getGame()->getMap(); ASSERT(map != 0L);
	MoveMap* mvmap = Game::getGame()->getMoveMap(); ASSERT(mvmap != 0L);

	// マップに脇役を配置
	for(ListIterator<PlacementObj*> it = _listPlaceObj->iterator(); it.has(); it.next())
	{
		PlacementObj* pobj = it.object();

		if(isDeserializeCase)	// セーブデータ読み込み時
		{
			if(pobj->isPlaced())		// 配置済み
			{
				map->placePlacementObj(pobj, true);		// マップ配置を復元
			}
			else if(pobj->isNewPlacedCondition())
			{
				map->placePlacementObj(pobj, false);	// マップに通常条件配置
			}
		}
		else
		{
			if(pobj->isNewPlacedCondition())
			{
				map->placePlacementObj(pobj, false);	// マップに配置
			}
			else if(pobj->isPlaced())	// 配置済み
			{
				map->unplacePlacementObj(pobj);			// 配置解除
			}
		}
	}

	// マップ置換イベントを処理
	EventData* evdat = _evsysRef->getEventData();
	for(ListIterator<OverrideEventMatter*> it = _listOvrdEvm->iterator(); it.has(); it.next())
	{
		const OverrideEventMatter* oem = it.object();
		if(oem->getKind() == OverrideEventMatter::KIND_MAP)	// タイプがマップのもののみ
		{
			if(oem->isCondition())
			{
				evdat->overrideMatter(oem);
			}
		}
	}

	// マップモジュールを作成
	_mapmod = MapModFactory::makeMapMod(mvmap->getCurMapId()); ASSERT(_mapmod != 0L);

	// マップ開始時イベントを起動
	beginAutoBeginEvent(AutoBeginEventInfo::KIND_MAP_START);

	// 各通知処理
	ASSERT(_stmod != 0L);
	_stmod->onDecisionParty(mvmap->getCurMapId(), mvmap->getPrevMapId());
	_stmod->notifyChangedMap(mvmap->getCurMapId(), mvmap->getPrevMapId());
	_mapmod->begin();
	_wmap->notifyChangedMap();
}