/*
 ******************************************************************************
 * 	File :		m_immig.c
 *  	Programer :	Gentaro Takaki
 *
 *	 入出国管理ファイル
 *  
 *	$Id: m_immig.c,v 1.1 2004/03/02 01:30:26 tong Exp $
 ******************************************************************************
*/

#include "m_immig.h"
#include "m_flashrom.h"
#include "m_cpak.h"
#include "m_land.h"
#include "m_immig.h"
#include "m_private.h"
#include "m_font.h"
#include "assert64.h"
#include "m_start_data_init.h"
#include "m_cockroach.h"
#include "m_mail.h"
#include "m_nmibuf.h"           /* M_APPNMI_* */
#include "sys_gmalloc.h"
#include "m_malloc.h"

#ifdef BBPLAYER
extern u32 bbRTC_delta_minutes;
extern int bbRTC_delta_sign;
#endif

enum	mimm_start_data_init_mode{
    mImm_SDI_MODE_INIT_e,		/** 開始データセット */
    mImm_SDI_MODE_SAVE_INIT_e,		/** リセット魔神用セーブ前処理 */
    mImm_SDI_MODE_SAVE_MAIN_INIT_e,	/** リセット魔神用セーブ前処理 */
    mImm_SDI_MODE_SAVE_CHKSUM_e,	/** リセット魔神用セーブ前処理 */
    
    mImm_SDI_MODE_SAVE_MAIN_e,		/** リセット魔神用セーブ前処理 */
    mImm_SDI_MODE_SAVE_PACK_e,		/** リセット魔神用セーブ前処理 */
    mImm_SDI_MODE_SAVE_BACKUP_e,	/** リセット魔神用セーブ前処理 */
    mImm_SDI_MODE_LOAD_BACKUP_e,	/** リセット魔神用セーブ前処理 */
    mImm_SDI_MODE_RESAVE_MAIN_e,	/** リセット魔神用セーブ前処理 */
//    mImm_SDI_MODE_SAVE_e,		/** リセット魔神用セーブ処理 */
    mImm_SDI_MODE_AFTER_e,		/** スタート後処理 */
    
    mImm_SDI_MODE_END_e
};
/** ゲーム開始時のデータセット処理型 */
typedef int	(* mImm_INIT_PROC)( int , int , int, u32 **, int * );
/** ゲーム開始時のデータのロード & 初期化 & セーブ処理モード */
static int	l_mimm_start_mode = mImm_SDI_MODE_INIT_e;

enum	mimm_save_mode{
    mImm_SAVE_MODE_INIT_e,		/** セーブ前処理 */
    
    mImm_SAVE_MODE_MAIN_INIT_e,		/** セーブ処理 */
    mImm_SAVE_MODE_CHECKSUM_e,		/** セーブ処理 */
    mImm_SAVE_MODE_SAVE_MAIN_e,		/** セーブ処理 */
    mImm_SAVE_MODE_SAVE_PACK_e,		/** セーブ処理 */
    mImm_SAVE_MODE_SAVE_BACKUP_e,	/** セーブ処理 */
    mImm_SAVE_MODE_LOAD_BACKUP_e,	/** セーブ処理 */
    mImm_SAVE_MODE_RESAVE_MAIN_e,	/** セーブ処理 */
    
    mImm_SAVE_MODE_AFTER_e,		/** 後始末 */
    
    mImm_SAVE_MODE_END_e
};
typedef struct	privaet_keep_item {
    mAc_nfs_t		itemNo[ITEM_POSSESS_NUM];
    unchar		ticket_expiration;	/* 福引の賞味期限 */
    unchar		ticket_remain;		/* 渡しきれていない福引の数 */
    unint		item_cond;		/* アイテムの状態 */
    money_t		money;			/* 所持金 */
    mQst_dlv_c		delivery[DELIVERY_QUEST_MAX];	/** 配達クエスト */
    mQst_erd_c		errand[ERRAND_QUEST_MAX];	/** お使いクエスト */
    Mail_c		mail[MAIL_POSSESS_NUM];		/* お手紙 */
    mPr_sftr_c		shop_ftr[SHOP_FTR_ORDER_MAX];	/** 注文家具 */
} mImm_kpr_c;
/** セーブ時の処理型 */
typedef int	(* mImm_SAVE_PROC)( int , int , Private_c *, mImm_kpr_c *, int *, u32 ** );

/** セーブ時の処理モード */
static int	l_mimm_save_mode = mImm_SAVE_MODE_INIT_e;


enum	mimm_save_pak_mode {
    mImm_SAVE_PAK_ERASE_e,
    mImm_SAVE_PAK_SAVE_e = mImm_SAVE_PAK_ERASE_e,
    mImm_SAVE_PAK_NO_e,
    
    mImm_SAVE_PAK_END_e
};



/** スタートデータ組み合わせパターン */
static int	l_start_comb = mImm_DATA_COMB_0_e;
/** スタートデータカテゴリー */
static int	l_start_dt_ct = mImm_SVLD_CT_NOT_e;

/** */
static int	l_mimm_malloc_time = 0;


/*
 ****************************************************************
 *	最後の登録プレーヤーの名前取得
 *
 *	in	:	なし
 *
 *	out	:	最後の登録プレーヤーの名前取得
 *			PERSON_NAME_NUM分のサイズが必要
 *
 *	返り値	:	なし
 ****************************************************************
 */
extern void mImm_GetLastRegistPlayerName(
    unchar	*last_player_name_p
    ){
    
    static unchar	debug_player_name[PERSON_NAME_NUM] = {
	MOJI_TA, MOJI_YA, MOJI_SU, MOJI_TU, MOJI_YO, MOJI_SI,
    };

    mPr_CopyPlayerName( last_player_name_p, debug_player_name );
}


/*
 ------------------------------------------------------------------------------
 *			リセット魔神
 ------------------------------------------------------------------------------
 */
#define	mImm_RESET_CODE_MAX_F		((float)(0x0000ffff))
#define	mImm_RESET_MAX			(4)
/*
 ****************************************************************
 *	リセットコードクリア
 ****************************************************************
 */
static void mImm_ClearResetCode( void ){

    Private_c	*private_p = ZCommonGet(now_private);

#if	DEBUG
    assert(private_p);
#endif	/** DEBUG end */

    bzero( &(private_p->reset_code), sizeof(unint));
}

/*
 ****************************************************************
 *	リセットコードセット
 ****************************************************************
 */
static void mImm_SetResetCode(
    Private_c	*private_p
    ){

#if	DEBUG
    assert(private_p);
#endif	/** DEBUG end */
    private_p->reset_code = (unint)(mImm_RESET_CODE_MAX_F * rnd( ));
    (private_p->reset_code)++;
}

/*
 ****************************************************************
 *	リセットコードチェック
 *
 *	正常終了	TRUE
 *	異常終了	FALSE
 ****************************************************************
 */
