簡単RPG講座12-2。お店と宝箱。その2

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

簡単RPG講座12-2。お店と宝箱。その2

投稿記事 by softya(ソフト屋) » 14年前

さて、続いてアイテム処理関係の変更とお店の処理を追加します。

まず、パーティ処理のヘッダです。
[party.h]
●関数の宣言
アイテム追加や削除と宿泊処理を追加。

CODE:

//	アイテムを削除する。
extern int party_delItem(PlayerParam_t *playerParam,int no);
//	アイテムを追加する。
extern int party_addItem(PlayerParam_t *playerParam,int item_no);
//	宿泊の回復
extern void party_Inn(PlayerParam_t *playerParam);
[party.cpp]
プログラム本体です。
●定数
初期パラメータを変更しました。

CODE:

//	初期パラメータ
#define INI_HP_MAX	(10)
#define INI_MP_MAX	(5)
#define INI_ATTACK	(9)
#define INI_DEFENSE	(11)
●party_init
初期パラメータをテスト用にふたたび変更。
本来の初期値を#if 0でコメントアウトしてあります。

CODE:

//----------------------------------------------------------------------
//	パラメータ初期化
//----------------------------------------------------------------------
void party_init(PlayerParam_t *playerParam)
{
	//	パラメータに初期値を与える。
#if 0
	playerParam->level = 1;				//レベル
	playerParam->expp = 0;				//経験値(Experience point)
	playerParam->hp = INI_HP_MAX;		//HP
	playerParam->hp_max = INI_HP_MAX;	//HPMAX
	playerParam->mp = INI_MP_MAX;		//MP
	playerParam->mp_max = INI_MP_MAX;	//MPMAX
	playerParam->attack = INI_ATTACK;	//攻撃力
	playerParam->def = INI_DEFENSE;		//防御力
	playerParam->money = 0;				//所持金
	for( int i=0 ; iitems[i] = ITEM_NON;//所持アイテム(4つまで)
	}
#else
	playerParam->level = 5;				//レベル
	playerParam->expp = 0;				//経験値(Experience point)
	playerParam->hp = INI_HP_MAX/2;		//HP
	playerParam->hp_max = INI_HP_MAX;	//HPMAX
	playerParam->mp = INI_MP_MAX/2;		//MP
	playerParam->mp_max = INI_MP_MAX;	//MPMAX
	playerParam->attack = INI_ATTACK;	//攻撃力
	playerParam->def = INI_DEFENSE;		//防御力
	playerParam->money = 20;				//所持金
	for( int i=0 ; iitems[i] = ITEM_HERB;//所持アイテム(4つまで)
		} else {
			playerParam->items[i] = ITEM_MG_HERB;//所持アイテム(4つまで)
		}
	}
#endif
}
●party_delItem
アイテムの削除を行う関数です。
指定された番号(袋の中の順番番号でアイテム番号ではありません)のアイテムを削除してアイテムを前に詰めます。
前に詰めたら後ろには空アイテム(ITEM_NON)を入れています。
他のプログラムの部分でも前詰め前提で作られていますので、空アイテムが前方(若い番号)に有ってはいけません。

CODE:

//----------------------------------------------------------------------
//	アイテムを削除する。
//----------------------------------------------------------------------
int party_delItem(PlayerParam_t *playerParam,int no)
{
	//	アイテムを消費する(アイテムテーブルを前に詰める)。
	for( int i=no ; iitems[i] = playerParam->items[i+1];
	}
	playerParam->items[ITEM_MAX_NUMS-1] = ITEM_NON;	//最後を空にする。
	
	//	削除した
	return TRUE;
}
●party_addItem
アイテムの追加関数です。
アイテム袋の先頭から空きを探して、空きがあったらアイテムを格納してTRUEを戻します。
もし空きがなかった場合には、FALSEを戻します。

CODE:

//----------------------------------------------------------------------
//	アイテムを追加する。
//----------------------------------------------------------------------
int party_addItem(PlayerParam_t *playerParam,int item_no)
{
	//	アイテム袋に空きがあるか?
	for( int i=0 ; iitems[i] == ITEM_NON ) {//空き?
			//	アイテムを入れる。
			playerParam->items[i] = item_no;
			//	アイテムを格納した。
			return TRUE;
		}
	}
	
	//	空きがなかった
	return FALSE;
}
●party_Inn
宿泊処理で、HPとMPをMAXまで回復します。

CODE:

//----------------------------------------------------------------------
//	宿泊の回復
//----------------------------------------------------------------------
void party_Inn(PlayerParam_t *playerParam)
{
	//	HP回復
	party_healSub(&(playerParam->hp),playerParam->hp_max,playerParam->hp_max);
	//	MP回復
	party_healSub(&(playerParam->mp),playerParam->mp_max,playerParam->mp_max);
}
以上、パーティ処理の変更でした。

[menu.cpp]
アイテムを削除する処理をパーティ処理に移しましたので変更します。
●menu_item
関数全体を書いていますが、変えたのはアイテムを消費するparty_delItem()を呼んでいる部分だけです。

