/*
 *****************************************************************************
 *              
 *    ULTRA64 ヨッシーゲーム プログラム
 *    $Id: main.c,v 1.1 2003/05/30 21:25:28 tong Exp $
 *
 *    <条件コンパイルのシンボル説明>
 *
 *    PRODUCT_ROM : 一切のデバッグ情報を外した製品版ROMを生成。
 *    SAMPLE0_ROM : 最小限のデバッグ情報だけを残した調整、チェック用ROMを生成。
 *    DEBUG       : プログラム開発用で,ターミナルへの情報表示が可能となる。
 *                  DEBUG が有効のとき SAMPLE0_ROM も有効となる。
 *
 *****************************************************************************
 */
#include "system.h"
#include "main.h"
#include "system_info.h"
#include "memory.h"
#include "castNameOBJ.h"
#include "viewManager.h"
#include "bgManager.h"
#include "entryManager.h"
#include "actorManager.h"
#include "frameManager.h"
#include "nxgotoManager.h"
#include "procTimManager.h"
#include "automsg.h"
#include "audio.h"
#include "bg_task.h"
#include "crossManagerBG.h"
#include "worldDatabase.h"
#include "clipbdManager.h"
#if VIBPACK
#include "vibpackManager.h"
#endif
#include "saveManager.h"
#include "sramManager.h"

#if USE_FAULT
#include "fault.h"
#endif
#include "bg_debug.h"		/* REG */

#include "sleep.h"
#include "irqmgr.h"		/* ResetStatus */

#include "actor_yoshiSetupAction.h"

#include "raster.h"

static PROCESS dummy[] = {
    (PROCESS)raster_init,
    (PROCESS)raster_SetScrollParam,
    (PROCESS)raster_SetScrollRect,
    (PROCESS)raster_SetVRAMAddress,
    (PROCESS)raster_move2,
    (PROCESS)raster_kill,
};
/*
 ******************************************************************************
 *
 *     例外処理
 *
 ******************************************************************************
 */
/*
 ******************************************************************************
 *    リセットスイッチが押された時の処理
 *    (Game->processに登録され実行される)
 ******************************************************************************
 */
static void reset_process(GAME *Game)
{
    (void *)Game;
#if DEBUG
    PRINTF("reset_process\n");
#endif
    ForceBlackOn();		/* 画面を真っ暗にする */
#if VIBPACK
    VIBPACK_CTRL(0);		/* 振動パック停止 */
#endif
#if SOUND
    sNa_soundStop();	        /* サウンドの停止 */
#endif
    if (ResetStatus == 2) {	/* ０．５秒経過 */
	audio_timer_disable();	/* オーディオスレッド足止め */
	audio_timer_disable();	/* 既に止まっている場合は自分も止まる */
    }
}
/*
 ******************************************************************************
 *     リセットの設定処理を行う。
 ******************************************************************************
 */
#include "actor_seisan.h"
static int resetProc(GAME *Game)
{
    if (ResetStatus != 0) {
        /* ハードリセットスイッチが押された時の処理 */
        Game->process = reset_process;
#if DEBUG
	PRINTF("Game->process = reset_process\n");
#endif
	return TRUE;
    }
   if(is_playGame() && !is_reset())
       if(chkButton(Z_BTN) && chkTrigger(START)) {
#if DEBUG
	   PRINTF("## ソフトリセット!!\n");
#endif
	   set_reset();
#if VIBPACK
	   VIBPACK_CTRL(0);		      // 振動パック停止
#endif
#if SOUND
	   sNa_soundStop();	              // サウンドの停止
#endif
	   subresetGame();	/* ゲーム中に関係する情報の初期化 */
	   set_newGamePage(GMPAGE_1);
#if JAPAN
	   nextTo_titleScene(PURIKURA_VIEW);
#endif
#if AMERICA
	   if( is_JAPAN() )
	       nextTo_titleScene(PURIKURA_VIEW);
	   else
	       nextTo_titleScene(PCAMERICA_VIEW);
#endif
#if EUROPE
	   if( is_USA() )	/* 英語？ */
	       nextTo_titleScene(PCAMERICA_VIEW);
	   if( is_FRANCE() )	/* フランス語？ */
	       nextTo_titleScene(PCFRENCH_VIEW);
	   if( is_GERMANY() )	/* ドイツ語？ */
	       nextTo_titleScene(PCGERMANY_VIEW);
#endif
	   return TRUE;
       }
   return FALSE;
}
/*
 ******************************************************************************
 *     メインアクターの強制 KILL 処理
 *     (KILL すれば TRUE を返す)
 ******************************************************************************
 */
static int forceKill_mainActorProc(void)
{
    if(!is_shopDemo()
       && chkButton(Z_BTN)
       && chkButton(L_BTN)
       && chkButton(A_BTN)
       && chkButton(B_BTN)) {
	ACTOR  *actor = getP_mainActor();

	if(actor) {
#if DEBUG
	    PRINTF("## ヨッシーを強制 KILL した!!\n");
#endif
	    chgDownDemo_Yoshi(actor);
	    return TRUE;
	}
    }
    return FALSE;
}
/*
 ******************************************************************************
 *     デバッグ用ポーズ(一時停止)設定処理を行う。
 ******************************************************************************
 */