static int mImm_CheckResetCode(
    Private_c	*private_p
    ){

    int		ret = TRUE;
#if	DEBUG
    assert(private_p);
#endif	/** DEBUG end */
#if	defined(U_gen_U)
    PRINTF("check reset code : %#010x\n",private_p->reset_code);
#endif	/** defined(U_gen_U) */
    if( private_p->reset_code != 0 ){
	ret = FALSE;
    }
    return ret;
}

/*
 ****************************************************************
 *	プレーヤーリセット情報のセット
 ****************************************************************
 */
static  void mImm_SetResetInfo(
    Private_c	*private_p
    ){

    /*
     * 前回正常に終了していなければリセット処理
     * ハングアップなどによるリセットでは処理しない
     */
    if(( mImm_CheckResetCode( private_p ) == FALSE ) &&
       ( mFRm_GetRepair( ) == OFF ) &&
       !(M_APPNMI_TST_ILGRESET1( ))){
#if	defined(U_gen_U)
	PRINTF("りせっとさ〜〜〜〜〜ん now count : %d\n",private_p->reset);
#endif	/** defined(U_gen_U) end */
	/** リセットフラグセット */
	ZCommonSet(reset_flag, ON);
	(private_p->reset)++;
    }
}

/*
 ****************************************************************
 *	開始時のデータのロード & 初期化 & セーブモード初期化
 ****************************************************************
 */
extern void mImm_InitGameStart_init( void ){
    
    l_mimm_start_mode = mImm_SDI_MODE_INIT_e;
    l_mimm_malloc_time = 0;
}

/*
 ****************************************************************
 *	初期化
 ****************************************************************
 */
static void mImm_InitGameStart_cleanup(
    u32		**buf_p
    ){
    
    mFRm_ClearRepair( );
    mImm_InitGameStart_init( );
    if((*buf_p) != NULL ){
	sys_gmalloc_free((*buf_p));
    }
}

/*
 ****************************************************************
 *	ゲーム開始時のデータのロード & 初期化
 ****************************************************************
 */
static int mImm_InitGameStart_data_init(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){


    GAME		*game_p = getP_game( );
    PersonalID_c	*pID_p;
    int			ret = FALSE;
    int			fin = OFF;
    int			init_mode = mSDI_INIT_MD_NEW_e;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN
	   "ゲーム開始データ初期化開始......................................\n"
	   ESC_NORMAL);
    PRINTF(ESC_RED"mode category : %d\n"ESC_NORMAL,mode_category);
    PRINTF(ESC_RED"player no : %d\n"ESC_NORMAL,player_no);