CODE:

//----------------------------------------------------------------------
//	メニューアイテム
//----------------------------------------------------------------------
static int menu_item(PlayerParam_t *playerParam)
{
	int menuFrame = STM_GetFrameCount(s_MenuStateObj);	//メニューのフレーム
	static char *s_itemList[ITEM_MAX_NUMS+1];	//	表示用のリスト
	
	//	アイテムメニューの構成を組み立てる準備
	menu_ListInit();
	
	//	アイテムメニューの構成を組み立てる。
	int items = 0;
	for( int i=0 ; iitems[i] == ITEM_NON ) { //アイテムを所持していない。
			break;	//アイテム未所持なら抜ける。
		}
		s_itemList[i] = menu_ListSprintf( "%s", party_getItemName(playerParam->items[i]));//アイテム
		items++;
	}
	s_itemList[items] = NULL;//ストッパ
	
	//	ステータス表示のウィンドウの設定
	menu_MakeStatusList(playerParam);
	
	//	アイテムメニューの最初?
	if( menuFrame==0 ) {
		//	ステータス表示ウィンドウの生成。
		s_SubWinNo = menu_NewWinStatusList();
		
		//	アイテムメニューを設定
		int sizex = 150;
		int sizey = 120;
		int posx = (SCREEN_X-sizex) / 3;
		int posy = (SCREEN_Y-sizey) / 3;
		s_MainWinNo = winmng_NewWin(posx,posy,sizex,sizey,"アイテム");
		winmng_SetMenu( s_itemList );
	} else {
		//	アイテムメニューを更新
		winmng_UpdateMenu( s_itemList );
	}

	//	アイテムの選択をする。
	int item_selno = winmng_SelectMenu();
	if( item_selno!=-1 ) {	//選択されたら
		
		//	アイテムの処理を行う。
		if( party_useItem(playerParam,playerParam->items[item_selno]) ) {
			//	アイテムを消費する(アイテムテーブルを前に詰める)。
			party_delItem(playerParam,item_selno);
		}
	}
	
	//	キャンセル
	if( g_MainData.key[g_MainData.key_menu] == 1 ) {
		//	表示終了ならばこのアイテム関連ウィンドウを消去。
		winmng_DelWin(s_MainWinNo);
		winmng_DelWin(s_SubWinNo);
		//	次のフレームで遷移。
		return TRUE;
	}
	//	遷移しない。
	return FALSE;
}
メニューの変更は、これだけです。
次は新規のお店処理です。
[shop.h]
●先頭部分と定数
パーティ処理のヘッダ情報がほしいので#includeしてます。
SHOP_TYPE_???は、ショップの種類を表す定数です。

CODE:

#ifndef INCLUDE_SHOP_H
#define INCLUDE_SHOP_H

#include "party.h"

//----------------------------------------------------------------------
//	定数
//----------------------------------------------------------------------

//	ショップのタイプ
enum {
	SHOP_TYPE_ITEM,	//	道具屋
	SHOP_TYPE_INN,	//	宿屋
	
	SHOP_TYPE_MAX
};
●関数の宣言
ショップ処理に関わる関数を定義しています。
詳細はプログラム本体で説明します。

CODE:

//----------------------------------------------------------------------
//	関数の宣言
//----------------------------------------------------------------------


//	SHOP初期化
extern void shop_Init();

//	SHOP終了
extern void shop_End();

//	SHOP処理
extern int shop_Main(int frame,PlayerParam_t *playerParam);

//	SHOP描画
extern void shop_Draw();

#endif /*INCLUDE_SHOP_H*/
[shop.cpp]
お店処理のプログラム本体です。
●ヘッダのインクルード
お店で使うヘッダです。まぁ~色々使ってますね。
状態管理、ウィンドウ管理、イベント処理など盛り沢山です。

CODE:

#include 

#include "main.h"
#include "stateMng.h"
#include "winMng.h"
#include "eventScn.h"
#include "shop.h"
●内部関数の宣言
内部関数ですが、SHOP処理用、お金の表示用、共通処理など色々あります。

CODE:

//----------------------------------------------------------------------
//	内部関数
//----------------------------------------------------------------------

//	SHOP
static int shop_ItemSelect(PlayerParam_t *playerParam,char *format,int *pSelno,int *pWinNo);//	道具屋:アイテム選択
static int shop_ComMsg(PlayerParam_t *playerParam,char *format,int price);				//	共通:メッセージ処理
static int shop_ComYnSel(PlayerParam_t *playerParam,char *format,int price,int *pWinNo);	//	共通:Y/N選択
static int shop_InnSleep(PlayerParam_t *playerParam,int price);								//	宿屋:宿泊

//	お金の表示
static void shop_MakeMoneyView(PlayerParam_t *playerParam);	//	お金表示の準備
static int shop_NewWinMoneyView();							//	お金表示ウィンドウの作成