#if FOR_EDITOR
/* デバッグ用ポーズ中のコマ送り処理 */
static void pouse_and_pass_frameProc(ACTORIF *actorInfo)
{
    if(chkTrigger(R_BTN))	      // コマ送り
	activeEntryProc(actorInfo);
    else
	dbg_pouseEntryProc(actorInfo);// ポーズ中のアクティブ処理
}
/* デバッグ用ポーズの設定処理 */
int set_dbgPouse(t_gsps pouse)
{
    if(set_pouseFg(pouse)) {
        get_game().actorInfo.process = pouse_and_pass_frameProc;
	return TRUE;
    }
    get_game().actorInfo.process = activeEntryProc;
    return FALSE;
}
/* コントローラの状態によってデバッグ用ポーズの設定を行う */
static int dbg_pouseProc(void)
{
    if(is_pousePermi()
       && (is_playGame() && !is_exerciseMode())
       && chkTrigger(START))
	return set_dbgPouse((t_gsps)(get_pouseFg() ^ TRUE));
     return FALSE;
}
#endif
#if USE_SLEEP_WAKEUP
/*
 ******************************************************************************
 *     ヨッシーセレクト開始のためのコントローラー入力の監視処理
 *     (セレクト処理が開始されれば TRUE を返す)
 ******************************************************************************
 */
static int yoshi_selectProc(void)
{
    if(is_pouse() && chkTrigger(A_BTN)) {
	if(nextTo_pSelOvlScene()) {
#if DEBUG
	    PRINTF("### セレクト スタート\n");
#endif
	    return TRUE;
	}
#if DEBUG
	PRINTF(__ERROR
	       "yoshi_selectProc() : ヨッシーのセレクトシーンへの移行に"
	       "失敗した!!\n");
#endif
    }
    return FALSE;
}
#endif
/*
 ******************************************************************************
 *     例外処理
 *     (次フレームの処理の大きな流れを決定する処理なので,必ず最後にあること)
 ******************************************************************************
 */
#include "actor_panoramaMaster.h"
static void exceptionProc(GAME *Game)
{
    if(resetProc(Game))		          // リセット処理
	return;
    if(forceKill_mainActorProc())         // メインアクターを強制的にKILL
	return;
#if USE_SLEEP_WAKEUP
    if(yoshi_selectProc())	          // ヨッシーセレクト処理
	return;
#endif
#if FOR_EDITOR
    if(dbg_pouseProc())		          // ポーズ処理
	return;
#endif
}
/*
 ******************************************************************************
 *
 *     時限処理
 *
 ******************************************************************************
 */
/*
 ******************************************************************************
 *     スイッチのカウンターを減らしていく
 ******************************************************************************
 */
static void decrementSwichiCnt(void)
{
    if (!is_pause()) {
	if (get_switchCnt() > 0) {
	    /* スイッチ Counter decrement */
	    set_switchCnt(get_switchCnt() - 1);
	    
	    PRINTF("SWITCH : %d\n", get_switchCnt());
#if SOUND /* ♪ */
	    sNa_SetTimerCount(NA_TIMER_HATENA_SWITCH, (s16)get_switchCnt());
#endif
	    /* Start? */
	    if (!get_switchFlag()) {
#if SOUND /* ♪♪ */
		sNa_Event(NA_EVENT_TIMER_START);
#if DEBUG
		PRINTF("♪♪ タイマーの調べ START\n");
#endif
#endif
		set_switchFlag(ON);
	    }
	} else {
	    /* End ? */
	    if (get_switchFlag()) {
#if SOUND /* ♪♪ */
		sNa_Event(NA_EVENT_TIMER_END);
#if DEBUG
		PRINTF("♪♪ タイマーの調べ END\n");
#endif
#endif
		set_switchFlag(OFF);
	    }
	}
    }
}
/*
 ******************************************************************************
 *     スイッチを OFF する
 ******************************************************************************
 */
static void offSwichiCnt(void)
{
    /* End ? */
    if (get_switchFlag()) {
#if SOUND /* ♪♪ */
	sNa_Event(NA_EVENT_TIMER_END);
	sNa_SetTimerCount(NA_TIMER_HATENA_SWITCH, 0);
#if DEBUG
	PRINTF("♪♪ タイマーの調べ END\n");
#endif
#endif
	set_switchFlag(OFF);
	set_switchCnt(0);
    }
}

/*
 ******************************************************************************
 *     時限処理
 ******************************************************************************
 */
/* 時限処理の解放 */
#define deconst_limitTimeProc()               offSwichiCnt()

/* 時限処理 */
static void limitTimeProc(void)
{
    decrementSwichiCnt();
}
/*
 ******************************************************************************
 *
 *     入出力処理
 *
 ******************************************************************************
*/
/*
 ******************************************************************************
 *     "入力"のリセット 
 ******************************************************************************
*/
#define  reset_inputProc()           chg_inputProc(ROCK_ON_INPUT)
#if SYS_GATEWAY_N64
/*
 ******************************************************************************
 *    ゲートウェイ６４システムの処理
 *    (ゲートウェイ６４システムからスーパーフリーズを掛ける処理)
 ******************************************************************************
 */