#endif
    (*buf_p) = NULL;

    if( l_mimm_malloc_time < 150 ){
	(*buf_p) =
	    (u32 *)sys_gmalloc_malloc_nowait(ALIGNMENT_128(sizeof(Save_c)));
	if((*buf_p) != NULL ){
#if	DEBUG
	    PRINTF(ESC_CYAN"セーブ用領域確保成功 : %#010x"
		   ESC_NORMAL,ALIGNMENT_128(sizeof(Save_c)));
#endif	/** DEBUG end */
	    switch( mode_category ){
	    case mImm_SVLD_CT_NOT_e:	/** 一番始め */
		init_mode = mSDI_INIT_MD_NEW_e;
		l_mimm_start_mode = mImm_SDI_MODE_END_e;
		fin = ON;
		break;
	    case mImm_SVLD_CT_FLASH_e:
#if	DEBUG
		if( player_no >= COMPATRIOT_PLAYER_NUM ){
		    assert(0);
		}
#endif
		pID_p = SaveGetP(privateInfo[player_no].pID);
	    
		if( mPr_NullCheckPersonalID( pID_p ) == TRUE ){
		    fin = ON;
		    init_mode = mSDI_INIT_MD_NEW_PLAYER_e;
		    l_mimm_start_mode = mImm_SDI_MODE_END_e;
		} else {
		    init_mode = mSDI_INIT_MD_FROM_e;
		}
		break;
	    case mImm_SVLD_CT_GB_e:
#if	DEBUG
		init_mode = mSDI_INIT_MD_NEW_e;
#endif
		l_mimm_start_mode = mImm_SDI_MODE_END_e;
		fin = ON;
		break;
	    case mImm_SVLD_CT_CPAK_e:
		init_mode = mSDI_INIT_MD_PAK_e;
		break;
	    default :
		break;
	    }
	    /** ゲーム初期データセット */
	    ret = mSDI_StartDataInit( game_p, player_no, init_mode );
	    if(( fin == OFF ) && ( ret == TRUE )){
		ret = FALSE;
	    }
#if	defined(U_gen_U)
	    else {
		PRINTF(ESC_ERROR"初期キャラかエラー fin : %d ret : %d\n"ESC_NORMAL,fin,ret);
	    }
#endif	/** defined(U_gen_U) end */
	    l_mimm_malloc_time = 0;
	    /** モードの切り替え */
	    l_mimm_start_mode = mImm_SDI_MODE_SAVE_INIT_e;
	} else {
	    (l_mimm_malloc_time)++;
	}
    } else {
#if	defined(U_gen_U)
	PRINTF(ESC_ERROR"マロック出来ませんでした\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
	ret = TRUE;
	l_mimm_malloc_time = 0;
    }
    l_start_comb = start_comb;
    l_start_dt_ct = mode_category;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	リセット魔神用セーブ前処理
 ****************************************************************
 */
static int mImm_InitGameStart_before_save(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){

    mCPk_pkinfo_c	*pak_info_p = mCPk_get_pkinfo( );
    Private_c		*private_p;
    int			rec;
    int			ret = FALSE;
    
#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_InitGameStart_before_save : リセット魔神用セーブ前処理 : %d mode_category : %d"
	   " ........................\n"
	   ESC_NORMAL,player_no,mode_category );
#endif	/** defined(U_gen_U) end */
    (*pak_mode) = mImm_SAVE_PAK_NO_e;
    if((*buf_p) == NULL ){
	return TRUE;
    }
    switch( mode_category ){
	case mImm_SVLD_CT_FLASH_e:
#if	DEBUG
	    if( player_no >= COMPATRIOT_PLAYER_NUM ){
		assert(0);
	    }
#endif
	    private_p = SaveGetP(privateInfo[player_no]);
	    
	    if( mPr_NullCheckPersonalID(&(private_p->pID)) == FALSE ){
		/** プレーヤーリセット情報のセット */
		mImm_SetResetInfo( private_p );
		/** リセット魔神コードセット */
		mImm_SetResetCode( private_p );
		/** ハニワ顔であればいったん不在に */
		if( ZCommonGet(player_decoy) == TRUE ){
		    private_p->exist = 0;
		}
	    } else {
		ret = TRUE;
	    }
	    break;
	case mImm_SVLD_CT_CPAK_e:
	    rec = mCPk_PakOpen( pak_info_p, 0 );
	    if( rec == 1 ){
		if( mLd_PlayerManKindCheckNo((unchar)player_no ) == NATIVE_e ){
		    private_p = ZCommonGet(now_private);
		    if( private_p != NULL ){
#if	defined(U_gen_U)
			PRINTF(ESC_RED"リセット情報セット\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
			/** プレーヤーリセット情報のセット */
			mImm_SetResetInfo( private_p );
			/** リセット魔神コードセット */
			mImm_SetResetCode( private_p );
		    }
		    (*pak_mode) = mImm_SAVE_PAK_ERASE_e;
		} else {
		    private_p = mCPk_GetSaveFilePrivateP( );
		    if( private_p != NULL ){
#if	defined(U_gen_U)
			PRINTF(ESC_RED"パックリセット情報セット\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
			/** プレーヤーリセット情報のセット */
			mImm_SetResetInfo( private_p );
#if	defined(U_gen_U)
			PRINTF(ESC_MAZENTA" reset count : %d\n"ESC_NORMAL,
			       private_p->reset);
#endif	/** defined(U_gen_U) end  */
			/** リセット魔神コードセット */
			mImm_SetResetCode( private_p );
		    }
		    private_p = ZCommonGet(now_private);
		    if( private_p != NULL ){
#if	defined(U_gen_U)
			PRINTF(ESC_RED"パックリセット情報セット\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
			/** プレーヤーリセット情報のセット */
			mImm_SetResetInfo( private_p );
#if	defined(U_gen_U)
			PRINTF(ESC_MAZENTA" reset count : %d\n"ESC_NORMAL,
			       private_p->reset);
#endif	/** defined(U_gen_U) end  */
			/** リセット魔神コードセット */
			mImm_SetResetCode( private_p );
		    }
		    /** パックデータコピープロテクトセット */
		    rec = mCPk_SetPakCopyProtect( pak_info_p );
		}
		if( rec == FALSE ){
		    ret = -2;
		}
	    } else {
		ret = -1;
	    }
	    break;
	default :
	    ret = TRUE;
	    break;
    }
    l_mimm_start_mode = mImm_SDI_MODE_SAVE_MAIN_INIT_e;
    (void)start_comb;
    return ret;
}

/*
 ****************************************************************
 *	リセット魔神用セーブ処理	メインデータセーブ
 ****************************************************************
 */
static int mImm_InitGameStart_main_init(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_InitGameStart_main_init\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */

    mFRm_ClearRepair( );
    if((*buf_p) != NULL ){
	bcopy( ZCommonGetP(save.data[0]), (*buf_p),
	       ALIGNMENT_128(sizeof(Save_c)));
#if	DEBUG
	PRINTF("バッファのコピー成功\n");
#endif	/** DEBUG end */
    }
#if	DEBUG
    else {
	PRINTF(ESC_ERROR"バッファがありません\n"ESC_NORMAL);
    }
#endif	/** DEBUG end */
    l_mimm_start_mode = mImm_SDI_MODE_SAVE_CHKSUM_e;
    (void)mode_category;
    (void)start_comb;
    (void)player_no;
    (void)pak_mode;
    
    return FALSE;
}

/*
 ****************************************************************
 *	リセット魔神用セーブ処理	チェックサム
 ****************************************************************
 */
static int mImm_InitGameStart_checksum(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){

    Save_c	*save_p;
    unshort	check_sum;
    int		ret = FALSE;

    if((*buf_p) != NULL ){
	save_p = (Save_c *)(*buf_p);
	/** 書き込みバッファのセット */
	/* 2000.11.16 M.Sasaki Add	*/
	/* バージョンセット		*/
	save_p->save_check.version = mFRm_FLROM_VERSION;
	/** セーブチェックデータのセット */
	mFRm_SetSaveCheckData( &(save_p->save_check));
#if	DEBUG
	save_p->saved_rom_d = ON;
	/** 時間の設定 */
	lbRTC_TimeCopy( &(save_p->debug_time), ZCommonGetP(time.rtcTime));
#endif	/** DEBUG end */
	/** チェックサムのセット */
	check_sum = mFRm_GetFlatCheckSum((unshort *)save_p,
					 ALIGNMENT_128(sizeof(Save_c)),
					 save_p->save_check.check_sum );
#if	defined(U_gen_U)
	PRINTF(ESC_RED
	       "チェックサム計算後のチェックサム %#010x %#010x-------------\n"
	       ESC_NORMAL,
	       check_sum,
	       mFRm_ReturnCheckSum((unshort *)save_p,
				   (int)ALIGNMENT_128(sizeof(Save_c))));
#endif	/** defined(U_gen_U) end */
	save_p->save_check.check_sum = check_sum;
#if	defined(U_gen_U)
	PRINTF(ESC_RED
	       "チェックサム計算後のチェックサム %#010x --------------------\n"
	   ESC_NORMAL,mFRm_ReturnCheckSum((unshort *)save_p,
					  (int)ALIGNMENT_128(sizeof(Save_c))));
#endif	/** defined(U_gen_U) end */
    } else {
	ret = TRUE;
    }
    l_mimm_start_mode = mImm_SDI_MODE_SAVE_MAIN_e;
    (void)mode_category;
    (void)start_comb;
    (void)player_no;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	リセット魔神用セーブ処理	メインデータセーブ
 ****************************************************************
 */
static int mImm_InitGameStart_main(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){

    int		rec;
    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_InitGameStart_main\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    if((*buf_p) != NULL ){
	rec = mFRm_WriteHalfFlash_bg((*buf_p), 0 );
	if( rec == TRUE ){
#if	defined(U_gen_U)
	    PRINTF("\nメイン書き込み終了 -----------------------------\n\n");
#endif	/** defined(U_gen_U) end */
	    mFRm_ClearRepair( );
	    l_mimm_start_mode = mImm_SDI_MODE_SAVE_PACK_e;
	} else if( rec == -1 ){
	    ret = TRUE;
	}
    } else {
	ret = TRUE;
    }
    (void)mode_category;
    (void)start_comb;
    (void)player_no;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	リセット魔神用セーブ処理	パックセーブ
 ****************************************************************
 */
static int mImm_InitGameStart_pak(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){

    int		rec = 1;
    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_InitGameStart_pak\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    switch((*pak_mode)){
	case mImm_SAVE_PAK_ERASE_e :		/** パック内データの消去 */
#if	defined(U_gen_U)
	    PRINTF(ESC_YELLOW"パック内データの消去\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
	    /** パック内のプレーヤー情報クリア */
	    rec = mCPk_EraseForestData( );
	    break;
	default :
#if	defined(U_gen_U)
	    PRINTF("パックなにもしません\n");
#endif	/** defined(U_gen_U) end */
	    break;
    }
    if( rec != 1 ){
#if	defined(U_gen_U)
	PRINTF(ESC_ERROR"パックエラー   バックアップからの復帰\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
	l_mimm_start_mode = mImm_SDI_MODE_LOAD_BACKUP_e;
    } else {
	l_mimm_start_mode = mImm_SDI_MODE_SAVE_BACKUP_e;
    }
    (void)mode_category;
    (void)start_comb;
    (void)player_no;
    (void)pak_mode;
    (void)buf_p;
    return ret;
}

/*
 ****************************************************************
 *	リセット魔神用セーブ処理	バックアップデータセーブ
 ****************************************************************
 */
static int mImm_InitGameStart_backup(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){

    int		rec;
    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_InitGameStart_backup\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */

    if((*buf_p) != NULL ){
	rec = mFRm_WriteHalfFlash_bg((*buf_p), 1 );
	if( rec == TRUE ){
#if	defined(U_gen_U)
	    PRINTF("\nバック書き込み終了 -----------------------------\n\n");
#endif	/** defined(U_gen_U) end */
	    mFRm_ClearRepair( );
	    l_mimm_start_mode = mImm_SDI_MODE_AFTER_e;
	} else if( rec == -1 ){
	    ret = TRUE;
	}
    } else {
	ret = TRUE;
    }
    (void)mode_category;
    (void)start_comb;
    (void)player_no;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	バックアップからのデータの読み込み
 ****************************************************************
 */
static int mImm_InitGameStart_load_back(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){

    Save_c	*save_p;
    unshort	check_sum;
    int		ret = FALSE;
    int		rec;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_InitGameStart_load_back\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    rec = mFRm_FlashLoadAllData_common((*buf_p), mFRm_BACKUP_START_PAGE_NO );
    if( rec == TRUE ){
	check_sum = mFRm_ReturnCheckSum((unshort *)(*buf_p),
					(int)ALIGNMENT_128(sizeof(Save_c)));
	if( check_sum == 0 ){
	    save_p = (Save_c *)(*buf_p);
	    if( mFRm_CheckSaveData_ID(&(save_p->save_check)) == TRUE ){
		mFRm_ClearRepair( );
		l_mimm_start_mode = mImm_SDI_MODE_RESAVE_MAIN_e;
	    } else {
		ret = TRUE;
	    }
	} else {
	    ret = TRUE;
	}
    } else {
	ret = TRUE;
    }
    (void)mode_category;
    (void)start_comb;
    (void)player_no;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	リセット魔神用セーブ処理	メインデータセーブ
 ****************************************************************
 */
static int mImm_InitGameStart_re_main(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){

    int		rec;
    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_InitGameStart_re_main\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    if((*buf_p) != NULL ){
	rec = mFRm_WriteHalfFlash_bg((*buf_p), 0 );
	if( rec == TRUE ){
#if	defined(U_gen_U)
	    PRINTF("\nメイン書き込み終了 -----------------------------\n\n");
#endif	/** defined(U_gen_U) end */
	    mFRm_ClearRepair( );
	    l_mimm_start_mode = mImm_SDI_MODE_INIT_e;
	    ret = -2;
	} else if( rec == -1 ){
	    ret = TRUE;
	}
    } else {
	ret = TRUE;
    }
    (void)mode_category;
    (void)start_comb;
    (void)player_no;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	スタート後処理
 ****************************************************************
 */
static int mImm_InitGameStart_after(
    int		mode_category,	/** ロードカテゴリー */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no,	/** プレーヤー番号 */
    u32		**buf_p,
    int		*pak_mode
    ){
    
    Private_c	*private_p = ZCommonGet(now_private);
    
#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_InitGameStart_after ........................................\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    if(( ZCommonGet(player_decoy) == TRUE ) && ( private_p != NULL )){
	if( mPr_NullCheckPersonalID(&(private_p->pID)) == FALSE ){
	    /** 強制的にプレーヤー在宅に */
	    private_p->exist = 1;
	    /** 装備品を外す */
	    private_p->equipment.item = NULL_NO;
	}
    }
    l_mimm_start_mode = mImm_SDI_MODE_INIT_e;
    (void)mode_category;
    (void)start_comb;
    (void)player_no;
    (void)pak_mode;
    (void)buf_p;
    return TRUE;
}

/*
 ******************************************************************************
 *	ゲーム開始時のデータのロード & 初期化 & セーブ
 *
 *	in	:	ロードカテゴリー (save_load_mode_category参照)
 *			ロードモード (save_load_mode_kind参照)
 *			組み合わせパターン(start_data_combination参照)
 *			プレーヤー番号( 0 〜 5 )
 *
 *	out	:	なし
 *
 *	返り値	:	ロード初期化の成功	TRUE
 *			処理中			FALSE
 *			異常終了		-1
 *-----------------------------------------------------------------------------
 *	備考	今まで player_select.cの中で初期化していた処理が
 *		ここに入ります
 *
 *		引数で渡すプレーヤー番号はプレーヤー選択処理を通った場合
 *		そこで選ばれた番号を渡してください. それ以外の場合は
 *		必ず 0を渡してください.
 ******************************************************************************
 */
extern int mImm_InitGameStart(
    int		mode_category,	/** ロードカテゴリー */
    int		mode,		/** ロードモード */
    int		start_comb,	/** 組み合わせパターン */
    int		player_no	/** プレーヤー番号 */
    ){

    static mImm_INIT_PROC	init_proc[mImm_SDI_MODE_END_e] = {
	mImm_InitGameStart_data_init,
	mImm_InitGameStart_before_save,
	mImm_InitGameStart_main_init,
	mImm_InitGameStart_checksum,
	mImm_InitGameStart_main,
	mImm_InitGameStart_pak,
	mImm_InitGameStart_backup,
	mImm_InitGameStart_load_back,
	mImm_InitGameStart_re_main,
	mImm_InitGameStart_after,
    };
    static u32	*buf_p = NULL;
    static int	pak_mode = 1;
    int		ret = FALSE;
    
    if(( l_mimm_start_mode < 0 ) ||
       ( l_mimm_start_mode >= mImm_SDI_MODE_END_e )){
#if	DEBUG
	PRINTF("l_mimm_start_mode : %d\n");
	assert(0);
#endif	/** DEBUG end */
	return TRUE;
    }
    /** データセット処理 */
    ret = (init_proc[l_mimm_start_mode])( mode_category,
						    start_comb,
						    player_no,
						    &buf_p,
						    &pak_mode );
    if( l_mimm_start_mode >= mImm_SDI_MODE_END_e ){
	l_mimm_start_mode = mImm_SDI_MODE_INIT_e;
	ret = TRUE;
    }
    if( ret != FALSE ){
	mImm_InitGameStart_cleanup( &buf_p );
	buf_p = NULL;
	pak_mode = 1;
    }
    (void)mode;
    return ret;
}

/*
 ****************************************************************
 *	セーブ処理のモード初期化
 ****************************************************************
 */
extern void mImm_SaveMode_init( void ){
    l_mimm_save_mode = mImm_SAVE_MODE_INIT_e;
}

/*
 ****************************************************************
 *	セーブ前処理
 ****************************************************************
 */

/*
 *	保存情報のコピー
 */
static void mImm_CopyKeep(
    mAc_nfs_t	*d_itemNo_p,
    unchar	*d_ticket_expiration,
    unchar	*d_ticket_remain,
    unint	*d_item_cond,
    money_t	*d_money,
    mQst_dlv_c	*d_delivery_p,
    mQst_erd_c	*d_errand_p,
    Mail_c	*d_mail_p,
    mPr_sftr_c	*d_shop_ftr_p,
    mAc_nfs_t	*s_itemNo_p,
    unchar	s_ticket_expiration,
    unchar	s_ticket_remain,
    unint	s_item_cond,
    money_t	s_money,
    mQst_dlv_c	*s_delivery_p,
    mQst_erd_c	*s_errand_p,
    Mail_c	*s_mail_p,
    mPr_sftr_c	*s_shop_ftr_p
    ){

    int		i;

    bcopy( s_itemNo_p, d_itemNo_p, sizeof(mAc_nfs_t) * ITEM_POSSESS_NUM );
    (*d_item_cond) = s_item_cond;
    (*d_ticket_expiration) = s_ticket_expiration;
    (*d_ticket_remain) = s_ticket_remain;
    (*d_money) = s_money;
    for( i = 0; i < DELIVERY_QUEST_MAX; i++ ){
	mQst_CopyDelivery( d_delivery_p, s_delivery_p );
	d_delivery_p++;
	s_delivery_p++;
    }
    for( i = 0; i < ERRAND_QUEST_MAX; i++ ){
	mQst_CopyErrand( d_errand_p, s_errand_p );
	d_errand_p++;
	s_errand_p++;
    }
    for( i = 0; i < MAIL_POSSESS_NUM; i++ ){
	mMl_copy_mail( d_mail_p, s_mail_p );
	d_mail_p++;
	s_mail_p++;
    }
    for( i = 0; i < SHOP_FTR_ORDER_MAX; i++ ){
	d_shop_ftr_p->itemNo = s_shop_ftr_p->itemNo;
	d_shop_ftr_p->shopLevel = s_shop_ftr_p->shopLevel;
	d_shop_ftr_p++;
	s_shop_ftr_p++;
    }
}

/*
 *	プレーヤーお出かけ時の情報消去
 */
static void mImm_ClearPrivateItem(
    Private_c	*private_p,
    mImm_kpr_c	*keep_p
    ){

    if( keep_p != NULL ){
	bzero( keep_p, sizeof(mImm_kpr_c));

	mImm_CopyKeep( &(keep_p->itemNo[0]),
		       &(keep_p->ticket_expiration),
		       &(keep_p->ticket_remain),
		       &(keep_p->item_cond),
		       &(keep_p->money),
		       &(keep_p->delivery[0]),
		       &(keep_p->errand[0]),
		       &(keep_p->mail[0]),
		       &(keep_p->shop_ftr[0]),
		       &(private_p->possession.itemNo[0]),
		       private_p->possession.ticket_expiration,
		       private_p->possession.ticket_remain,
		       private_p->possession.item_cond,
		       private_p->possession.money,
		       &(private_p->delivery[0]),
		       &(private_p->errand[0]),
		       &(private_p->mail[0]),
		       &(private_p->shop_ftr[0]) );
    }
    /** セーブデータからプレーヤーの持ち物情報消去 */
    bzero( &(private_p->possession.itemNo[0]),
	   sizeof(mAc_nfs_t) * ITEM_POSSESS_NUM );
    private_p->possession.item_cond = 0;
    private_p->possession.ticket_expiration = 0;
    private_p->possession.ticket_remain = 0;
    private_p->possession.money = 0;
    /** 配達クエスト情報の初期化 */
    mQst_ClearDelivery( &(private_p->delivery[0]), DELIVERY_QUEST_MAX );
    /** お使いクエスト情報の初期化 */
    mQst_ClearErrand( &(private_p->errand[0]), ERRAND_QUEST_MAX );
    /** 手紙情報消去 */
    mMl_clear_mail_box( &(private_p->mail[0]), MAIL_POSSESS_NUM );
    bzero(&(private_p->shop_ftr[0]), sizeof(mPr_sftr_c) * SHOP_FTR_ORDER_MAX);
}

static void mImm_ReplaceKeep(
    Private_c	*private_p,
    mImm_kpr_c	*keep_p
    ){
    
    if( keep_p != NULL ){
	mImm_CopyKeep( &(private_p->possession.itemNo[0]),
		       &(private_p->possession.ticket_expiration),
		       &(private_p->possession.ticket_remain),
		       &(private_p->possession.item_cond),
		       &(private_p->possession.money),
		       &(private_p->delivery[0]),
		       &(private_p->errand[0]),
		       &(private_p->mail[0]),
		       &(private_p->shop_ftr[0]),
		       &(keep_p->itemNo[0]),
		       keep_p->ticket_expiration,
		       keep_p->ticket_remain,
		       keep_p->item_cond,
		       keep_p->money,
		       &(keep_p->delivery[0]),
		       &(keep_p->errand[0]),
		       &(keep_p->mail[0]),
		       &(keep_p->shop_ftr[0]) );
    }
}

static int mImm_Save_init(
    int		mode_category,
    int		continue_flag,
    Private_c	*keep_private_p,
    mImm_kpr_c	*keep_p,
    int		*pak_mode,
    u32		**buf_p
    ){

    mCPk_pkinfo_c	*pak_info_p;
    Private_c		*private_p;
    Animal_c		*remove_animal_p;
//    mImm_kpr_c		*keep_p = NULL;
    int			rec = -1;
    int			ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_YELLOW
	   "セーブ前処理 ***************************************************\n"
	   ESC_NORMAL);
#endif
    (*pak_mode) = mImm_SAVE_PAK_NO_e;
    (*buf_p) = NULL;

    if( l_mimm_malloc_time < 150 ){
	(*buf_p) =
	    (u32 *)sys_gmalloc_malloc_nowait(ALIGNMENT_128(sizeof(Save_c)));
	if((*buf_p) != NULL ){

#if	defined(U_gen_U)
	    PRINTF(ESC_CYAN"領域確保成功 : %#010x"ESC_NORMAL,ALIGNMENT_128(sizeof(Save_c)));
#endif	/** defined(U_gen_U) end */
    
	    /*--------------------------------------*/
	    /* PlayTimeのセーブ。(ゴキブリ用)       */
	    /*--------------------------------------*/
	    mCkRh_SavePlayTime((int)ZCommonGet(player_no));

	    switch( mode_category ){
	    case mImm_SVLD_CT_FLASH_e :	/** フラッシュロムにセーブ */
		if( continue_flag != ON ){
		    /** リセット魔神情報クリア */
		    mImm_ClearResetCode( );
		} else {
		    private_p = ZCommonGet(now_private);
		    /** この時点でリセットコードがなければ再セット */
		    if( mImm_CheckResetCode( private_p ) == TRUE ){
			mImm_SetResetCode( private_p );
		    }
		}
		if( mImm_CheckStartDataCategory( ) == TRUE ){
		    /** 動物引っ越し */
		    remove_animal_p = mNpc_GetInAnimalP( );
		    mNpc_GetRemoveAnimal( remove_animal_p, OFF );
		}
//		ret = 1;
		break;
	    case mImm_SVLD_CT_CPAK_e :	/** コントローラパックにもセーブ */
		if( continue_flag != ON ){
		    /** リセット魔神情報クリア */
		    mImm_ClearResetCode( );
		}
		/** パックのオープン */
		pak_info_p = mCPk_get_pkinfo( );
		rec = mCPk_PakOpen( pak_info_p, 0 );
		if( rec == 1 ){
		    private_p = ZCommonGet(now_private);

		    /** 動物引っ越し */
		    remove_animal_p = mNpc_GetInAnimalP( );
		    mNpc_GetRemoveAnimal( remove_animal_p, ON );
#if	DEBUG
		    assert(remove_animal_p);
#endif	/** DEBUG */
		    (*pak_mode) = mImm_SAVE_PAK_SAVE_e;
		    mPr_CopyPrivateInfo( keep_private_p, private_p );
#if 0
		    rec = mCPk_SavePak( private_p,
					remove_animal_p,
					pak_info_p );
#endif	/** #if 0 end */
		    /** プレーヤーを不在にセット */
		    if( mLd_PlayerManKindCheckNo( ZCommonGet(player_no))
			== NATIVE_e ){
			private_p->exist = 0;
#if 0
			keep_p = (mImm_kpr_c *)zelda_malloc( sizeof(mImm_kpr_c));
#if	DEBUG
			if( keep_p != NULL ){
			    PRINTF(ESC_CYAN
				   "mImm_kpr_c サイズ確保成功 : %#010x\n"
				   ESC_NORMAL,sizeof(mImm_kpr_c));
			} else {
			    PRINTF(ESC_ERROR
				   "mImm_kpr_c サイズ確保失敗 : %#010x\n"
				   ESC_NORMAL,sizeof(mImm_kpr_c));
			    assert(0);
			}
#endif	/** DEBUG end */
#endif	/** #if 0 end */
			/** セーブデータからプレーヤーの持ち物情報消去 */
			mImm_ClearPrivateItem( private_p, keep_p );
		    }
#if 0
		    if( rec == 1 ){
			ret = 1;
		    } else {
#if	DEBUG
			PRINTF("パックへの書き込みに失敗しました\n");
#endif	/** DEBUG end */
			/** プレーヤーデータ修正 */
			if(( private_p != NULL ) &&
			   ( mLd_PlayerManKindCheckNo( ZCommonGet(player_no))
			     == NATIVE_e )){
			    private_p->exist = 1;
			    mImm_ReplaceKeep( private_p, keep_p );
			}
			ret = -2;
		    }
#endif	/** #if 0 end */
		

#if 0
		    if( keep_p != NULL ){
			zelda_free( keep_p );
#if	DEBUG
			PRINTF(ESC_CYAN"mImm_kpr_c 領域解放 : %#010x\n"ESC_NORMAL,
			       sizeof(mImm_kpr_c));
#endif	/** DEBUG end */
		    }
#endif	/** #if 0 end */
		} else {
		    ret = -1;
		}
		break;
	    default :
#if	DEBUG
		PRINTF(ESC_ERROR
		       "セーブカテゴリーの指定が正しくありません : %d\n"
		       ESC_NORMAL,mode_category);
#if	defined(U_gen_U)
		assert(0);
#endif	/** defined(U_gen_U) end */
		
#endif	/** DEBUG end */
		ret = -1;
		break;
	    }
	    l_mimm_malloc_time = 0;
	    l_mimm_save_mode = mImm_SAVE_MODE_MAIN_INIT_e;
	} else {
#if	defined(U_gen_U)
	    PRINTF("確保中 : %d\n",l_mimm_malloc_time);
#endif	/** defined(U_gen_U) end */
	    (l_mimm_malloc_time)++;
	}
    } else {
#if	defined(U_gen_U)
	PRINTF(ESC_ERROR"マロック出来ませんでした\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
	ret = TRUE;
	l_mimm_malloc_time = 0;
    }
    return ret;
}

/*
 ****************************************************************
 *	データのコピー
 ****************************************************************
 */
static int mImm_Save_main_init(
    int		mode_category,
    int		continue_flag,
    Private_c	*keep_private_p,
    mImm_kpr_c	*keep_p,
    int		*pak_mode,
    u32		**buf_p
    ){

    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_Save_main_init ..........................\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */

    mFRm_ClearRepair( );
    if((*buf_p) != NULL ){

#ifdef BBPLAYER
        SaveSet(delta.minutes, bbRTC_delta_minutes);
        SaveSet(delta.sign, bbRTC_delta_sign);
#endif

	bcopy( ZCommonGetP(save.data[0]), (*buf_p),
	       ALIGNMENT_128(sizeof(Save_c)));
#if	DEBUG
	PRINTF("バッファのコピー成功\n");
#endif	/** DEBUG end */
    }
    else {
#if	DEBUG
	PRINTF(ESC_ERROR"バッファがありません\n"ESC_NORMAL);
#endif	/** DEBUG end */
	ret = TRUE;
    }
    l_mimm_save_mode = mImm_SAVE_MODE_CHECKSUM_e;
    (void)mode_category;
    (void)continue_flag;
    (void)keep_private_p;
    (void)keep_p;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	チェックサムセット
 ****************************************************************
 */
static int mImm_Save_set_checksum(
    int		mode_category,
    int		continue_flag,
    Private_c	*keep_private_p,
    mImm_kpr_c	*keep_p,
    int		*pak_mode,
    u32		**buf_p
    ){

    Save_c	*save_p;
    unshort	check_sum;
    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_Save_set_checksum ..........................\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    if((*buf_p) != NULL ){
	save_p = (Save_c *)(*buf_p);
	/** 書き込みバッファのセット */
	/* 2000.11.16 M.Sasaki Add	*/
	/* バージョンセット		*/
	save_p->save_check.version = mFRm_FLROM_VERSION;
	/** セーブチェックデータのセット */
	mFRm_SetSaveCheckData( &(save_p->save_check));
#if	DEBUG
	save_p->saved_rom_d = ON;
	/** 時間の設定 */
	lbRTC_TimeCopy( &(save_p->debug_time), ZCommonGetP(time.rtcTime));
#endif	/** DEBUG end */
	/** チェックサムのセット */
	check_sum = mFRm_GetFlatCheckSum((unshort *)save_p,
					 ALIGNMENT_128(sizeof(Save_c)),
					 save_p->save_check.check_sum );
#if	defined(U_gen_U)
	PRINTF(ESC_RED
	       "チェックサム計算後のチェックサム %#010x %#010x-------------\n"
	       ESC_NORMAL,
	       check_sum,
	       mFRm_ReturnCheckSum((unshort *)save_p,
				   (int)ALIGNMENT_128(sizeof(Save_c))));
#endif	/** defined(U_gen_U) end */
	save_p->save_check.check_sum = check_sum;
#if	defined(U_gen_U)
	PRINTF(ESC_RED
	       "チェックサム計算後のチェックサム %#010x --------------------\n"
	   ESC_NORMAL,mFRm_ReturnCheckSum((unshort *)save_p,
					  (int)ALIGNMENT_128(sizeof(Save_c))));
#endif	/** defined(U_gen_U) end */
    } else {
	ret = TRUE;
    }
    l_mimm_save_mode = mImm_SAVE_MODE_SAVE_MAIN_e;
    (void)mode_category;
    (void)continue_flag;
    (void)keep_private_p;
    (void)keep_p;
    (void)pak_mode;
    return ret;
}


/*
 ****************************************************************
 *	メインセーブ
 ****************************************************************
 */
static int mImm_Save_save_main(
    int		mode_category,
    int		continue_flag,
    Private_c	*keep_private_p,
    mImm_kpr_c	*keep_p,
    int		*pak_mode,
    u32		**buf_p
    ){

    
    int		rec;
    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_Save_save_main ..........................\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    if((*buf_p) != NULL ){
	rec = mFRm_WriteHalfFlash_bg((*buf_p), 0 );
	if( rec == TRUE ){
#if	defined(U_gen_U)
	    PRINTF("\nメイン書き込み終了 -----------------------------\n\n");
#endif	/** defined(U_gen_U) end */
	    mFRm_ClearRepair( );
	    l_mimm_save_mode = mImm_SAVE_MODE_SAVE_PACK_e;
	} else if( rec == -1 ){
	    ret = TRUE;
	}
    } else {
	ret = TRUE;
    }
    (void)mode_category;
    (void)continue_flag;
    (void)keep_private_p;
    (void)keep_p;
    (void)pak_mode;
    
    return ret;
}

/*
 ****************************************************************
 *	パックセーブ
 ****************************************************************
 */
static int mImm_Save_pak(
    int		mode_category,
    int		continue_flag,
    Private_c	*keep_private_p,
    mImm_kpr_c	*keep_p,
    int		*pak_mode,
    u32		**buf_p
    ){

    int		rec = 1;
    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_Save_pak ..........................\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    switch((*pak_mode)){
	case mImm_SAVE_PAK_SAVE_e :	/** パック内データのセーブ */
#if	defined(U_gen_U)
	    PRINTF(ESC_YELLOW"パック内データの消去\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
	    rec = mCPk_SavePak( keep_private_p,
				mNpc_GetInAnimalP( ),
				mCPk_get_pkinfo( ));
	    break;
	default :
#if	defined(U_gen_U)
	    PRINTF("パックなにもしません\n");
#endif	/** defined(U_gen_U) end */
	    break;
    }
    if( rec != 1 ){
#if	defined(U_gen_U)
	PRINTF(ESC_ERROR"パックエラー   バックアップからの復帰\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
	l_mimm_save_mode = mImm_SAVE_MODE_LOAD_BACKUP_e;
    } else {
	l_mimm_save_mode = mImm_SAVE_MODE_SAVE_BACKUP_e;
    }
    (void)mode_category;
    (void)continue_flag;
    (void)keep_p;
    (void)buf_p;
    return ret;
}

/*
 ****************************************************************
 *	バックアップセーブ
 ****************************************************************
 */
static int mImm_Save_backup(
    int		mode_category,
    int		continue_flag,
    Private_c	*keep_private_p,
    mImm_kpr_c	*keep_p,
    int		*pak_mode,
    u32		**buf_p
    ){


    int		rec;
    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_Save_backup ..........................\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */

    if((*buf_p) != NULL ){
	rec = mFRm_WriteHalfFlash_bg((*buf_p), 1 );
	if( rec == TRUE ){
#if	defined(U_gen_U)
	    PRINTF("\nバック書き込み終了 -----------------------------\n\n");
#endif	/** defined(U_gen_U) end */
	    mFRm_ClearRepair( );
	    l_mimm_save_mode = mImm_SAVE_MODE_AFTER_e;
	} else if( rec == -1 ){
	    ret = TRUE;
	}
    } else {
	ret = TRUE;
    }
    (void)mode_category;
    (void)continue_flag;
    (void)keep_private_p;
    (void)keep_p;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	バックアップデータロード
 ****************************************************************
 */
static int mImm_Save_backup_load(
    int		mode_category,
    int		continue_flag,
    Private_c	*keep_private_p,
    mImm_kpr_c	*keep_p,
    int		*pak_mode,
    u32		**buf_p
    ){

    Private_c	*private_p;
    Save_c	*save_p;
    unshort	check_sum;
    int		ret = FALSE;
    int		rec;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_Save_backup_load ..........................\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    rec = mFRm_FlashLoadAllData_common((*buf_p), mFRm_BACKUP_START_PAGE_NO );
    if( rec == TRUE ){
	check_sum = mFRm_ReturnCheckSum((unshort *)(*buf_p),
					(int)ALIGNMENT_128(sizeof(Save_c)));
	if( check_sum == 0 ){
	    save_p = (Save_c *)(*buf_p);
	    if( mFRm_CheckSaveData_ID(&(save_p->save_check)) == TRUE ){
		mFRm_ClearRepair( );
		l_mimm_save_mode = mImm_SAVE_MODE_RESAVE_MAIN_e;
	    } else {
		ret = TRUE;
	    }
	} else {
	    ret = TRUE;
	}
    } else {
	ret = TRUE;
    }
    /** プレーヤーデータ修正 */
    private_p = ZCommonGet(now_private);
    if(( private_p != NULL ) &&
       ( mLd_PlayerManKindCheckNo( ZCommonGet(player_no)) == NATIVE_e )){
	private_p->exist = 1;
	mImm_ReplaceKeep( private_p, keep_p );
    }
    (void)mode_category;
    (void)continue_flag;
    (void)keep_private_p;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	メインの復帰
 ****************************************************************
 */
static int mImm_Save_re_main(
    int		mode_category,
    int		continue_flag,
    Private_c	*keep_private_p,
    mImm_kpr_c	*keep_p,
    int		*pak_mode,
    u32		**buf_p
    ){

    int		rec;
    int		ret = FALSE;

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_Save_re_main ..........................\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    if((*buf_p) != NULL ){
	rec = mFRm_WriteHalfFlash_bg((*buf_p), 0 );
	if( rec == TRUE ){
#if	defined(U_gen_U)
	    PRINTF("\nメイン書き込み終了 -----------------------------\n\n");
#endif	/** defined(U_gen_U) end */
	    mFRm_ClearRepair( );
	    l_mimm_save_mode = mImm_SAVE_MODE_INIT_e;
	    ret = -2;
	} else if( rec == -1 ){
	    ret = TRUE;
	}
    } else {
	ret = TRUE;
    }
    (void)mode_category;
    (void)continue_flag;
    (void)keep_private_p;
    (void)keep_p;
    (void)pak_mode;
    return ret;
}

/*
 ****************************************************************
 *	セーブ処理
 ****************************************************************
 */
static int mImm_Save_after(
    int		mode_category,
    int		continue_flag,
    Private_c	*keep_private_p,
    mImm_kpr_c	*keep_p,
    int		*pak_mode,
    u32		**buf_p
    ){

    Private_c	*private_p = ZCommonGet(now_private);

#if	defined(U_gen_U)
    PRINTF(ESC_CYAN"mImm_Save_after ..........................\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
    if( continue_flag == ON ){
	if(( ZCommonGet(player_decoy) == TRUE ) && ( private_p != NULL )){
	    /** 強制的にプレーヤー在宅に */
	    private_p->exist = 1;
	}
    } else {
	ZCommonSet(player_decoy, FALSE);
    }
    (void)mode_category;
    (void)keep_private_p;
    (void)keep_p;
    (void)pak_mode;
    (void)buf_p;
    return TRUE;
}

/*
 ******************************************************************************
 *	セーブ
 *	
 *	in	:	セーブモードカテゴリー(save_load_mode_category)
 *			セーブモード (save_load_mode_kind)
 *			コンティニューフラグ( やめる OFF / 続ける ON )
 *
 *	out	:	なし
 *
 *	返り値	:	正常終了	1
 *			セーブ中	0
 *			異常終了	-1 (パックが抜かれた場合)
 *			異常終了	-2 (パックセーブに失敗した場合)
 *-----------------------------------------------------------------------------
 *	(※) 返り値として !0が返るまで毎フレーム呼んでください
 ******************************************************************************
 */
extern int mImm_Save_common(
    int		mode_category,
    int		mode,
    int		continue_flag
    ){
    
    static mImm_SAVE_PROC	save_proc[mImm_SAVE_MODE_END_e] = {
	mImm_Save_init,
	mImm_Save_main_init,
	mImm_Save_set_checksum,
	mImm_Save_save_main,
	mImm_Save_pak,
	mImm_Save_backup,
	mImm_Save_backup_load,
	mImm_Save_re_main,
	mImm_Save_after,	/** 後始末 */
    };

    int			ret = 0;
    static Private_c	keep_private;
    static mImm_kpr_c	keep_info;
    static int		pak_mode = mImm_SAVE_PAK_NO_e;
    static u32		*buf_p = NULL;

    if( mode != mImm_SVLDMD_PLAYER_e ){
#if	defined(U_gen_U)
	PRINTF("モードの指定が違います\n");
#endif	/** defined(U_gen_U) end */
	mode = mImm_SVLDMD_PLAYER_e;
    }

    if(( l_mimm_save_mode < 0 ) ||
       ( l_mimm_save_mode >= mImm_SAVE_MODE_END_e )){
#if	DEBUG
	PRINTF("save mode : %d\n",l_mimm_save_mode);
	assert(0);
#else	/** DEBUG else */
	l_mimm_save_mode = mImm_SAVE_MODE_AFTER_e;
#endif	/** DEBUG else end */
    }

    ret = (save_proc[l_mimm_save_mode])( mode_category,
					 continue_flag,
					 &keep_private,
					 &keep_info,
					 &pak_mode,
					 &buf_p );
    if( ret != FALSE ){
	mFRm_ClearRepair( );
	mPr_ClearPrivateInfo( &keep_private );
	bzero( &(keep_info), sizeof(mImm_kpr_c));
	pak_mode = mImm_SAVE_PAK_NO_e;
	l_mimm_save_mode = mImm_SAVE_MODE_INIT_e;
	if( buf_p != NULL ){
	    sys_gmalloc_free( buf_p );
	}
	buf_p = NULL;
    }

#if 0
    if( rec == 1 ){
	l_mimm_save_mode++;
    } else if( rec < 0 ){
	if( rec == -1 ){
#if	DEBUG
	    PRINTF(ESC_ERROR"セーブがうまくいきませんでした\n"ESC_NORMAL);
#endif	/** DEBUG end */
	    if( l_mimm_save_mode == mImm_SAVE_MODE_SAVE_e ){
#if	DEBUG
		PRINTF(ESC_RED,
		       "フラッシュロムでセーブ失敗しているので"
		       "無理やり正常終了に\n"ESC_NORMAL);
#endif	/** DEBUG end */
		ret = 1;
	    } else {
		ret = -1;
	    }
	} else {
#if	defined(U_gen_U)
	    PRINTF("何らかの異常\n");
#endif	/** defined(U_gen_U) end */
	    ret = rec;
	}
	l_mimm_save_mode = mImm_SAVE_MODE_INIT_e;
    }
    if( l_mimm_save_mode >= mImm_SAVE_MODE_END_e ){
#if	defined(U_gen_U)
	PRINTF(ESC_YELLOW"正常にセーブ終了しました\n"ESC_NORMAL);
#endif	/** defined(U_gen_U) end */
	l_mimm_save_mode = mImm_SAVE_MODE_INIT_e;
	ret = 1;
    }
#endif	/** #if 0 end */
    return ret;
}



/*
 ******************************************************************************
 *	ここの関数は コントローラパック, Flashromセーブ実験用です
 *	セーブ画面の仕様が決まり次第そちらに移ります.
 ******************************************************************************
 */
extern void mImm_SaveTest( void ){

#if	DEBUG
    mFRm_TEST( );
#endif
}





/*
 ------------------------------------------------------------------------------
 *		コントローラパックによる出入国
 ------------------------------------------------------------------------------
 */
/*
 ****************************************************************
 *	ゲーム開始したのがコントローラパックからかチェック
 *
 *	パックでゲーム開始	TRUE
 *	カートリッジで開始	FALSE
 ****************************************************************
 */
extern int mImm_CheckStartDataCategory( void ){

    int		ret = FALSE;

    if( l_start_dt_ct == mImm_SVLD_CT_CPAK_e ){
	ret = TRUE;
    }
    return ret;
}