//	共通処理
static void shop_CheckDelWin( int *pWinNo );	//	指定ウィンドウの削除
static void shop_SetFadeDegree( int fade );		//	フェード状態を設定。255で黒。0でクリア。
●定数
SHOP_STATE_???は、お店の状態を管理する定数です。道具屋と宿屋で別れてます。
YNSEL_???は、YN選択の戻り値用です。
INN_CHARGE_PRICEは宿の単価ですね。実際大きなRPGを本格的に作るときは宿ごとに値段が変わるので別の工夫をしないと行けません(お店呼び出しシナリオのパラメータにするとか)。

CODE:

//----------------------------------------------------------------------
//	定数
//----------------------------------------------------------------------

//	お店状態
enum {
	SHOP_STATE_ITEMSEL,		//	道具屋:アイテム選択
	SHOP_STATE_BUYSEL,		//	道具屋:購入選択
	SHOP_STATE_BUY,			//	道具屋:購入処理
	SHOP_STATE_BUYSKIP,		//	道具屋:購入できなかった
	
	SHOP_STATE_INN_PRICE,	//	宿屋:料金の提示
	SHOP_STATE_INN_YNSEL,	//	宿屋:Y/N選択
	SHOP_STATE_INN_MES,		//	宿屋:おやすみなさい表示
	SHOP_STATE_INN_SLEEP,	//	宿屋:宿泊
	SHOP_STATE_INN_SKIP,	//	宿屋:お金が足りません
	
	SHOP_STATE_MAX
};

//	shop_InnYnSel()の選択による分岐
enum {
	YNSEL_YES,	//はい
	YNSEL_NO,	//いいえ
	
	YNSEL_NON,	//未選択。
};

//	お宿の料金
#define INN_CHARGE_PRICE	(10)

//	メッセージバッファのサイズ
#define MSG_BUFF_SIZE (64)

●構造体
ShopItem_tはお店で扱っている商品一覧を定義するための構造体です。
アイテムとその単価を定義します。

CODE:

//----------------------------------------------------------------------
//	構造体
//----------------------------------------------------------------------

//	販売アイテム構造体。
typedef struct {
	int item_no;	//アイテム番号
	int price;		//価格
} ShopItem_t;
●変数
s_ShopStateObjはSHOPの状態管理オブジェクト。
s_MsgWinNo~s_ShopWinNo2はウィンドウの管理用。
s_ShopItemsは商品一覧用の元データ。
ItemInfoBufとs_ItemListは実際にアイテムを表示するためのリスト。
s_ItemSelnoは選択されたアイテム保持用。
s_MoneyListとMoneyViewBufはお金の表示専用。
s_fadeDegreeはフェードアウト制御用。

CODE:

//----------------------------------------------------------------------
//	変数
//----------------------------------------------------------------------

//	SHOPに関連したデータ
static STATEMNG_OBJECT s_ShopStateObj;	//SHOPのオブジェクト
static int s_MsgWinNo=-1;	//メッセージ・ウィンドウ番号
static int s_MoneyWinNo=-1;	//お金表示・ウィンドウ番号
static int s_ShopWinNo=-1;	//お店ウィンドウ番号
static int s_ShopWinNo2=-1;	//お店の購入ウィンドウ番号

//	販売アイテムリスト
#define SHOP_ITEMS	2
static ShopItem_t s_ShopItems[SHOP_ITEMS] = {
	//	アイテム番号と価格
	{ ITEM_HERB, 5 },		//薬草
	{ ITEM_MG_HERB, 25 },	//魔法薬草
};
//	販売アイテムメニュー用のリスト
static char ItemInfoBuf[SHOP_ITEMS][32];	//編集表示用バッファ
static char *s_ItemList[SHOP_ITEMS+1] = {
	ItemInfoBuf[0],		//1品目目
	ItemInfoBuf[1],		//2品目目
	NULL,				//ストッパ
};
//	選択されたアイテム番号
static int s_ItemSelno = -1;		//選択番号


//	お金表示用のリスト
static char MoneyViewBuf[16] = "x";	//編集表示用バッファ
static char *s_MoneyList[] = {
	MoneyViewBuf,
	NULL,
};

//	フェード状態
static int s_fadeDegree = 0;	//フェード度合い。
●shop_Init
初期化です。
お店の状態オブジェクト作成とフェードアウトを解除します。

CODE:

//----------------------------------------------------------------------
//	SHOP初期化
//----------------------------------------------------------------------
void shop_Init()
{
	//	SHOPの状態管理オブジェクトの作成。
	s_ShopStateObj = STM_Init(SHOP_STATE_MAX);
	//	フェード状態をクリアする。
	shop_SetFadeDegree( 0 );
}
●shop_End
お店の状態オブジェクトを破棄します。

CODE:

//----------------------------------------------------------------------
//	SHOP終了
//----------------------------------------------------------------------
void shop_End()
{
	//	SHOPの状態管理オブジェクトの破棄
	STM_End(s_ShopStateObj);
}
●shop_Main
これはあまりよい見本とは言えないコードです。長すぎました。
実際には、工夫してシナリオのような制御方法にした方がメンテナンス性が高いと思います。