static void spFzGatewayN64(void)
{
    unshort  port;
    
    if(chkButton(UP) && chkButton(DOWN) && !is_spFreeze()) {
	if(chkTrigger(UP) || chkTrigger(DOWN)) {
#if DEBUG
	    PRINTF("## ゲートウェイ６４のシステムポーズ ＯＮ !!\n");
#endif
	    port = 0x0ffff;
	    ssGWYPWrite(&port);        // ｹﾞｰﾄｳｪｲ64へ一時停止ｼｸﾞﾅﾙを送る
	    sNa_GatewayPauseOn();      // サウンドの一時停止
	    spFreeze_ON();	       // スーパーフリーズをＯＮ
	}
    }
    else
	if(chkButton(LEFT) && chkButton(RIGHT) && is_spFreeze()) {
	    if(chkTrigger(LEFT) || chkTrigger(RIGHT)) {
#if DEBUG
		PRINTF("## ゲートウェイ６４のシステムポーズ ＯＦＦ !!\n");
#endif
		port = 0x0;
		ssGWYPWrite(&port);    // ｹﾞｰﾄｳｪｲ64へ一時停止解除ｼｸﾞﾅﾙを送る
		sNa_GatewayPauseOff(); // サウンドの一時停止解除
		spFreeze_OFF();	       // スーパーフリーズをＯＦＦ
	    }
	}
}
#endif
/*
 ******************************************************************************
 *     入力処理
 *     (コントローラから入力を行い, 入力結果を"入力変換処理"を通して特定の
 *    目的のためのコードに変換する。
 *      変換は, Game->inputProc に登録された処理によって行う。)
 ******************************************************************************
*/
/* 入力禁止するボタンのマスク */
#define PAUSE_FREEZE_BTN          (UP | DOWN | LEFT | RIGHT \
				   | L_BTN | R_BTN \
				   | A_BTN | B_BTN \
				   | C_BTN | D_BTN | E_BTN | F_BTN \
				   | Z_BTN)
#if !USE_SUPER_FREEZE
#define CONTROLLER_FREEZE_BTN     (UP | DOWN | LEFT | RIGHT \
				   | L_BTN | R_BTN \
				   | A_BTN | B_BTN \
				   | C_BTN | D_BTN | E_BTN | F_BTN \
				   | Z_BTN \
				   | START)
#endif
#if USE_SUPER_FREEZE
#define SUPER_FREEZE_BTN          (L_BTN | R_BTN \
				   | A_BTN | B_BTN \
				   | C_BTN | D_BTN | E_BTN | F_BTN \
				   | Z_BTN \
				   | START)
#define CONTROLLER_FREEZE_BTN     SUPER_FREEZE_BTN
#endif

void inputProcess(GAME *Game)
{
    Controller(Game);      // コントローラからの入力
#if SYS_GATEWAY_N64
    spFzGatewayN64();      // スーパーフリーズ ゲートウェイ６４処理
#endif

    /* コントローラからの入力に条件マスクを行う */
#if USE_SUPER_FREEZE
    if(is_freeze() || is_spFreeze() || is_freezeController()) {
 	/* フリーズ時のコントローラ入力のマスク(スーパーフリーズを優先) */
	if(is_spFreeze() || is_freezeController())
	    clrButton(SUPER_FREEZE_BTN);      // スーパーフリーズの時
#endif
#if !USE_SUPER_FREEZE
    if(is_freeze() || is_freezeController()) {
 	/* フリーズ時のコントローラ入力のマスク */
	if(is_freezeController())
	    clrButton(CONTROLLER_FREEZE_BTN); // コントローラの全面入力禁止の時
#endif
	else
	    clrButton(PAUSE_FREEZE_BTN);
	clrJoystick_X();
	clrJoystick_Y();
    }

    /* コントローラからの入力を変換する */
    if(Game->inputProc)
	(*Game->inputProc)();	   
#if DEBUG
    memChkControl();	           // メモリーチェックのコントロール
#endif
}

/*
 ******************************************************************************
 *   (Z)バッファの有効/無効の設定
 ******************************************************************************
 */
static void *zBuffer = NULL;

/* (Z)バッファの有効化処理 */
void available_zBuff(void)
{
    if(zBuffer == NULL) {	//  4/8 komatu
	zBuffer = Malloc(SCREEN_WD * SCREEN_HT * 2 + 64);
	if(zBuffer == NULL) {
#if DEBUG
	    PRINTF(__ERROR"(Z)バッファの領域確保失敗。\n");
#endif
	    __STOP;
	}
	setP_ZBuffer((void *)to_64ByteAlign(zBuffer));
    }
}

/* (Z)バッファの初期化 */
static initial_zBuff(void)
{
    setP_ZBuffer(zBuffer = NULL);
    regist_zBuffer(getP_ZBuffer());
}

/* (Z)バッファの利用設定 */
/* (Z)バッファの無効化処理 */
void unavailable_zBuff(void)
{
    if(!zBuffer)
	return;
    Free(zBuffer);
    initial_zBuff();
}
/*
 ******************************************************************************
 *    登録された"表示後処理"を実行する
 ******************************************************************************
 */
/* "表示後処理"を登録する(登録できれば TRUE を返す) */
int regist_displayAfterProc(DSAFPC process, void *prm)
{
    t_dafp  dspAftPc_id = get_dspAftPc_id(getP_game());
    DAPETY  *dspAftPc;

    if(dspAftPc_id >= MAX_DSAFPROC) {
#if DEBUG
	PRINTF(__ERROR
	       "push_displayAfterProc():これ以上'表示後処理'を"
	       "登録できない!!\n");
#endif
	return FALSE;
    }
    dspAftPc = getP_dspAfterProcS(getP_game()) + (int)dspAftPc_id;
#if USE_CHECK_POINT
    if(!process) {
#if DEBUG
	PRINTF(__ERROR
	       "regist_displayAfterProc():processをNULLで登録できない!!\n");
#endif
	__STOP;
	return FALSE;
    }
#endif
    dspAftPc->process = process;
    dspAftPc->prm = prm;
    inc_dspAftPc_id(getP_game());
    return TRUE;
}
/* 登録された"表示後処理"を実行する */
static void displayAfterProc(GAME *Game)
{
    DAPETY  *dspAftPc;
    t_dafp  idspAftPc_id = get_dspAftPc_id(Game);
    t_dafp  i;
 
    if(!idspAftPc_id)
	return;
    dspAftPc = getP_dspAfterProcS(Game);
    for(i=0; i<idspAftPc_id; i++) {
	(*dspAftPc->process)(dspAftPc->prm);
	dspAftPc++;
    }
    reset_dspAftPc_id(Game);
}
/*
 ******************************************************************************
 *   表示処理
 ******************************************************************************
 */
#define NORMAL_DISPLAY               display_normal
#define NOWAITRCP_DISPLAY            display_no_rcpwait
/* 表示処理の初期化 */
#define initial_display(g)           off_display(g)
#define reset_display(g)             ((g)->display = NOWAITRCP_DISPLAY)
#define off_display(g)               ((g)->display = NOWAITRCP_DISPLAY)
#define is_display(g)                ((g)->display != NULL)
/* 標準表示する */
static void display_normal(GAME *Game)
{
    rcpwait();		                             // RCP待ち
    displayAfterProc(Game);	                     // 表示後処理
    wait_bgDMA(Game);		                     // 裏DMA待ち
    regist_zBuffer(getP_ZBuffer());                  // (Z)バッファの設定
    bgkick();
    bgwait();                                        // スプライトＬＩＢ待ち
}
/* RCP待ちを行わないで表示する。表示後,標準表示に戻す。*/
static void display_no_rcpwait(GAME *Game)
{
    regist_zBuffer(getP_ZBuffer());                  // (Z)バッファの設定
    bgkick();
    Game->display = NORMAL_DISPLAY;
    bgwait();                                        // スプライトLIB待ち
}

/*
 ******************************************************************************
 *    再スタート処理
 *
 *    再スタート処理は, 以下のシーケンスで行われる。
 *
 *    1. [前回処理の後始末]
 *    2. ワールドデータの読み込み
 *    3. [初期画面生成の前設定]
 *    4. [初期画面生成]
 *    5. [初期画面生成の後設定]
 *    -- 次フレームへ -- 
 *    6. [ゲーム処理]
 ******************************************************************************
*/
static void game_process(GAME *);

/*
 ******************************************************************************
 *    次処理からのゲームページ番号を変更する
 *    (変更できれば TRUE を返す。誕生エントリー, プールエントリーなどに未処理
 *   のエントリーがあれば FALSE を返しゲームページ番号は変更しない)
 ******************************************************************************
 */
int change_gamePage(void)
{
    if(get_birthEntry().entryCnt || get_poolEntry().entryCnt)
	return FALSE;

    if(get_gamePage() == GMPAGE_1)
	set_newGamePage(GMPAGE_2);
    else
	set_newGamePage(GMPAGE_1);
    return TRUE;
}

/*
 ******************************************************************************
 *   新ゲームページ番号で新しいゲームページを構築する
 ******************************************************************************
 */
static void construct_gamePage(int n)
{
    set_gamePage(n);
#if !WORLDMEM
    renew_worlddP();
#endif
    renew_viewP();
    renew_frameP();
    renew_castingListP();
    renew_activeEntryP();
    renew_crossEntryP();
    renew_heapEntryP();
    renew_nxgotoP();
    renew_pipeEntryP();
    renew_envDetailP();
}

#if USE_SLEEP_WAKEUP
/*
 ******************************************************************************
 *    シーン情報を"スリープ", "ウェークアップ"に設定する
 *    (元のシーンを残しながら新たなシーンを被せ, その後, 被せたシーンを消し
 *   元のシーンを再び復活させる処理の設定を行う。
 *     プールエントリー, 誕生エントリーの内容が, すべてアクティブエントリーに
 *   移行しているメイン処理の最後で実行すること)
 ******************************************************************************
 */
/* シーン情報を"スリープ"する
   ((*Game->deconstProc)(Game) [画面生成前の後始末処理] で実行される。*/
void sleep_sceneInfo(GAME *Game)
{
    // 現在のアクティブエントリーのアクターを全て"スリープ"に設定
#if 0
    PRINTF("#### スリープ ####\n");
#endif
#if 0
    PRINTF("--- スリープ前のメモリ ----\n");
    MEMORYCHAIN();
#endif
    sleepAll_ActorInEntry(ACTENTRYPp_P(Game));  // アクティブアクターをスリープ
    sleepAll_heapAreaList(HEAPENTRYPp_P(Game)); // 静的アクターをスリープ
    sleep_castingList(CASTLTPp_P(Game));        // キャスティングをスリープ
#if 0
    PRINTF("--- スリープ後のメモリ ----\n");
    MEMORYCHAIN();
#endif
}

/* シーン情報を"ウェークアップ"する
   ((*Game->const1Proc)(Game) [画面生成前の処理] で実行される) */
void wakeup_sceneInfo(GAME *Game)
{
#if 0
    PRINTF("#### ウェークアップ ####\n");
#endif
    reset_inputProc();                     // "入力"のリセット
    renew_gameMode();	                   // "現在のゲーム処理モード"の更新
    wakeup_castingList(CASTLTPp_P(Game));  // キャスティングをウェークアップ
                                           // 静的アクターをウェークアップ
    wakeupAll_heapAreaList(HEAPENTRYPp_P(Game));
    if(is_entrySleep(get_entryStatus(ACTENTRY_P(ACTORIFp_(Game)))))
                                           //アクティブアクターをウェークアップ
	wakeupAll_ActorInEntry(ACTENTRYPp_P(Game));
    refresh_scrInfo();		           // スクリーン情報のリフレッシュ
    redrawBgProc();	                   // 全てのBGを全面描画

#if 0
    MEMORYCHAIN();
#endif
}
#endif
/*
 ******************************************************************************
 *   シーン構築のための情報の設定と解放処理
 ******************************************************************************
 */
/* シーン情報の解放処理
   ((*Game->deconstProc)(Game) [画面生成前の後始末処理] で実行される) */
void deconst_sceneInfo(GAME *Game)
{
PRINTF("シーン情報の解放処理 +++++++++++ start\n");
    deconst_limitTimeProc();	           // 時限処理の解放
    freeAll_clipboardInfo(CLPBDIFp_P(Game));// クリップボード情報を解放
    setFactor_movementFrame(FRAMEPp_P(Game),
			    NULL,
			    NULL);         // フレーム移動処理を無効にする
    clear_crossEntry();                    // 1:衝突キャストを未登録にする
    freeAll_pipeEntry(PIPEINFp_P(Game));   // 2:パイプエントリー内容の解放
    freeAll_actorInfo(ACTORIFp_P(Game),
		      UNCOMPULSION_FREE);  // 3:アクター情報の解放
    freeAll_unjointGate(NXGTIFp_P(Game));  // 4:next-goto"出口"無し"入口"の解放
    free_heapAreaList();	           // 5:登録されているヒープ領域の解放
    free_castingList(CASTLTPp_P(Game));    // 6:キャスティングリストの解放
    clear_frameInfo(FRMINFp_P(Game));      // 7:フレーム情報のクリアー
#if !WORLDMEM
    free_world(WORLDp_P(WORLDDPp_P(Game)));// 8:ゲームワールド情報の解放
#endif
#if WORLDMEM
    freeAll_worldMemory(WRLDIFp_P(Game));  // 8:全てのワールド記憶の解放
#endif
PRINTF("シーン情報の解放処理 +++++++++++ end\n");
}

/* シーン構築のための情報の設定
   ((*Game->const1Proc)(Game) [画面生成前の処理] で実行される) */
#if (USE_CIC6104 || DEBUG_CIC)
    int __osCic6104_RamTest1_is_OK = 0;
    int __osCic6104_RamTest2_is_OK = 0;
#endif
void const_sceneInfo(GAME *Game)
{
#if (USE_CIC6104 || DEBUG_CIC)
    __osCic6104_RamTest1_is_OK = osCic6104_RamTest1_is_OK();
    __osCic6104_RamTest2_is_OK = osCic6104_RamTest2_is_OK();
#endif

PRINTF("シーン情報の生成処理 +++++++++++ start\n");
    reset_inputProc();                     // "入力"のリセット
    renew_gameMode();	                   // "現在のゲーム処理モード"の更新

    setup_clipboardInfo(CLPBDIFp_P(Game)); // 3:クリップボードの設定

    const1_worldInfo(WRLDIFp_P(Game));     // 1:ワールド情報の構築 １
    setup_warpInfo();			   // 4:ワープちゃん情報の設定
    const_castingList(CTLTIFp_P(Game),
		      getP_worlddP(),
		      NXGOTOPp_P(Game));   // 5:新規にキャスティングする 
    const2_worldInfo(WRLDIFp_P(Game));     // 1:ワールド情報の構築 ２
    setup_viewInfo(VIEWIFp_P(Game));       // 8:視点の設定
    setup_frameInfo(FRMINFp_P(Game),
		    getP_worlddP());       // 2:フレーム情報の設定

    setup_enviroInfo();	                   // 7:"環境"と"効果"の設定
    setup_actorInfo(ACTORIFp_P(Game));     // 9:アクター情報の設定
PRINTF("シーン情報の生成処理 +++++++++++ end\n");
}
/*
 ******************************************************************************
 *    ゲームの初期画面生成後の設定
 *    ([画面生成後の処理]:(*Game->const2Proc)(Game) で実行される)
 ******************************************************************************
*/
void init2_gameproc(GAME *Game)
{
    extern void controllerIsYoshi(GAME *);
    
    if(find_mainActor() && is_melt())
	// ヨッシーが誕生している場合
	controllerIsYoshi(Game);	// ゲームのコントロールをヨッシーにする
}

#if SOUND
/*
 ******************************************************************************
 *   ＢＧＭのセット
 ******************************************************************************
 */
static setup_BGM(void)
{
#if !SOUND_BGM_OFF
    static int curBGMcode = NA_SCENE_NULL;
    int  newBGMcode = (int)get_BGM_handle();
    int  cancelEvent = FALSE;

    Stop_sound_Ato();
    /* 新BGMの設定 */
    if(!is_continueBGM(newBGMcode) && (curBGMcode != newBGMcode)) {
#if 0
	if((curBGMcode == NA_SCENE_TRIAL) && (newBGMcode == NA_SCENE_MAP01))
	    // "プリクラ" → "ラッキーフルーツ"
	    cancelBGM = TRUE;
	else
#endif
	if(newBGMcode == NA_SCENE_SELECT) {
	    activeYsSoundProc();
	    cancelEvent = TRUE;
	}
	// 通常シーンのチェンジした場合
	sNa_SceneChange((NA_SCENE)newBGMcode);
	curBGMcode = newBGMcode;
    }
    else
	// 引き続き同じＢＧＭの場合
	sNa_SceneChange(NA_SCENE_NULL);
	
#endif
    if(get_ENV_event() && !cancelEvent)
	sNa_Event(get_ENV_event());               // イベント音の設定
    if(get_ENV_handle())
	sNa_SeStart(get_ENV_handle(), 0, NULL);   // 環境音の設定と開始
}
#endif
/*
 ******************************************************************************
 *   シーンの生成処理
 ******************************************************************************
 */
static int makeScene_process(GAME *Game)
{
    int  rt;
    
#if 0
    PRINTF("シーンの生成処理\n");
#endif
    inputProcess(Game);                       // 入力処理
    viewProc(VIEWPp_P(Game));                 // 視界・射影処理
    stageProc(FRAMEPp_P(Game));	              // ステージへの登場,退場処理
    rt = mkScene_actorProc(ACTORIFp_P(Game)); // アクターの生成処理
    setup_OAM(PRIENTRY_P(ACTORIFp_(Game)));   // OAMテーブルのセット
    return rt;
}
#if USE_CHECK_POINT
/*
 ******************************************************************************
 *   シーン変更前のヨッシーの状態をチェックする
 *   (チェック不良なら FALSE を返す)
 ******************************************************************************
 */
int checkYoshi(void)
{
#if 0
    ACTOR  *actor = getP_mainActor();
    
    if(!actor)
	return TRUE;
    /* ヨッシーが子アクターになっていないかチェックする */
    if(is_existParent(actor)) {
#if DEBUG
	PRINTF(__ERROR
	       "ヨッシーが子アクターのままシーンを変えようとしている!!"
	       "(parent=%x)\n", get_category(get_peActor(actor)->name));
	print_actvEntryList();
#endif
	__STOP;
	return FALSE;
    }
#endif
    return TRUE;
}
#endif
/*
 ******************************************************************************
 *   シーンの解体処理
 ******************************************************************************
 */
static void deconstruct_scene(GAME *Game)
{
#if 0
    PRINTF("シーンの解体処理\n");
#endif
#if USE_CHECK_POINT
    checkYoshi();		        // シーン変更前のヨッシーの状態チェック
#endif
    if(is_useBlackout())
	ForceBlackOn();	                // 画面をブラックアウトする
    use_blackout();		        // 画面のブラックアウト使用可能にする
    pousePermi_OFF();		        // 画面生成中はポーズを"禁止"に設定
#if FOR_EDITOR
    set_dbgPouse(OFF);		        // ポーズを解除する
#endif
    unavailable_zBuff();	        // (Z)バッファの使用を無効にする
#if VIBPACK // '97/11/6 heiho
    vib_stop();			        // 振動パックを停止する
#endif
#if SOUND
    if(sNa_SeLevelCheck(get_ENV_handle(), 0) == 1)
	sNa_SeStop(get_ENV_handle(), 0);// 環境音の停止
#endif
    set_keepFrame(1);		        // 処理フレームを1/1に再設定

    if(is_orgScene()) {
	// "電源投入時, ハードリセット"-->"NINTENDOロゴ"-->"タイトル"の時の処理
	initial_saveInfo();	        // EEPROMへのセーブ処理の初期化
	end_orgScene();
    }
    
    (*Game->deconstProc)(Game);         // [画面生成前の後始末処理]
}

/*
 ******************************************************************************
 *   シーンの構築処理 (最初のシーンを生成する)
 *   
 *    [ページ設定] → [画面生成の前処理] → [画面生成の処理]
 *     → [画面生成の後処理] → [表示処理のリセット]
 ******************************************************************************
 */
/* シーンの構築処理 フェーズ１
   (最初のシーン生成前の初期処理とBG1の生成を行う) */
static int constructScene_fase1(GAME *Game)
{
#if 0
    PRINTF("２ー１ シーンの構築処理 フェーズ１\n");
#endif
    newScene(MAKING_NOW_NEWSCENE);         // "新シーンを生成中"を設定
    construct_gamePage(get_newGamePage()); // 新ページの設定
    (*Game->const1Proc)(Game);             // [画面生成の前処理]
    clr_BgDrawSignal();		           // BGの描画シグナルをクリアーする
#if SOUND
    setup_BGM();                           // 新BGMの設定
#endif
    makeScene_process(Game);               // シーンの生成処理
    return TRUE;
}
/* シーンの構築処理 フェーズ２ (BG2,BG3とOBJの生成を行う) */
static int constructScene_fase2(GAME *Game)
{
#if 0
    PRINTF("２ー２ シーンの構築処理 フェーズ２\n");
#endif
    return makeScene_process(Game);        // シーンの生成処理
}
/* シーンの構築のメイン処理
    (フェーズ１〜フェーズ３までの処理をコントロールしている。
   完了すれば TRUE を返す) */
#define CONST_SCENE_FASE_NUM              (sizeof(process) / sizeof(SGPROC))
static int construct_scene(GAME *Game)
{
    static int     fase = 0;
    static SGPROC  process[] = {constructScene_fase1, constructScene_fase2};
    int    rt;

#if 0
    PRINTF("２ シーンの構築のメイン処理\n");
#endif
#if DEBUG
    PRINTF("シーンの構築処理 ==================== start-fase %d \n", fase);
#endif
    rt = (*process[fase])(Game);
    if(!rt)
	return FALSE;
    if(++fase < (int)CONST_SCENE_FASE_NUM)
	return FALSE;
    (*Game->const2Proc)(Game);             // [画面生成の後処理]
    fase = 0;
    newScene(MAKING_COMPLETE_NEWSCENE);    // "新シーンを生成完了"を設定
#if DEBUG
    PRINTF("シーンの構築処理 ==================== end \n");
#endif
    return TRUE;
}
/*
 ******************************************************************************
 *    再スタート処理
 *    (シーンを再生成するときのメイン処理)
 *
 *    [シーンの解体処理] → [シーンの構築処理]
 ******************************************************************************
 */
/* 再スタート処理のフェーズ１
   (メモリー解放と初期化を行った後, BG1の生成を開始する) */
static int restartProc_fase1(GAME *Game)
{
#if 0
    PRINTF("１ー１ 再スタート処理のフェーズ１\n");
#endif
#if DEBUG
    PRINTF("********** 再スタート処理 ***********\n");
#endif
    rcpwait();                          // 全てのRCP処理の完了を待つ
    deconstruct_scene(Game);            // シーンの解体処理(及びBGMの停止)
#if DEBUG
    INITIAL_ACCESSPOINT;

    PRINTF("************* 次処理の設定前のエントリー状態 ***********\n");
    BthPoolActDie_entry();
    PRINTF("********************************************************\n");
    PRINTF("************* 次処理の設定前のＯＡＭ状態 ***************\n");
    useOAM_list();
    PRINTF("********************************************************\n");
    PRINTF("************* 次処理の設定前のメモリー状態 *************\n");
//    CHECK_MALLOC();
    PRINT_MALLOCMSG;
//    PRINT_MARK_UNFREEPOINT();
    MEMORYCHAIN();
    PRINTF("********************************************************\n");
#endif
    reset_display(Game);	        // 表示処理のリセット

    construct_scene(Game);              // シーンの構築処理
    return FALSE;
}
/* 再スタート処理のフェーズ２
   (BG2,BG3とOBJの生成を行う。処理が完了すれば TRUE を返す) */
static int restartProc_fase2(GAME *Game)
{
#if 0
    PRINTF("１ー２ 再スタート処理のフェーズ２\n");
#endif
    if(!construct_scene(Game))	        // シーンの構築処理
	return FALSE;
    if(is_playGame() && !is_exerciseMode())
	pousePermi_ON();	        // ゲーム中はポーズを受け付ける
    else
	pousePermi_OFF();
    ForceBlackOff();                    // 画面のブラックアウトを解除する
#if DEBUG
    PRINTF("********** 再スタート処理完了 ***********\n");
#endif
    return TRUE;
}
/* 再スタートのメイン処理
   (再スタートの前処理(フェーズ１) 〜 再スタートの後処理(フェーズ２)を行う) */
#define RESTART_FASE_STEP   (sizeof(process) / sizeof(GMPROC))
static void restart_process(GAME *Game)
{
    static SGPROC process = restartProc_fase2;

#if 0
    PRINTF("１ 再スタートのメイン\n");
#endif
#if USE_SUPER_FREEZE
    inputProcess(Game);                // 入力処理
    if(is_spFreeze())
	return;
#endif
    if(!(*process)(Game)) {
	process = restartProc_fase2;
	return;
    }
    // 通常処理への移行
    process = restartProc_fase1;
    Game->process = game_process;
    return;
}
/*
 ******************************************************************************
 *     再スタートのための設定
 ******************************************************************************
 */
void set_restart(GMPROC dcProc, GMPROC fcProc, GMPROC ncProc)
{
    get_game().process = restart_process;
    get_game().deconstProc = dcProc;
    get_game().const1Proc = fcProc;
    get_game().const2Proc = ncProc;
}
void setAll_restart(GMPROC dcProc, GMPROC fcProc, GMPROC ncProc)
{
    get_game().actorInfo.process = activeEntryProc;
    set_restart(dcProc, fcProc, ncProc);
}
/*
 ******************************************************************************
 *    開発のための処理
 ******************************************************************************
 */
void subresetGame(void)
{
    INIT_playCourseNo();
    clr_warpInfo();		          // ワープ情報をクリアーする
    offAll_protectWorld();	          // ワールド記憶を忘れる

    /* スコア関係のクリア */
    set_smileScore(0);
    set_enmyScore(0);
    set_flowerScore(0);
    set_starScore(0);
    set_luckyScore(0);
    set_smileScoreSv(0);
    set_enmyScoreSv(0);
    set_flowerScoreSv(0);
    set_starScoreSv(0);
    set_luckyScoreSv(0);

    /* フルーツメーターのクリア */
    set_lampItemSum(0);
    set_lampItemSumSv(0);
}
/*
 ******************************************************************************
 *    
 *     ゲーム処理
 *   
 ******************************************************************************
 */
#if DEBUG
/*
 ******************************************************************************
 *    開発のための処理
 ******************************************************************************
 */
static void developProc(void)
{
    static size_t  areaSize;

    if(cdbg_chkButton(Z_BTN) && cdbg_chkTrigger(D_BTN))
	BthPoolActDie_entry();
    if(cdbg_chkButton(Z_BTN) && cdbg_chkTrigger(C_BTN))
	dynamicActorList();
    if(cdbg_chkButton(Z_BTN) && cdbg_chkTrigger(B_BTN)) {
        MEMORYCHAIN();
	PRINT_MALLOCMSG;
    }
    CHECK_MALLOC();		            // メモリー領域のチェック
}
#endif
/*
 ******************************************************************************
 *    ゲームのメイン処理
 *    (Game->processに登録され実行される)
 ******************************************************************************
 */
static void game_process(GAME *Game)
{
    FRAME  *Frame = FRAMEPp_P(Game);
    
//PRINTF("ゲームのメイン処理 start -----------------------------\n");
    clr_BgDrawSignal();		            // BGの描画シグナルをクリアーする
    inputProcess(Game);                     // 入力処理

#ifdef USE_SUPER_FREEZE
    if(is_spFreeze()) {
	setup_OAM(PRIENTRY_P(ACTORIFp_(Game))); // OAMテーブルのセット
	return;
    }
#endif

    if(!is_pouse()) {
	viewProc(VIEWPp_P(Game));           // 視界・射影処理
	frameProc(Frame);                   // フレーム移動処理 
    }
    stageProc(Frame);	                    // ステージへの登場,退場処理
    actorProc(ACTORIFp_P(Game));            // アクターの処理
    setup_OAM(PRIENTRY_P(ACTORIFp_(Game))); // OAMテーブルのセット

    limitTimeProc();	                    // 時限処理
    exceptionProc(Game);	            // 例外処理(必ず最後にあること)
//PRINTF("ゲームのメイン処理 end -----------------------------\n");
}
/*
 ******************************************************************************
 *    メインループ処理  
 *    (Game->processに下記のいずれかが登録され, メイン処理として実行される。
 *     setAll_restart() : 再スタート処理 
 *     game_process()   : ゲーム処理)
 ******************************************************************************
 */
static void process(void)
{
    void   change_OAM(void);

    performanceSwitch(NORMAL);
#if TIME
    AddLoadGraph();
#endif
    while(TRUE) {
//	PRINTF("========= メインループ start ========\n");
#if 0 //DEBUG
	musicPouse();
#endif
	(*get_game().process)(getP_game());     // 処理
#if VIBPACK
	if( !is_SHOPDEMO(get_gameMode()) )	/* 店頭デモプレイ？ */
	    vib_ctrl(is_pause());		// 振動パック処理
#endif
#if USE_SUPER_FREEZE
	if(!is_spFreeze())
#endif
	    frameCount();
#if CHK_SOUND_HEAP
	check_area(SOUND_HEAP, SOUND_HEAP_SIZE, SOUND_MAGIC_CODE);
#endif
#if DEBUG
	developProc();
#endif
#if TIME
	timerProc1();
#endif
#if SOUND
	sNa_GameFrameWork();	                // サウンド処理 
#endif
#if TIME
	timerProc2();
#endif
	if(is_display(getP_game())) {
	    (*get_game().display)(getP_game());
	    change_OAM();	               // OAMの切り替え
	}
#if DEBUG
	PRINT_ACCESSPOINT;
#endif
//	PRINTF("========= メインループ end ========\n");
    }
}
/*
 ******************************************************************************
 *   初期処理
 *   (システムのブート時に実行される処理)
 ******************************************************************************
 */
/* ゲーム情報の初期化 */
static GAME *initial_GAME(void)
{
    clearArea_s(getP_game(), sizeof(GAME));
    start_orgScene();
    return getP_game();
}
/* 初期処理 */
void Grou_camdemo_init(void);
static void initial(void)
{
    GAME  *Game = initial_GAME();
    
#if DEBUG
    INITIAL_ACCESSPOINT;
#endif
    initial_Malloc();		              // メモリ管理の初期化
#if DEBUG
    Tester_of_malloc();		              // Malloc() Free() テスター
#endif
    initialSystem(Game);                      // システムの初期化
#if CHK_SOUND_HEAP
    initial_check_area(SOUND_HEAP, SOUND_HEAP_SIZE, SOUND_MAGIC_CODE);
#endif
    initial_random_i(1);	              // 整数乱数生成の初期化
    initial_random_d(1);	              // 小数乱数生成の初期化

    initial_dmaInfo(Game);	              // DMA情報領域の初期化
    initial_Controller(Game);                 // コントローラの初期化
#if EEPROM_TEST
    test_eeprom();
#endif
#if DEBUG && SYS_GATEWAY_N64
    SRAMAccessTest();
#endif
    initial_zBuff();	                      // (Z)バッファの初期化
    initial_viewInfo(VIEWIFp_P(Game));        // 射影情報と視点の初期化
    initial_castingListInfo(CTLTIFp_P(Game)); // キャスティングの初期化
    initial_romAccessRecord();	              // "ROMアクセス記録"の初期化
    initial_frameInfo(FRMINFp_P(Game));       // フレームの初期化
    initial_actorInfo(ACTORIFp_P(Game));      // エントリーの初期化
    initial_worldInfo(WRLDIFp_P(Game));       // ワールド情報領域の初期化
    initial_pipeInfo(PIPEINFp_P(Game));       // パイプ情報領域の初期化
    initial_nextgotoInfo(NXGTIFp_P(Game));    // "Next-goto"情報領域の初期化
    initial_OAM(Game);                        // OAMの初期化
    initial_display(Game);	              // 表示処理の初期化
    initial_clipboardInfo(CLPBDIFp_P(Game));  // クリップボード情報の初期化
    initial_warpInfo();		              // ワープ情報の初期化
#if CAMERA_DEBUG
    Grou_camdemo_init();	              // demo camera initial routine
#endif
#if DEBUG
    PRINTF("************* デフォルトのメモリー状態 *************\n");
    PRINT_MALLOCMSG;
    PRINTF("****************************************************\n");
    MALLOCMARK_ON
#endif
#if SOUND
    s_audio_timer_enable();
#endif
    reset_frameCnt();                  // フレームカウンターのリセット
    set_newGamePage(GMPAGE_1);
    nextTo_titleScene(NINTENDO_ROGO);  // ニンテンドウ ロゴシーンへの移行設定
    restart_process(Game);	       // 最初のシーンを作る(シーンの構築処理)
}

/*
 ******************************************************************************
 *   メイン処理  
 ******************************************************************************
*/
#if DEBUG
enum {
//    REG_BGBG_TEST8 = REG_BG_BG_BEGIN,
    REG_BGBG_TEST8 = REG_BG_BG_DRAW_BEGIN+4,
    REG_BGBG_MAX
};
#endif /* USE_DEBUGMODE */

void mainproc(void *ptr)
{
    (void)ptr;
#if USE_FAULT
    DbStartDebugger();
#if FOR_PARTNER
    DbSetPartnerDebug();
#endif
#if DISABLE_FAULT_DISPLAY
    DbSetDisplayDisable();	/* 落ちたときに画面に情報を表示しない */
#endif
#endif
    initial();
#if DEBUG
    SETREG(BGBG_TEST8, 1);
#endif
    process();
}