1.準備・初期化
最初のフレームなら様々な初期化を行います。
まず、イベント処理からお店の種別を得て、お店の最初の状態を決定します。
この時、STM_ResetStateを使うのは、道具屋→道具屋と2買い続けて同じ店に入ると初期化されない問題があったからです。
抜けたときのお店状態と最初のお店状態が同じだとフレームカウントが初期化されない問題がありました。
アイテムの選択番号はs_ItemSelno未選択にしておきます。
s_MsgWinNoはシナリオで表示しているメッセージウィンドウの番号を保存しておきます。
s_MoneyWinNoは、shop_NewWinMoneyViewで生成したお金表示用のウィンドウの番号です。

2.道具屋の状態管理。
ここからは状態管理がややこしいので図を用意しました。図と合わせて説明をお読みください。
SHOPメニュー状態遷移図.png
 ●SHOP_STATE_ITEMSEL
  最初の状態でアイテム一覧を表示して購入する商品を選んで貰います。
  メッセージを出しながら独立してアイテム一覧を選択できると言うめんど臭い事が出来ていたりします。
  これもウィンドウシステムをちゃんと組んだお陰ですね(自画自賛)。
  最後にメニューボタンの道具屋を抜けるチェックをしています。
 
 ●SHOP_STATE_BUYSEL
  選んだアイテムを買うか問い合せます。
  YESならアイテムを購入しますが、アイテムを入れる袋がいっぱいならSHOP_STATE_BUYSKIPに遷移します。
  うまく購入できたらお金をいただいてSHOP_STATE_BUYに遷移します。
  NOならSHOP_STATE_ITEMSELに戻ります。
 
 ●SHOP_STATE_BUY
  お礼のメッセージを表示して、表示終了でSHOP_STATE_ITEMSELに戻ります。
 
 ●SHOP_STATE_BUYSKIP
  袋がいっぱいだよを表示して、表示終了でSHOP_STATE_ITEMSELに戻ります。
 
  動くとこんな感じです。
道具屋.png
3.宿屋の状態管理。
こっちは、宿屋です。
SHOPメニュー状態遷移図.png
 ●SHOP_STATE_INN_PRICE
  メッセージで料金を提示します。表示終了でSHOP_STATE_INN_YNSELに移ります。
 
 ●SHOP_STATE_INN_YNSEL
  YESでお金が足りるならSHOP_STATE_INN_MESに移ります。足りない場合はSHOP_STATE_INN_SKIPに移ります。
  NOならお店を抜けます。
 
 ●SHOP_STATE_INN_MES
  おやすみなさいを表示して、表示終了でSHOP_STATE_INN_SLEEPに移ります。
 
 ●SHOP_STATE_INN_SLEEP
  お金をいただいて回復します。
  画面をフェードアウト/インして寝たことを演出します。終わったらお店を抜けます。
 
 ●SHOP_STATE_INN_SKIP
  お金が足らないことを表示して、表示終了でお店を抜けます。
 
 動くとこんな感じです。
宿屋.png
4.抜ける処理
 お店を抜けるフラグが立っていたら、お店用に開いたウィンドウを閉じて状態遷移をするための戻り値TRUEを返します。
 それ以外はお店継続で、FALSEを返します。

CODE:

//----------------------------------------------------------------------
//	SHOP処理
//----------------------------------------------------------------------
int shop_Main(int frame,PlayerParam_t *playerParam)
{
	int bExit = FALSE;	//抜ける
	
	//------------------------------
	//	準備・初期化
	//------------------------------
	//	今のゲーム状態のフレームをウィンドウ管理に設定。
	winmng_SetFrame(frame);
	
	//	お金の表示の準備
	shop_MakeMoneyView(playerParam);
	
	//	最初のフレーム?
	if( frame == 0 ) {
		//	入店するSHOPタイプ番号を得る。
		int shopNo = event_GetShopNo();
		MACRO_ASSERT(shopNo=0);
		MACRO_ASSERT(s_ItemSelnomoney -= s_ShopItems[s_ItemSelno].price;
				MACRO_ASSERT(playerParam->money>=0);
				//	次のフレームで遷移。
				STM_ChangeState(s_ShopStateObj,SHOP_STATE_BUY);//購入処理に移る。
			} else {
				//	増やせない。
				//	次のフレームで遷移。
				STM_ChangeState(s_ShopStateObj,SHOP_STATE_BUYSKIP);//購入できなかったに移る。
			}
			break;

		case YNSEL_NO:	//いいえ
			//	購入選択ウィンドウを閉じる。
			shop_CheckDelWin( &s_ShopWinNo2 );
			//	次のフレームで遷移。
			STM_ChangeState(s_ShopStateObj,SHOP_STATE_ITEMSEL);//アイテム選択に移る。
			break;
		}
		break;
	
	case SHOP_STATE_BUY:		//	道具屋:購入メッセージ
		//	道具屋:購入メッセージ
		if( shop_ComMsg(playerParam,"道具屋「おっ、買ってくれてありがとうな」",0) ) {
			//	次のフレームで遷移。
			STM_ChangeState(s_ShopStateObj,SHOP_STATE_ITEMSEL);//アイテム選択に移る。
		}
		break;
		
	case SHOP_STATE_BUYSKIP:		//	道具屋:購入できなかった
		//	道具屋:購入
		if( shop_ComMsg(playerParam,"道具屋「残念だが、袋がいっぱいなようだ。余裕があるときに買ってくんな」",0) ) {
			//	次のフレームで遷移。
			STM_ChangeState(s_ShopStateObj,SHOP_STATE_ITEMSEL);//アイテム選択に移る。
		}
		break;
	
		//------------------------------
		//	宿屋
		//------------------------------
	case SHOP_STATE_INN_PRICE:	//	宿屋:料金の提示
		//	宿屋:料金の提示
		if( shop_ComMsg(playerParam,"宿屋「お泊りは、一泊%dゼニーとお得な料金となっております」",INN_CHARGE_PRICE) ) {
			//	次のフレームで遷移。
			STM_ChangeState(s_ShopStateObj,SHOP_STATE_INN_YNSEL);//Y/N選択
		}
		break;
	
	case SHOP_STATE_INN_YNSEL:	//	宿屋:Y/N選択
		//	宿屋:Y/N選択
		switch( shop_ComYnSel(playerParam,"宿屋「%dゼニーですが、お泊りになりますか?」",INN_CHARGE_PRICE,&s_ShopWinNo) ) {
		case YNSEL_YES:	//はい
			//	Y/N選択ウィンドウを閉じる。
			shop_CheckDelWin( &s_ShopWinNo );	//お店ウィンドウ番号
			//	お金が足りる?
			if( playerParam->money >= INN_CHARGE_PRICE ) {
				//	次のフレームで遷移。
				STM_ChangeState(s_ShopStateObj,SHOP_STATE_INN_MES);//おやすみなさい表示に移る。
			} else {
				//	次のフレームで遷移。
				STM_ChangeState(s_ShopStateObj,SHOP_STATE_INN_SKIP);//お金が足りません
			}
			break;
		case YNSEL_NO:	//いいえ
			//	SHOPを抜けます。
			bExit = TRUE;
			break;
		}
		break;
	
	case SHOP_STATE_INN_MES:	//	宿屋:おやすみなさい表示
		//	宿屋:おやすみなさい表示
		if( shop_ComMsg(playerParam,"宿屋「どうぞ、ごゆっくり」",0) ) {
			//	次のフレームで遷移。
			STM_ChangeState(s_ShopStateObj,SHOP_STATE_INN_SLEEP);//宿泊に移る。
		}
		break;
	
	case SHOP_STATE_INN_SLEEP:	//	宿屋:宿泊
		//	宿屋:宿泊
		if( shop_InnSleep(playerParam,INN_CHARGE_PRICE) ) {
			//	次のフレームで遷移。
			bExit = TRUE;
		}
		break;
	
	case SHOP_STATE_INN_SKIP:	//	宿屋:お金が足りません
		//	宿屋:宿泊しない
		if( shop_ComMsg(playerParam,"宿屋「申し訳ありません。ゼニーが足らないようです」",0) ) {
			//	次のフレームで遷移。
			bExit = TRUE;
		}
		break;
	}
	
	//------------------------------
	//	抜ける処理
	//------------------------------
	
	//	抜ける?
	if( bExit ) {
		//	SHOPで使う可能性のあるウィンドウを閉じる。
		shop_CheckDelWin( &s_MoneyWinNo );	//お金表示・ウィンドウ番号
		shop_CheckDelWin( &s_ShopWinNo );	//お店ウィンドウ番号
		shop_CheckDelWin( &s_ShopWinNo2 );	//お店ウィンドウ番号2
		//	次のフレームで遷移。
		return TRUE;
	}
	
	//	継続する。
	return FALSE;
}
●shop_Draw
ウィンドウの表示と宿泊のフェードアウト/インの制御をしています。
フェードアウト/インは黒の一枚板をs_fadeDegreeで示される透明度で一番上に表示しているだけです。

CODE:

//----------------------------------------------------------------------
//	SHOP描画
//----------------------------------------------------------------------
void shop_Draw()
{
	//	有効なウィンドウの描画
	winmng_Draw();
	//	フェードのコントロール
	int color	= GetColor( 0,0,0 );
	SetDrawBlendMode(DX_BLENDMODE_ALPHA,s_fadeDegree);	//アルファブレンド
	DrawBox( 0, 0, SCREEN_X, SCREEN_Y, color, TRUE ) ; 
	SetDrawBlendMode(DX_BLENDMODE_NOBLEND,255);	//ノーマルブレンド
}
●shop_ItemSelect
アイテム選択の処理です。
mesは、表示メッセージの組み立てに使います。
最初にアイテムの販売メニュー(アイテム名と金額)を組み立てますが、手持ちの金が購入金額に満たないアイテムはグレーに表示します。

最初のフレームなら、表示メッセージをmesに編集してメッセージウィンドウに設定します。
アイテム選択用のウィンドウをwinmng_GetWinParam()でメッセージウィンドウの位置から逆算した位置に表示しています。
最後にお金を表示するウィンドウを生成します。

winmng_UpdateMsg()で表示メッセージを更新、winmng_SelectMenu()でアイテムを選択します。
winmng_SelectMenu()でアイテムが選択されたとき、お金が足りていれば選択番号を保存して次の状態に遷移するためTRUEを返します。それ以外はFALSEでアイテム選択を維持します。

CODE:

//----------------------------------------------------------------------
//	道具屋:アイテム選択
//----------------------------------------------------------------------
static int shop_ItemSelect(PlayerParam_t *playerParam,char *format,int *pSelno,int *pWinNo)
{
	static char mes[MSG_BUFF_SIZE] = "";	//編集表示用バッファ
	int shopFrame = STM_GetFrameCount(s_ShopStateObj);	//SHOPのフレーム
	
	//	販売メニューの構成を組み立てる。
	for( int i=0 ; imoney money >= s_ShopItems[item_selno].price ) {
			//	選択番号を持ち帰る。
			*pSelno = item_selno;
			//	次のフレームで遷移。
			return TRUE;
		}
	}
	
	//	遷移しない。
	return FALSE;
}
●shop_ItemBuySelect

CODE:

//----------------------------------------------------------------------
//	道具屋:購入選択
//----------------------------------------------------------------------
static int shop_ItemBuySelect(PlayerParam_t *playerParam,char *format,int Selno)
{
	//ST2 買うか最終確認		→	お金を減らす。アイテムを追加。

	playerParam->money++;

	//	遷移しない
	return FALSE;
}
●shop_ComMsg
道具屋、宿屋共通のメッセージ処理です。
今までにも出てきたメッセージ処理で、指定された書式でメッセージを編集して表示しています。
メッセージが終了(正確にはメッセージが終了して決定ボタンを押したら)したら次に遷移するためTRUEを返します。
それまではFALSEで状態を維持します。

CODE:

//----------------------------------------------------------------------
//	共通:メッセージ処理
//----------------------------------------------------------------------
static int shop_ComMsg(PlayerParam_t *playerParam,char *format,int price)
{
	static char mes[MSG_BUFF_SIZE] = "";	//編集表示用バッファ
	int shopFrame = STM_GetFrameCount(s_ShopStateObj);	//SHOPのフレーム
	
	//	最初?
	if( shopFrame==0 ) {
		//	メッセージの編集。
		sprintf( mes, format, price );
		//	メッセージウィンドに表示
		winmng_SetActiveWin(s_MsgWinNo);
		winmng_SetMsg(mes,TRUE);	//	ウィンドウに表示するメッセージを設定
	}
	
	//	毎フレームの更新
	if( winmng_UpdateMsg(MES_SPEED) ) {
		//	遷移する。
		return TRUE;
	}
	
	//	遷移しない
	return FALSE;
}
●shop_ComYnSel
道具屋、宿屋共通のYN選択処理です。

最初のフレームなら、指定されたメッセージを編集・表示してメッセージウィンドウに表示します。
はい/いいえ選択用のウィンドウをwinmng_GetWinParam()でメッセージウィンドウの位置から逆算した位置に表示しています。

winmng_UpdateMsg()で表示メッセージを更新、winmng_SelectMenu()ではい/いいえを選択します。
winmng_SelectMenu()ではい/いいえ選択されたとき、戻り値でそれぞれYNSEL_YES/YNSEL_NOで戻ります。
もし、選択がキャンセルされたらYNSEL_NOを選んだことにします。
それ以外は遷移しないためYNSEL_NONを戻します。

CODE:

//----------------------------------------------------------------------
//	共通:Y/N選択
//----------------------------------------------------------------------
static int shop_ComYnSel(PlayerParam_t *playerParam,char *format,int price,int *pWinNo)
{
	static char mes[MSG_BUFF_SIZE] = "";	//編集表示用バッファ
	int shopFrame = STM_GetFrameCount(s_ShopStateObj);	//SHOPのフレーム
	static char *s_YnList[] = {
		"はい",
		"いいえ",
		NULL,
	};
	
	//	最初?
	if( shopFrame==0 ) {
		//	メッセージの編集。
		sprintf( mes, format, price );
		//	メッセージウィンドに表示
		winmng_SetActiveWin(s_MsgWinNo);
		winmng_SetMsg(mes,FALSE);	//	ウィンドウに表示するメッセージを設定
		//	選択メニューを設定
		int sizex = 150;
		int sizey = 55;
		int posx = (SCREEN_X-sizex) / 3;
		int posy = (SCREEN_Y-sizey) / 2;
		//	メッセージウィンドウに座標を合わせる
		int mpx,mpy,msizex,msizey;
		if( winmng_GetWinParam(s_MsgWinNo,&mpx,&mpy,&msizex,&msizey) ) {
			posy = mpy - sizey - 10;
		}
		*pWinNo = winmng_NewWin(posx,posy,sizex,sizey,NULL);
		winmng_SetMenu( s_YnList );
	}
	
	//	毎フレームのメッセージ更新
	winmng_SetActiveWin(s_MsgWinNo);
	winmng_UpdateMsg(MES_SPEED);
	
	//	選択の処理
	winmng_SetActiveWin(*pWinNo);
	int selno = winmng_SelectMenu();
	if( selno!=-1 ) {	//選択されたら
		if( selno == 0 )  {
			//	はいを選んだ。
			return YNSEL_YES;	//はい
		} else {
			//	いいえを選んだ。
			return YNSEL_NO;	//いいえ
		}
	}
	//	抜ける?
	if( g_MainData.key[g_MainData.key_menu] == 1 ) {
		//	いいえを選んだと同じ
		return YNSEL_NO;	//いいえ
	}
	
	//	遷移しない
	return YNSEL_NON;	//未選択。
}
●shop_InnSleep
宿泊処理で、最初のフレームで宿泊料金を頂いてHPMPを全回復します。

FADEOUT_IN_FRAMESを基準に半分の時間でフェードアウト、残りの時間でフェードインして泊まったことを演出しています(音楽がないので不完全ですけどね)。フェードアウト/インの度合いはshop_SetFadeDegree()関数で設定しています。

FADEOUT_IN_FRAMEに達したらフェード状態をクリアして次に遷移するためTRUEを返します。
それ以外はFALSEを返します。

CODE:

//----------------------------------------------------------------------
//	宿屋:宿泊
//----------------------------------------------------------------------
static int shop_InnSleep(PlayerParam_t *playerParam,int price)
{
	int shopFrame = STM_GetFrameCount(s_ShopStateObj);	//SHOPのフレーム
	#define	FADEOUT_IN_FRAMES	120
	
	//	最初?
	if( shopFrame==0 ) {
		//	宿泊料金を頂く
		playerParam->money -= price;
		//	回復処理
		party_Inn(playerParam);
	}
	
	//	所定フレームが過ぎたら遷移する。
	if( shopFrame > FADEOUT_IN_FRAMES ) {
		//	フェード状態をクリアする。
		shop_SetFadeDegree( 0 );
		//	遷移する。
		return TRUE;
	} else {
		int HalfFrames = (FADEOUT_IN_FRAMES/2);
		if( shopFrame > HalfFrames ) {
			//	フェードインする。
			shop_SetFadeDegree( (FADEOUT_IN_FRAMES-shopFrame)*255/HalfFrames );
		} else {
			//	フェードアウトする。
			shop_SetFadeDegree( (shopFrame)*255/HalfFrames );
		}
	}
	
	//	遷移しない
	return FALSE;
}
●shop_MakeMoneyView
お金を表示するために金額を文字列として編集します。

CODE:

//----------------------------------------------------------------------
//	お金表示の準備
//----------------------------------------------------------------------
static void shop_MakeMoneyView(PlayerParam_t *playerParam)
{
	sprintf( MoneyViewBuf, "%15d", playerParam->money );
}
●shop_NewWinMoneyView
お金を表示するウィンドウを生成します。
これも、winmng_GetWinParam()でメっセージウィンドウの座標を得て、右端に座標を合わせて表示させています。
最後にウィンドウ番号は戻り値として返しています。

CODE:

//----------------------------------------------------------------------
//	お金表示ウィンドウの作成
//----------------------------------------------------------------------
static int shop_NewWinMoneyView()
{
	//	とりあえずの値。
	int sizex = 150;
	int sizey = 40;
	int posx = (SCREEN_X-sizex) / 8 * 7;
	int posy = (SCREEN_Y-sizey) / 3 * 2;
	
	//	メッセージウィンドウに座標を合わせる
	int mpx,mpy,msizex,msizey;
	if( winmng_GetWinParam(s_MsgWinNo,&mpx,&mpy,&msizex,&msizey) ) {
		posx = mpx + msizex - sizex;
		posy = mpy - sizey - 10;
	}
	
	//	表示ウィンドウの作成
	int winNo = winmng_NewWin(posx,posy,sizex,sizey,"お金");
	winmng_SetList( s_MoneyList );
	
	//	ウィンドウ番号を持ち帰る。
	return winNo;
}
●shop_CheckDelWin
ウィンドウ番号が-1じゃ無ければ指定されたウィンドウを閉じて、ウィンドウ番号に-1を入れます。

CODE:

//----------------------------------------------------------------------
//	管理番号のウィンドウを閉じる。管理番号を初期化。
//----------------------------------------------------------------------
static void shop_CheckDelWin( int *pWinNo )
{
	//	ガード
	MACRO_ASSERT( pWinNo!=NULL );

	//	使われている?
	if( *pWinNo!=-1 ) {
		//	ウィンドウを閉じる。
		winmng_DelWin(*pWinNo);
		//	管理番号を初期化
		*pWinNo = -1;
	}
}
●shop_SetFadeDegree
s_fadeDegreeに値を設定します。
関数にしたのは、明確化したからです。

CODE:

//----------------------------------------------------------------------
//	フェード状態を設定。255で黒。0でクリア。
//----------------------------------------------------------------------
static void shop_SetFadeDegree( int fade )
{
	//	設定する。
	s_fadeDegree = fade;
}
以上でお店処理は終了です。
長かったですね。でも、もう少し続きますのでお付き合い下さい。

[gameMain.cpp]
ゲームメインにちゃんとしたお店処理を組み込みます。
●インクルード
お店のヘッダを追加します。

CODE:

#include "shop.h"
●GameMain_Init
大幅には変えてないのですが、shop_Init()の追加とSTM_ResetState()に変わっています。

CODE:

//----------------------------------------------------------------------
//	ゲーム本編の初期化
//----------------------------------------------------------------------
void GameMain_Init(GameMainInitType_t initType)
{
	//	モードの設定
	s_GameMainData.initType = initType;
	
	//	初回?
	if( s_GameMainData.bFirstInit == FALSE ) {
		s_GameMainData.bFirstInit = TRUE;
		//	ゲーム本編の状態管理オブジェクトの作成。
		//	オブジェクトと言ってもC++のクラスとは無関係です。
		s_GameMainData.StateObj = STM_Init(GAMEMAIN_STATE_MAX);
		//	主人公キャラオブジェクトの作成。
		s_GameMainData.mapMoveData.PlayerObj = char_Load(PLAYER_FILENAME,PLAYER_CHAR_XNUM,PLAYER_CHAR_YNUM);
		//	主人公キャラオブジェクトの仮の初期座標や向き
		s_GameMainData.mapMoveData.player_px = ((SCREEN_X/CHAR_PIXEL_SIZEX)/2-1) * CHAR_PIXEL_SIZEX;
		s_GameMainData.mapMoveData.player_py = ((SCREEN_Y/CHAR_PIXEL_SIZEY)/2+2) * CHAR_PIXEL_SIZEY;
		s_GameMainData.mapMoveData.player_muki = CHAR_MUKI_DOWN;
		//	マップ管理の初期化
		map_Init(g_MapDefDatas);
		//	イベント処理の初期化
		event_Init("town");	//初期スタートのマップ情報
		//	起動するイベントの情報を設定する。
		event_SetEvent(EVENT_TYPE_NEW_START,0);	//初期スタート時イベント
		//	パーティ(プレーヤーのパラメータ)を初期化
		party_init(&(s_GameMainData.playerParam));
		//	メニュー初期化
		menu_Init();
		//	SHOP初期化
		shop_Init();
	}
	
	//	ゲーム本編の状態を強制初期化
	STM_ResetState(s_GameMainData.StateObj,GAMEMAIN_STATE_MAPLOAD);//マップロード処理へ遷移。
}
●GameMain_End
shop_End()の追加です。

CODE:

//----------------------------------------------------------------------
//	ゲーム本編の終了
//----------------------------------------------------------------------
void GameMain_End()
{
	//	ゲーム本編の状態管理オブジェクトの破棄
	STM_End(s_GameMainData.StateObj);
	//	主人公キャラオブジェクトの破棄。
	char_Delete(s_GameMainData.mapMoveData.PlayerObj);
	//	マップ管理の終了
	map_End();
	//	メニュー終了
	menu_End();
	//	SHOP終了
	shop_End();
}
●GameMain_Event
関数の呼び出しなので変更分だけ書いておきます。
要するにイベント処理にパラメータが増えています。

CODE:

	//	イベントを実行する。
	int rtnCode = event_Main(frame,&s_GameMainData.mapMoveData);
		↓
	//	イベントを実行する。
	int rtnCode = event_Main(frame,&(s_GameMainData.mapMoveData),&(s_GameMainData.playerParam)) ;
●GameMain_Shop
ショップ処理は、shop_Main()で処理しています。
TRUEが戻ってきたらSTM_SetBackState()でイベント処理に戻ります。
mapMove_Draw()でマップとキャラクタ表示。
shop_Draw();でお店に関係あるものの表示です。

CODE:

//----------------------------------------------------------------------
//	お店で買い物中
//----------------------------------------------------------------------
static void GameMain_Shop()
{
	//	今のフレーム
	int frame = STM_GetFrameCount(s_GameMainData.StateObj);
	
	//	実際のSHOP処理
	if( shop_Main(frame,&(s_GameMainData.playerParam)) ) {
		//	前の状態に戻す。フレームカウントはそのまま。
		STM_SetBackState(s_GameMainData.StateObj,GAMEMAIN_STATE_EVENT);//イベント中へ遷移。
	}
	
	//	マップとキャラクタ表示処理
	mapMove_Draw(&s_GameMainData.mapMoveData,frame,FALSE);
	
	//	SHOPの描画
	shop_Draw();
}
以上、ゲームメインでした。

長くなりましたね。
一旦ここで切りましょうか。
次回は、下準備が出来たのでいよいよシナリオにお店やら宝箱を組み込みます。

コメントはまだありません。