본문 바로가기
Programming I/C. C++

Text Rpg _C, C++

by 김 원 2023. 3. 7.

# 작성 코드

// Text RPG 만들기
#include <iostream>
#include <ctime>

#ifndef DBG_NEW 
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ ) 
#define new DBG_NEW 
#endif

using namespace std;

enum PlayerState { ENTRANCE, MAIN, SKILL, INVENTORY, STORE, HUNTINGGROUND, BATTLE };

struct PlayerInfo
{
	string sName = "";
	string sGender = "";
	string sSpecies = "";
	string sJob = "";
	int iLv = 0;
	int iHp = 0;
	int iCurrHp = 0;
	int iAttack = 0;
	int iDefense = 0;
	int iEx = 0;
	int iCoin = 0;
};
struct MonsterInfo
{
	string sName = "";
	string sProperty = "";
	int iLv = 0;
	int iHp = 0;
	int iAttack = 0;
	int iEx = 0;
	int iCoin = 0;
};
struct SkillInfo
{
	string sName = "미보유";
	int iSkillLv = 0;
	int iDamage = 0;
	int iDefense = 0;
	int iRecovery = 0;

	int iUseCoint = 0;
};
struct PlayerInvenInfo
{
	string sName = "미장착";
	string sItemEffect = "";
	int iEffectNum = 0;
	int iCoin = 0;

	int iNum = 0;
	int iCount = 0;
};
#pragma region 선언한 함수 목록
void SavePlayerInfo(PlayerInfo _pplayerInfo, SkillInfo _tplayerSkill[], PlayerInvenInfo _tEquipInven[], PlayerInvenInfo _tHaveInven[], FILE* _fPlayerSave);
PlayerInfo* EntranceState(PlayerState* _pplayerstate, FILE* _fPlayerSave, SkillInfo _tplayerSkill[], PlayerInvenInfo _tEquipInven[], PlayerInvenInfo _tHaveInven[]);
void MainState(PlayerState* _pplayerstate, PlayerInfo* _pplayerInfo, bool* _pgameover);
void SkillState(PlayerState* _pplayerstate, PlayerInfo* _tplayerInfo, SkillInfo _tplayerSkill[]);
void PlayerInvenTory(PlayerState* _pplayerstate, PlayerInvenInfo _tEquipInven[], PlayerInvenInfo _tHaveInven[], PlayerInfo* _tplayerInfo);
void ArrSort(int _iInputNum, PlayerInvenInfo _tlocation[], PlayerInvenInfo _tDatamove[]);
void StoreState(PlayerState* _pplayerstate, PlayerInfo* _pplayerInfo, PlayerInvenInfo _tHaveInven[]);
void HuntingGround(PlayerState* _pplayerstate, PlayerInfo* _pplayerInfo, MonsterInfo** _ppMonsterInfo);
void BattlwState(PlayerState* _pplayerstate, PlayerInfo* _pplayerInfo, MonsterInfo* _pmonsterInfo, SkillInfo _tplayerSkill[]);

MonsterInfo MonsterCreat(int _iLvMons);
void PlayerStatsUpdate(PlayerInfo* _tplayerInfo, PlayerInvenInfo _pequipInven[], int iNum, bool _btrue);
void PlayerLvUp(PlayerInfo* _tplayerInfo, SkillInfo _tplayerSkill[]);
void PlayerInfoPrint(PlayerInfo _tplayerInfo);
void PlayerSkillInfoPrint(SkillInfo _tplayerSkill[]);
void MonsterInfoPrint(MonsterInfo _tmonsterInfo);
#pragma endregion 선언한 함수 목록

void main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	srand(unsigned(time(nullptr)));

	FILE* fPlayerSave = nullptr;
	PlayerState tPlayerstate = ENTRANCE;
	PlayerInfo* pPlayer = nullptr;
	MonsterInfo* pMonster = nullptr;

	SkillInfo tPlayerSkill[3]{};
	PlayerInvenInfo pEquipInven[3]{};
	PlayerInvenInfo pHaveInven[3]{};
	bool bGameOver(false);

	while (bGameOver != true)
	{
		switch (tPlayerstate)
		{
		case ENTRANCE:
			pPlayer = EntranceState(&tPlayerstate, fPlayerSave, tPlayerSkill, pEquipInven, pHaveInven);
			SavePlayerInfo(*pPlayer, tPlayerSkill, pEquipInven, pHaveInven, fPlayerSave);
			break;
		case MAIN:
			MainState(&tPlayerstate, pPlayer, &bGameOver);
			break;
		case SKILL:
			SkillState(&tPlayerstate, pPlayer, tPlayerSkill);
			SavePlayerInfo(*pPlayer, tPlayerSkill, pEquipInven, pHaveInven, fPlayerSave);
			break;
		case INVENTORY:
			PlayerInvenTory(&tPlayerstate, pEquipInven, pHaveInven, pPlayer);
			SavePlayerInfo(*pPlayer, tPlayerSkill, pEquipInven, pHaveInven, fPlayerSave);
			break;
		case STORE:
			StoreState(&tPlayerstate, pPlayer, pHaveInven);
			SavePlayerInfo(*pPlayer, tPlayerSkill, pEquipInven, pHaveInven, fPlayerSave);
			break;
		case HUNTINGGROUND:
			HuntingGround(&tPlayerstate, pPlayer, &pMonster);
			break;
		case BATTLE:
			BattlwState(&tPlayerstate, pPlayer, pMonster, tPlayerSkill);
			delete pMonster;
			pMonster = nullptr;
			SavePlayerInfo(*pPlayer, tPlayerSkill, pEquipInven, pHaveInven, fPlayerSave);
			break;
		default:
			break;
		}
	}

	if (pPlayer != nullptr)
	{
		delete pPlayer;
		pPlayer = nullptr;
	}
}

void SavePlayerInfo(PlayerInfo _pplayerInfo, SkillInfo _tplayerSkill[], PlayerInvenInfo _tEquipInven[], PlayerInvenInfo _tHaveInven[], FILE* _fPlayerSave)
{
	int itrue = fopen_s(&_fPlayerSave, "../JS_230303_H(TextRPG_3)_2/PlayerSaveInfo.txt", "wb");

	if (0 == itrue)
	{
		fwrite(&_pplayerInfo, sizeof(_pplayerInfo), 1, _fPlayerSave);
		fwrite(_tplayerSkill, sizeof(SkillInfo), 3, _fPlayerSave);
		fwrite(_tEquipInven, sizeof(PlayerInvenInfo), 3, _fPlayerSave);
		fwrite(_tHaveInven, sizeof(PlayerInvenInfo), 3, _fPlayerSave);
		
	    fclose(_fPlayerSave);
	}
	else
	{
		cout << "플레이어 정보 저장 실패" << endl;
		system("pause");
	}
}

PlayerInfo* EntranceState(PlayerState* _pplayerstate, FILE* _fPlayerSave, SkillInfo _tplayerSkill[], PlayerInvenInfo _tEquipInven[], PlayerInvenInfo _tHaveInven[])
{
	PlayerInfo* tPlayer = new PlayerInfo;
	string sNameStr("");
	int iInput(0), itrue(0);
	bool bStart(false);

	while (!bStart)
	{
		// 입구 시작 ------------------------------------------
		cout << "Text RPG에 오신 것을 환영합니다." << endl << endl;

		cout << "1) 게임시작. 2) 불러오기 : ";
		cin >> iInput;
		system("cls");

		if (iInput == 1)
		{
			// 종족 선택 ------------------------------------------
			cout << "원하시는 종족을 선택해주세요." << endl;
			cout << "1) 인간. 2) 엘프. 3) 수인 : ";
			cin >> iInput;
			system("cls");

			switch (iInput)
			{
			case 1:
				(*tPlayer).sSpecies = "인간";
				(*tPlayer).iHp = 100;
				(*tPlayer).iCurrHp = 100;
				break;
			case 2:
				(*tPlayer).sSpecies = "엘프";
				(*tPlayer).iHp = 120;
				(*tPlayer).iCurrHp = 120;
				break;
			case 3:
				(*tPlayer).sSpecies = "수인";
				(*tPlayer).iHp = 150;
				(*tPlayer).iCurrHp = 150;
				break;
			default:
				cout << "지원하지 않는 입력 값 입니다." << endl;
				break;
			}

			// 성별 선택 ------------------------------------------
			cout << "원하시는 성별을 선택해주세요." << endl;
			cout << "1) 여자. 2) 남자 : ";
			cin >> iInput;
			system("cls");

			if (iInput == 1)
			{
				(*tPlayer).sGender = "여자";
				(*tPlayer).iDefense = 10;
			}
			else if (iInput == 2)
			{
				(*tPlayer).sGender = "남자";
				(*tPlayer).iDefense = 20;
			}

			// 직업 선택 ------------------------------------------
			cout << "원하시는 직업을 선택해주세요." << endl;
			cout << "1) 전사. 2) 마법사. 3) 도적 : ";
			cin >> iInput;
			system("cls");

			switch (iInput)
			{
			case 1:
				(*tPlayer).sJob = "전사";
				(*tPlayer).iAttack = 10;
				break;
			case 2:
				(*tPlayer).sJob = "마법사";
				(*tPlayer).iAttack = 20;
				break;
			case 3:
				(*tPlayer).sJob = "도적";
				(*tPlayer).iAttack = 15;
				break;
			default:
				cout << "지원하지 않는 입력 값 입니다." << endl;
				break;
			}

			// 이름 입력 ------------------------------------------
			cout << "사용할 플레이어 이름을 입력하세요 : ";
			cin >> sNameStr;
			system("cls");
			(*tPlayer).sName = sNameStr;

			// 캐릭터 생성 기본 값 할당
			(*tPlayer).iLv = 1;
			(*tPlayer).iEx = 0;
			(*tPlayer).iCoin = 1000;

			bStart = true;
		}
		else if (iInput == 2)
		{
			itrue = fopen_s(&_fPlayerSave, "../JS_230303_H(TextRPG_3)_2/PlayerSaveInfo.txt", "rb");

			if (itrue == 0)
			{
				cout << "저장된 정보를 불러옵니다." << endl;
				fread(tPlayer, sizeof(*tPlayer), 1, _fPlayerSave);
				fread(_tplayerSkill, sizeof(SkillInfo), 3, _fPlayerSave);
				fread(_tEquipInven, sizeof(PlayerInvenInfo), 3, _fPlayerSave);
				fread(_tHaveInven, sizeof(PlayerInvenInfo), 3, _fPlayerSave);

				system("pause");
				system("cls");
				fclose(_fPlayerSave);
				bStart = true;
			}
			else
			{
				cout << "저장된 정보가 없습니다." << endl;
				system("pause");
				system("cls");
			}
		}

		if (iInput == 1 || (iInput == 2 && itrue == 0))
		{
			cout << "[SYSTEM] 선택하신 프로필 정보입니다." << endl << endl;
			PlayerInfoPrint(*tPlayer);
			system("pause");
			system("cls");
			*_pplayerstate = MAIN;
			return tPlayer;
		}
	}
}

void MainState(PlayerState* _pplayerstate, PlayerInfo* _pplayerInfo, bool* _pgameover)
{
	int iInput(0);

	// 메인화면 ------------------------------------------
	cout << "[메인화면]" << endl;
	cout << "---------------------------------------------------------------" << endl;
	cout << "1) 프로필. 2) 보유스킬. 3) 소지품. 4) 상점. 5) 사냥터. 6) 종료 : ";
	cin >> iInput;
	system("cls");

	switch (iInput)
	{
	case 1:
		PlayerInfoPrint(*_pplayerInfo);
		system("pause");
		break;
	case 2:
		*_pplayerstate = SKILL;
		break;
	case 3:
		*_pplayerstate = INVENTORY;
		break;
	case 4:
		*_pplayerstate = STORE;
		break;
	case 5:
		*_pplayerstate = HUNTINGGROUND;
		break;
	case 6:
		*_pgameover = true;
		break;
	default:
		cout << "지원하지 않는 입력 값 입니다." << endl;
		break;
	}

	system("cls");
}

void SkillState(PlayerState* _pplayerstate, PlayerInfo* _tplayerInfo, SkillInfo _tplayerSkill[])
{
	int iInput(0);

	// 스킬 강화 및 메인화면 이동
	while (true)
	{
		PlayerSkillInfoPrint(_tplayerSkill);
		cout << "보유 코인 : " << (*_tplayerInfo).iCoin << endl << endl;
		cout << "1) 스킬강화. 2) 메인화면 : ";
		cin >> iInput;

		if (iInput == 1)
		{
			cout << "강화하고 싶은 스킬 번호 선택 : ";
			cin >> iInput;

			if (iInput == 1)
			{
				if ((*_tplayerInfo).iCoin >= 200)
				{
					(*_tplayerInfo).iCoin -= 200;
					(_tplayerSkill[0]).iSkillLv += 1;
					(_tplayerSkill[0]).iDamage += 3;
				}
				else
				{
					cout << "코인이 부족합니다." << endl;
					system("pause");
				}
			}
			else if (iInput == 2)
			{
				if ((*_tplayerInfo).iCoin >= 200)
				{
					(*_tplayerInfo).iCoin -= 200;
					_tplayerSkill[1].iSkillLv += 1;
					_tplayerSkill[1].iDamage += 10;
					_tplayerSkill[1].iDefense += 5;
				}
				else
				{
					cout << "코인이 부족합니다." << endl;
					system("pause");
				}
			}
			else if (iInput == 3)
			{
				if ((*_tplayerInfo).iCoin >= 200)
				{
					(*_tplayerInfo).iCoin -= 200;
					(_tplayerSkill[2]).iSkillLv += 1;
					_tplayerSkill[2].iRecovery += 10;
				}
				else
				{
					cout << "코인이 부족합니다." << endl;
					system("pause");
				}
			}
			else
				cout << "지원하지 않는 입력 값 입니다." << endl;
			system("cls");
		}
		else if (iInput == 2)
		{
			system("cls");
			*_pplayerstate = MAIN;
			break;
		}
	}
}

void PlayerInvenTory(PlayerState* _pplayerstate, PlayerInvenInfo _tEquipInven[], PlayerInvenInfo _tHaveInven[], PlayerInfo* _tplayerInfo)
{
	int iInput(0), i_Input(0);

	while (true)
	{
		cout << "=============================================" << endl;
		cout << "[장착된 아이템]" << endl;
		cout << "---------------------------------------------" << endl;
		for (int i = 0; i < _tEquipInven[0].iCount; ++i)
		{
			cout << "장착된 아이템: " << i + 1 << " 번" << endl;
			cout << "아이템 이름 : " << _tEquipInven[i].sName << endl;
			cout << "아이템 효과 : " << _tEquipInven[i].sItemEffect << _tEquipInven[i].iEffectNum << "증가" << endl;
			cout << "---------------------------------------------" << endl;
		}
		cout << "=============================================" << endl;
		cout << "[보유중인 아이템]" << endl;
		cout << "---------------------------------------------" << endl;
		for (int i = 0; i < _tHaveInven[0].iCount; ++i)
		{
			cout << "보유중인 아이템: " << i + 1 << " 번" << endl;
			cout << "아이템 이름 : " << _tHaveInven[i].sName << endl;
			cout << "아이템 효과 : " << _tHaveInven[i].sItemEffect << _tHaveInven[i].iEffectNum << "증가" << endl;
			cout << "---------------------------------------------" << endl;
		}
		cout << "보유코인 : " << (*_tplayerInfo).iCoin << endl;
		cout << "=============================================" << endl;
		cout << "1) 아이템 장착. 2) 아이템 장착 해제. 3) 아이템 판매. 4) 메인화면 : ";
		cin >> iInput;

		switch (iInput)
		{
		case 1: // 아이템 장착 : 가지고 있는 배열 -> 장착 배열
			cout << "장착할 아이템 번호 입력: ";
			cin >> i_Input;
			switch (i_Input)
			{
			case 1:
				if (_tHaveInven[0].iCount > 0 && _tEquipInven[0].iCount < 3)
				{
					// 장착한 아이템 효과 플레이어에게 업데이트
					PlayerStatsUpdate(_tplayerInfo, _tHaveInven, 0, true);
					// 이동한 배열 초기화 및 정렬
					ArrSort(1, _tEquipInven, _tHaveInven);
				}
				break;
			case 2:
				if (_tHaveInven[0].iCount > 1 && _tEquipInven[0].iCount < 3)
				{
					PlayerStatsUpdate(_tplayerInfo, _tHaveInven, 1, true);
					ArrSort(2, _tEquipInven, _tHaveInven);
				}
				break;
			case 3:
				if (_tHaveInven[0].iCount > 2 && _tEquipInven[0].iCount < 3)
				{
					PlayerStatsUpdate(_tplayerInfo, _tHaveInven, 2, true);
					ArrSort(3, _tEquipInven, _tHaveInven);
				}
				break;
			default:
				break;
			}
			break;
		case 2:
			cout << "장착 해제할 아이템 번호 입력: ";
			cin >> i_Input;
			switch (i_Input)
			{
			case 1:
				if (_tHaveInven[0].iCount < 3 && _tEquipInven[0].iCount > 0)
				{
					PlayerStatsUpdate(_tplayerInfo, _tEquipInven, 0, false);
					ArrSort(1, _tHaveInven, _tEquipInven);
				}
				break;
			case 2:
				if (_tHaveInven[0].iCount < 3 && _tEquipInven[0].iCount > 1)
				{
					PlayerStatsUpdate(_tplayerInfo, _tEquipInven, 1, false);
					ArrSort(2, _tHaveInven, _tEquipInven);
				}
				break;
			case 3:
				if (_tHaveInven[0].iCount < 3 && _tEquipInven[0].iCount > 2)
				{
					PlayerStatsUpdate(_tplayerInfo, _tEquipInven, 2, false);
					ArrSort(3, _tHaveInven, _tEquipInven);
				}
				break;
			default:
				break;
			}
			break;
		case 3:
			cout << "판매할 아이템 번호 입력: ";
			cin >> i_Input;
			switch (i_Input)
			{
			case 1:
				if (_tHaveInven[0].iCount > 0)
				{
					_tplayerInfo->iCoin += _tHaveInven[0].iCoin;
					// 보유중인 아이템 배열 초기화 및 배열 당기기
					if (_tHaveInven[0].iCount == 1)
					{
						_tHaveInven[0].sName = "미장착";
						_tHaveInven[0].sItemEffect = "";
						_tHaveInven[0].iEffectNum = 0;
						_tHaveInven[0].iNum = 0;
						_tHaveInven[0].iCoin = 0;

						_tHaveInven[0].iCount -= 1;
					}
					else if (_tHaveInven[0].iCount == 2)
					{
						_tHaveInven[0].sName = _tHaveInven[1].sName;
						_tHaveInven[0].sItemEffect = _tHaveInven[1].sItemEffect;
						_tHaveInven[0].iEffectNum = _tHaveInven[1].iEffectNum;
						_tHaveInven[0].iNum = _tHaveInven[1].iNum;
						_tHaveInven[0].iCoin = _tHaveInven[1].iCoin;

						_tHaveInven[1].sName = "미장착";
						_tHaveInven[1].sItemEffect = "";
						_tHaveInven[1].iEffectNum = 0;
						_tHaveInven[1].iNum = 0;
						_tHaveInven[1].iCoin = 0;

						_tHaveInven[0].iCount -= 1;
					}
					else if (_tHaveInven[0].iCount == 3)
					{
						_tHaveInven[0].sName = _tHaveInven[1].sName;
						_tHaveInven[0].sItemEffect = _tHaveInven[1].sItemEffect;
						_tHaveInven[0].iEffectNum = _tHaveInven[1].iEffectNum;
						_tHaveInven[0].iNum = _tHaveInven[1].iNum;
						_tHaveInven[0].iCoin = _tHaveInven[1].iCoin;

						_tHaveInven[1].sName = _tHaveInven[2].sName;
						_tHaveInven[1].sItemEffect = _tHaveInven[2].sItemEffect;
						_tHaveInven[1].iEffectNum = _tHaveInven[2].iEffectNum;
						_tHaveInven[1].iNum = _tHaveInven[2].iNum;
						_tHaveInven[1].iCoin = _tHaveInven[2].iCoin;

						_tHaveInven[2].sName = "미장착";
						_tHaveInven[2].sItemEffect = "";
						_tHaveInven[2].iEffectNum = 0;
						_tHaveInven[2].iNum = 0;
						_tHaveInven[2].iCoin = 0;

						_tHaveInven[0].iCount -= 1;
					}
				}
				break;
			case 2:
				if (_tHaveInven[0].iCount > 1)
				{
					_tplayerInfo->iCoin += _tHaveInven[1].iCoin;
					if (_tHaveInven[0].iCount == 2)
					{
						_tHaveInven[1].sName = "미장착";
						_tHaveInven[1].sItemEffect = "";
						_tHaveInven[1].iEffectNum = 0;
						_tHaveInven[1].iNum = 0;
						_tHaveInven[1].iCoin = 0;

						_tHaveInven[0].iCount -= 1;
					}
					else if (_tHaveInven[0].iCount == 3)
					{
						_tHaveInven[1].sName = _tHaveInven[2].sName;
						_tHaveInven[1].sItemEffect = _tHaveInven[2].sItemEffect;
						_tHaveInven[1].iEffectNum = _tHaveInven[2].iEffectNum;
						_tHaveInven[1].iNum = _tHaveInven[2].iNum;
						_tHaveInven[1].iCoin = _tHaveInven[2].iCoin;

						_tHaveInven[2].sName = "미장착";
						_tHaveInven[2].sItemEffect = "";
						_tHaveInven[2].iEffectNum = 0;
						_tHaveInven[2].iNum = 0;
						_tHaveInven[2].iCoin = 0;

						_tHaveInven[0].iCount -= 1;
					}
				}
				break;
			case 3:
				if (_tHaveInven[0].iCount > 2)
				{
					_tplayerInfo->iCoin += _tHaveInven[2].iCoin;

					_tHaveInven[2].sName = "미장착";
					_tHaveInven[2].sItemEffect = "";
					_tHaveInven[2].iEffectNum = 0;
					_tHaveInven[2].iNum = 0;
					_tHaveInven[2].iCoin = 0;

					_tHaveInven[0].iCount -= 1;
				}
				break;
			default:
				break;
			}
			break;
		case 4:
			system("cls");
			*_pplayerstate = MAIN;
			return;
		default:
			break;
		}
		system("cls");
	}
}

void ArrSort(int _iInputNum, PlayerInvenInfo _tlocation[], PlayerInvenInfo _tDatamove[])
{
	switch (_iInputNum)
	{
	case 1:
		// 원하는 배열로 이동
		_tlocation[_tlocation[0].iCount].sName = _tDatamove[0].sName;
		_tlocation[_tlocation[0].iCount].sItemEffect = _tDatamove[0].sItemEffect;
		_tlocation[_tlocation[0].iCount].iEffectNum = _tDatamove[0].iEffectNum;
		_tlocation[_tlocation[0].iCount].iNum = _tDatamove[0].iNum;
		_tlocation[_tlocation[0].iCount].iCoin = _tDatamove[0].iCoin;
		_tlocation[0].iCount++;

		// 이동한 아이템 배열 초기화 및 배열 당기기
		if (_tDatamove[0].iCount == 1)
		{
			_tDatamove[0].sName = "미장착";
			_tDatamove[0].sItemEffect = "";
			_tDatamove[0].iEffectNum = 0;
			_tDatamove[0].iNum = 0;
			_tDatamove[0].iCoin = 0;
			_tDatamove[0].iCount -= 1;
		}
		else if (_tDatamove[0].iCount == 2)
		{
			_tDatamove[0].sName = _tDatamove[1].sName;
			_tDatamove[0].sItemEffect = _tDatamove[1].sItemEffect;
			_tDatamove[0].iEffectNum = _tDatamove[1].iEffectNum;
			_tDatamove[0].iNum = _tDatamove[1].iNum;
			_tDatamove[0].iCoin = _tDatamove[1].iCoin;

			_tDatamove[1].sName = "미장착";
			_tDatamove[1].sItemEffect = "";
			_tDatamove[1].iEffectNum = 0;
			_tDatamove[1].iNum = 0;
			_tDatamove[1].iCoin = 0;
			_tDatamove[0].iCount -= 1;
		}
		else if (_tDatamove[0].iCount == 3)
		{
			_tDatamove[0].sName = _tDatamove[1].sName;
			_tDatamove[0].sItemEffect = _tDatamove[1].sItemEffect;
			_tDatamove[0].iEffectNum = _tDatamove[1].iEffectNum;
			_tDatamove[0].iNum = _tDatamove[1].iNum;
			_tDatamove[0].iCoin = _tDatamove[1].iCoin;

			_tDatamove[1].sName = _tDatamove[2].sName;
			_tDatamove[1].sItemEffect = _tDatamove[2].sItemEffect;
			_tDatamove[1].iEffectNum = _tDatamove[2].iEffectNum;
			_tDatamove[1].iNum = _tDatamove[2].iNum;
			_tDatamove[1].iCoin = _tDatamove[2].iCoin;

			_tDatamove[2].sName = "미장착";
			_tDatamove[2].sItemEffect = "";
			_tDatamove[2].iEffectNum = 0;
			_tDatamove[2].iNum = 0;
			_tDatamove[2].iCoin = 0;
			_tDatamove[0].iCount -= 1;
		}
		break;
	case 2:
		_tlocation[_tlocation[0].iCount].sName = _tDatamove[1].sName;
		_tlocation[_tlocation[0].iCount].sItemEffect = _tDatamove[1].sItemEffect;
		_tlocation[_tlocation[0].iCount].iEffectNum = _tDatamove[1].iEffectNum;
		_tlocation[_tlocation[0].iCount].iNum = _tDatamove[1].iNum;
		_tlocation[_tlocation[0].iCount].iCoin = _tDatamove[1].iCoin;
		_tlocation[0].iCount++;

		if (_tDatamove[0].iCount == 2)
		{
			_tDatamove[1].sName = "미장착";
			_tDatamove[1].sItemEffect = "";
			_tDatamove[1].iEffectNum = 0;
			_tDatamove[1].iNum = 0;
			_tDatamove[1].iCoin = 0;
			_tDatamove[0].iCount -= 1;
		}
		else if (_tDatamove[0].iCount == 3)
		{
			_tDatamove[1].sName = _tDatamove[2].sName;
			_tDatamove[1].sItemEffect = _tDatamove[2].sItemEffect;
			_tDatamove[1].iEffectNum = _tDatamove[2].iEffectNum;
			_tDatamove[1].iNum = _tDatamove[2].iNum;
			_tDatamove[1].iCoin = _tDatamove[2].iCoin;

			_tDatamove[2].sName = "미장착";
			_tDatamove[2].sItemEffect = "";
			_tDatamove[2].iEffectNum = 0;
			_tDatamove[2].iNum = 0;
			_tDatamove[2].iCoin = 0;
			_tDatamove[0].iCount -= 1;
		}
		break;
	case 3:
		_tlocation[_tlocation[0].iCount].sName = _tDatamove[2].sName;
		_tlocation[_tlocation[0].iCount].sItemEffect = _tDatamove[2].sItemEffect;
		_tlocation[_tlocation[0].iCount].iEffectNum = _tDatamove[2].iEffectNum;
		_tlocation[_tlocation[0].iCount].iNum = _tDatamove[2].iNum;
		_tlocation[_tlocation[0].iCount].iCoin = _tDatamove[2].iCoin;
		_tlocation[0].iCount++;

		_tDatamove[2].sName = "미장착";
		_tDatamove[2].sItemEffect = "";
		_tDatamove[2].iEffectNum = 0;
		_tDatamove[2].iNum = 0;
		_tDatamove[2].iCoin = 0;
		_tDatamove[0].iCount -= 1;
		break;
	default:
		break;
	}
}

void StoreState(PlayerState* _pplayerstate, PlayerInfo* _pplayerInfo, PlayerInvenInfo _tHaveInven[])
{
	int iInput(0);

	system("cls");
	cout << "=====================================" << endl;
	cout << "[아이템 상점]" << endl;
	cout << "-------------------------------------" << endl;
	cout << "1번. 멋진 검 ( 300 코인 )" << endl;
	cout << "   - 공격력 30 증가 ! " << endl << endl;
	cout << "2번. 멋진 방패 ( 500 코인 )" << endl;
	cout << "   - 방어력 20 증가 ! " << endl << endl;
	cout << "3번. 체력 회복_1회용 ( 1000 코인 )" << endl;
	cout << "   - 체력회복 100 증가 ! _1회 " << endl;
	cout << "-------------------------------------" << endl;
	cout << "보유코인 : " << _pplayerInfo->iCoin << endl;
	cout << "=====================================" << endl;
	cout << "1) 아이템 구매. 2) 메인화면 : ";
	cin >> iInput;
	if (iInput == 1)
	{
		cout << "구매할 아이템 번호 입력: ";
		cin >> iInput;

		switch (iInput)
		{
		case 1:
			if (_pplayerInfo->iCoin >= 300 && _tHaveInven[0].iCount < 3)
			{
				_tHaveInven[_tHaveInven[0].iCount].iNum = 1;
				_tHaveInven[_tHaveInven[0].iCount].sName = "멋진 검";
				_tHaveInven[_tHaveInven[0].iCount].sItemEffect = "공격력";
				_tHaveInven[_tHaveInven[0].iCount].iEffectNum = 30;
				_tHaveInven[_tHaveInven[0].iCount].iCoin = 300;
				_tHaveInven[0].iCount++;

				_pplayerInfo->iCoin -= 300;
				cout << "구매 성공!" << endl;
			}
			else
			{
				cout << "구매 실패!" << endl;
			}
			break;
		case 2:
			if (_pplayerInfo->iCoin >= 500 && _tHaveInven[0].iCount < 3)
			{
				_tHaveInven[_tHaveInven[0].iCount].iNum = 2;
				_tHaveInven[_tHaveInven[0].iCount].sName = "멋진 방패";
				_tHaveInven[_tHaveInven[0].iCount].sItemEffect = "방어력";
				_tHaveInven[_tHaveInven[0].iCount].iEffectNum = 20;
				_tHaveInven[_tHaveInven[0].iCount].iCoin = 500;
				_tHaveInven[0].iCount++;

				_pplayerInfo->iCoin -= 500;
				cout << "구매 성공!" << endl;
			}
			else
			{
				cout << "구매 실패!" << endl;
			}
			break;
		case 3:
			if (_pplayerInfo->iCoin >= 1000 && _tHaveInven[0].iCount < 3)
			{
				_tHaveInven[_tHaveInven[0].iCount].iNum = 3;
				_tHaveInven[_tHaveInven[0].iCount].sName = "체력 회복_1회용";
				_tHaveInven[_tHaveInven[0].iCount].sItemEffect = "체력";
				_tHaveInven[_tHaveInven[0].iCount].iEffectNum = 100;
				_tHaveInven[_tHaveInven[0].iCount].iCoin = 1000;
				_tHaveInven[0].iCount++;

				_pplayerInfo->iCoin -= 1000;
				cout << "구매 성공!" << endl;
			}
			else
			{
				cout << "구매 실패!" << endl;
			}
			break;
		default:
			break;
		}
		system("pause");
	}
	else if (iInput == 2)
	{
		system("cls");
		*_pplayerstate = MAIN;
	}
}

void HuntingGround(PlayerState* _pplayerstate, PlayerInfo* _pplayerInfo, MonsterInfo** _ppMonsterInfo)
{
	int iInput(0);

	PlayerInfoPrint(*_pplayerInfo);
	cout << endl;
	cout << "===========================================================" << endl;
	cout << "사냥터 입구]" << endl;
	cout << "-----------------------------------------------------------" << endl;
	cout << "1) 초급 사냥터. 2) 중급 사냥터. 3) 고급 사냥터. 4) 메인화면: ";
	cin >> iInput;
	system("cls");

	switch (iInput)
	{
	case 1:
		*_ppMonsterInfo = new MonsterInfo{};
		**_ppMonsterInfo = MonsterCreat(1);
		*_pplayerstate = BATTLE;
		break;
	case 2:
		*_ppMonsterInfo = new MonsterInfo{};
		**_ppMonsterInfo = MonsterCreat(2);
		*_pplayerstate = BATTLE;
		break;
	case 3:
		*_ppMonsterInfo = new MonsterInfo{};
		**_ppMonsterInfo = MonsterCreat(3);
		*_pplayerstate = BATTLE;
		break;
	case 4:
		*_pplayerstate = MAIN;
		break;
	default:
		break;
	}
}

MonsterInfo MonsterCreat(int _iLvMons)
{
	MonsterInfo tMonster{};
	int iMonsLv = rand() % 10 + 1;

	if (_iLvMons == 1)
	{
		tMonster.sName = "슬라임";
		tMonster.sProperty = "물속성";
		tMonster.iLv = iMonsLv;
		tMonster.iHp = 2 * iMonsLv;
		tMonster.iAttack = 2 * iMonsLv;
		tMonster.iEx = 10 * iMonsLv;
		tMonster.iCoin = 10 * iMonsLv;
	}
	else if (_iLvMons == 2)
	{
		tMonster.sName = "고블린";
		tMonster.sProperty = "풀속성";
		tMonster.iLv = iMonsLv + 10;
		tMonster.iHp = 10 * iMonsLv;
		tMonster.iAttack = 10 * iMonsLv;
		tMonster.iEx = 30 * iMonsLv;
		tMonster.iCoin = 20 * iMonsLv;
	}
	else if (_iLvMons == 3)
	{
		tMonster.sName = "드래곤";
		tMonster.sProperty = "불속성";
		tMonster.iLv = iMonsLv + 20;
		tMonster.iHp = 200 * iMonsLv;
		tMonster.iAttack = 15 * iMonsLv;
		tMonster.iEx = 100 * iMonsLv;
		tMonster.iCoin = 50 * iMonsLv;
	}

	return tMonster;
}

void MonsterInfoPrint(MonsterInfo _tmonsterInfo)
{
	if (_tmonsterInfo.iHp < 0)
	{
		_tmonsterInfo.iHp = 0;
	}
	cout << "=============================================" << endl;
	cout << "[생성된 몬스터]" << endl;
	cout << "---------------------------------------------" << endl;
	cout << "이름 : " << _tmonsterInfo.sName << "\t" << "속성 : " << _tmonsterInfo.sProperty << "\t" << "레벨 : " << _tmonsterInfo.iLv << endl;
	cout << "체력 : " << _tmonsterInfo.iHp << "\t" << "공격력 : " << _tmonsterInfo.iAttack << endl;
	cout << "=============================================" << endl;
}

void BattlwState(PlayerState* _pplayerstate, PlayerInfo* _pplayerInfo, MonsterInfo* _pmonsterInfo, SkillInfo _tplayerSkill[])
{
	int iInput(0), i_Input(0), iCount(0), iRan(0), iRanTrue(0);

	while (true)
	{
		system("cls");
		PlayerInfoPrint(*_pplayerInfo);
		MonsterInfoPrint(*_pmonsterInfo);

		cout << "1) 공격. 2) 도망 : ";
		cin >> iInput;

		iRan = rand() % 2 + 1;

		// 공격
		if (iInput == 1)
		{
			iCount++;

			// 보유 스킬 목록 출력 및 사용
			if (iCount % 5 == 0 && _tplayerSkill[0].iUseCoint >= 1)
			{
				PlayerSkillInfoPrint(_tplayerSkill);
				cout << "1) 사용할 스킬 선택: ";
				cin >> i_Input;
				system("cls");
				switch (i_Input)
				{
				case 1:
					if (_tplayerSkill[0].iUseCoint == 1)
					{
						(*_pmonsterInfo).iHp -= (*_pplayerInfo).iAttack + _tplayerSkill[0].iDamage;
						PlayerInfoPrint(*_pplayerInfo);
						MonsterInfoPrint(*_pmonsterInfo);
						cout << "회심의 공격 성공!" << endl;
					}
					break;
				case 2:
					if (_tplayerSkill[0].iUseCoint == 2)
					{
						(*_pmonsterInfo).iHp -= (*_pplayerInfo).iAttack + _tplayerSkill[1].iDamage;
						PlayerInfoPrint(*_pplayerInfo);
						MonsterInfoPrint(*_pmonsterInfo);
						cout << "스페셜 어택 성공!" << endl;
					}
					break;
				case 3:
					if (_tplayerSkill[0].iUseCoint == 3)
					{
						(*_pplayerInfo).iCurrHp += _tplayerSkill[2].iRecovery;
						if ((*_pplayerInfo).iCurrHp > (*_pplayerInfo).iHp)
							(*_pplayerInfo).iCurrHp = (*_pplayerInfo).iHp;
						PlayerInfoPrint(*_pplayerInfo);
						MonsterInfoPrint(*_pmonsterInfo);
						cout << "플레이어 생명력 회복 성공!" << endl;
					}
					break;
				default:
					cout << "지원하지 않는 입력 값 입니다." << endl;
					break;
				}
				system("pause");
			}
			else
			{
				system("cls");
				if (iRan == 1) // 플레이어가 몬스터 공격
				{
					(*_pmonsterInfo).iHp -= (*_pplayerInfo).iAttack;
					PlayerInfoPrint(*_pplayerInfo);
					MonsterInfoPrint(*_pmonsterInfo);
					cout << "플레이어 -> 몬스터 공격 성공!" << endl;
					cout << "몬스터 -> 플레이어 공격 실패!" << endl;
				}
				else // 몬스터가 플레이어 공격
				{
					iRanTrue = rand() % 10 + 1;
					if (iRanTrue < 3) // 공격 방어
					{
						PlayerInfoPrint(*_pplayerInfo);
						MonsterInfoPrint(*_pmonsterInfo);
						cout << "몬스터의 공격 방어 성공!" << endl;
					}
					else              // 방어 실패
					{
						(*_pplayerInfo).iCurrHp -= (*_pmonsterInfo).iAttack;
						PlayerInfoPrint(*_pplayerInfo);
						MonsterInfoPrint(*_pmonsterInfo);
						cout << "플레이어 -> 몬스터 공격 실패!" << endl;
						cout << "몬스터 -> 플레이어 공격 성공!" << endl;
					}
				}
				system("pause");
			}
			if ((*_pmonsterInfo).iHp <= 0)
			{
				cout << "몬스터 사망" << endl;
				(*_pplayerInfo).iEx += (*_pmonsterInfo).iEx;
				(*_pplayerInfo).iCoin += (*_pmonsterInfo).iCoin;
				PlayerLvUp(_pplayerInfo, _tplayerSkill);
				*_pplayerstate = HUNTINGGROUND;
				system("pause");
				system("cls");
				return;
			}
			if ((*_pplayerInfo).iCurrHp <= 0)
			{
				cout << "플레이어 사망" << endl;
				(*_pplayerInfo).iCurrHp = (*_pplayerInfo).iHp;
				*_pplayerstate = HUNTINGGROUND;
				system("pause");
				system("cls");
				return;
			}
		}
		// 도망
		else if (iInput == 2)
		{
			if (iRan == 1)
			{
				cout << "도망 성공!" << endl;
				*_pplayerstate = HUNTINGGROUND;
				system("pause");
				system("cls");
				return;
			}
			else
			{
				cout << "도망 실패!" << endl;
				system("pause");
			}
		}
		system("cls");
	}
}

void PlayerLvUp(PlayerInfo* _tplayerInfo, SkillInfo _tplayerSkill[])
{
	switch ((*_tplayerInfo).iLv)
	{
	case 1:
		if ((*_tplayerInfo).iEx >= 500)
		{
			(*_tplayerInfo).iLv += 1;
			(*_tplayerInfo).iHp += 50;
			(*_tplayerInfo).iCurrHp += 50;
			(*_tplayerInfo).iAttack += 20;
			(*_tplayerInfo).iDefense += 10;
			(*_tplayerInfo).iCoin += 500;
		}
		break;
	case 2:
		if ((*_tplayerInfo).iEx >= 1000)
		{
			(*_tplayerInfo).iLv += 1;
			(*_tplayerInfo).iHp += 50;
			(*_tplayerInfo).iCurrHp += 50;
			(*_tplayerInfo).iAttack += 20;
			(*_tplayerInfo).iDefense += 10;
			(*_tplayerInfo).iCoin += 500;

			_tplayerSkill[0].sName = "[ 회심의 공격 ]";
			_tplayerSkill[0].iSkillLv = 1;
			_tplayerSkill[0].iDamage = 5;
			_tplayerSkill[0].iDefense = 2;
			_tplayerSkill[0].iRecovery = 0;
			_tplayerSkill[0].iUseCoint = 1;
		}
		break;
	case 3:
		if ((*_tplayerInfo).iEx >= 1500)
		{
			(*_tplayerInfo).iLv += 1;
			(*_tplayerInfo).iHp += 50;
			(*_tplayerInfo).iCurrHp += 50;
			(*_tplayerInfo).iAttack += 20;
			(*_tplayerInfo).iDefense += 10;
			(*_tplayerInfo).iCoin += 500;
		}
		break;
	case 4:
		if ((*_tplayerInfo).iEx >= 2000)
		{
			(*_tplayerInfo).iLv += 1;
			(*_tplayerInfo).iHp += 50;
			(*_tplayerInfo).iCurrHp += 50;
			(*_tplayerInfo).iAttack += 20;
			(*_tplayerInfo).iDefense += 10;
			(*_tplayerInfo).iCoin += 500;
		}
		break;
	case 5:
		if ((*_tplayerInfo).iEx >= 2500)
		{
			(*_tplayerInfo).iLv += 1;
			(*_tplayerInfo).iHp += 100;
			(*_tplayerInfo).iCurrHp += 100;
			(*_tplayerInfo).iAttack += 25;
			(*_tplayerInfo).iDefense += 10;
			(*_tplayerInfo).iCoin += 500;

			_tplayerSkill[1].sName = "[ 스패셜 어택 ]";
			_tplayerSkill[1].iSkillLv = 1;
			_tplayerSkill[1].iDamage = 10;
			_tplayerSkill[1].iDefense = 5;
			_tplayerSkill[1].iRecovery = 0;
			_tplayerSkill[0].iUseCoint = 2;


		}
		break;
	case 6:
		if ((*_tplayerInfo).iEx >= 3000)
		{
			(*_tplayerInfo).iLv += 1;
			(*_tplayerInfo).iHp += 100;
			(*_tplayerInfo).iCurrHp += 100;
			(*_tplayerInfo).iAttack += 30;
			(*_tplayerInfo).iDefense += 10;
			(*_tplayerInfo).iCoin += 500;
		}
		break;
	case 7:
		if ((*_tplayerInfo).iEx >= 3500)
		{
			(*_tplayerInfo).iLv += 1;
			(*_tplayerInfo).iHp += 100;
			(*_tplayerInfo).iCurrHp += 100;
			(*_tplayerInfo).iAttack += 30;
			(*_tplayerInfo).iDefense += 20;
			(*_tplayerInfo).iCoin += 500;
		}
		break;
	case 8:
		if ((*_tplayerInfo).iEx >= 4000)
		{
			(*_tplayerInfo).iLv += 1;
			(*_tplayerInfo).iHp += 100;
			(*_tplayerInfo).iCurrHp += 100;
			(*_tplayerInfo).iAttack += 30;
			(*_tplayerInfo).iDefense += 20;
			(*_tplayerInfo).iCoin += 500;

			_tplayerSkill[2].sName = "[ 생명력 회복 ]";
			_tplayerSkill[2].iSkillLv = 1;
			_tplayerSkill[2].iDamage = 0;
			_tplayerSkill[2].iDefense = 0;
			_tplayerSkill[2].iRecovery = 50;
			_tplayerSkill[0].iUseCoint = 3;
		}
		break;
	case 9:
		if ((*_tplayerInfo).iEx >= 5000)
		{
			(*_tplayerInfo).iLv += 1;
			(*_tplayerInfo).iHp += 100;
			(*_tplayerInfo).iCurrHp += 100;
			(*_tplayerInfo).iAttack += 50;
			(*_tplayerInfo).iDefense += 30;
			(*_tplayerInfo).iCoin += 1000;
		}
		break;
	default:
		break;
	}
}

void PlayerStatsUpdate(PlayerInfo* _tplayerInfo, PlayerInvenInfo _pequipInven[], int iNum, bool _btrue)
{
	if (_btrue)
	{
		// 장착할때마다 스탯 업데이트
		if (_pequipInven[iNum].iNum == 1)
		{
			_tplayerInfo->iAttack += _pequipInven[iNum].iEffectNum;
		}
		else if (_pequipInven[iNum].iNum == 2)
		{
			_tplayerInfo->iDefense += _pequipInven[iNum].iEffectNum;
		}
		else if (_pequipInven[iNum].iNum == 3)
		{
			_tplayerInfo->iCurrHp += _pequipInven[iNum].iEffectNum;
			if (_tplayerInfo->iCurrHp > _tplayerInfo->iHp)
				_tplayerInfo->iCurrHp = _tplayerInfo->iHp;
		}
	}
	else if (!_btrue)
	{
		// 장착해제할때마다 스탯 업데이트
		if (_pequipInven[iNum].iNum == 1)
		{
			_tplayerInfo->iAttack -= _pequipInven[iNum].iEffectNum;
		}
		else if (_pequipInven[iNum].iNum == 2)
		{
			_tplayerInfo->iDefense -= _pequipInven[iNum].iEffectNum;
		}
	}
}

void PlayerInfoPrint(PlayerInfo _tplayerInfo)
{
	if (_tplayerInfo.iCurrHp < 0)
	{
		_tplayerInfo.iCurrHp = 0;
	}
	cout << "=============================================" << endl;
	cout << "[플레이어 프로필]" << endl;
	cout << "---------------------------------------------" << endl;
	cout << "이름 : " << _tplayerInfo.sName << "\t" << "성별 : " << _tplayerInfo.sGender << endl;
	cout << "레벨 : " << _tplayerInfo.iLv << "\t" << "경험치 : " << _tplayerInfo.iEx << endl;
	cout << "종족 : " << _tplayerInfo.sSpecies << "\t" << "직업 : " << _tplayerInfo.sJob << endl;
	cout << "체력 : " << _tplayerInfo.iCurrHp << "\t" << "공격력 : " << _tplayerInfo.iAttack << "\t" << "방어력 : " << _tplayerInfo.iDefense << endl;
	cout << "---------------------------------------------" << endl;
	cout << "보유코인 : " << _tplayerInfo.iCoin << endl;
	cout << "=============================================" << endl;
}

void PlayerSkillInfoPrint(SkillInfo _tplayerSkill[])
{
	cout << "[보유 스킬]" << endl;
	cout << "---------------------------" << endl;
	for (int i = 0; i < _tplayerSkill[0].iUseCoint; ++i)
	{
		cout << "스킬 번호 : " << i + 1 << " 번" << endl;
		cout << "스킬 이름 : " << _tplayerSkill[i].sName << endl;
		cout << "스킬 레벨 : " << _tplayerSkill[i].iSkillLv << " 레벨" << endl;
		cout << "스킬 효과 : 공격력 " << _tplayerSkill[i].iDamage << " 증가" << endl;
		cout << "스킬 효과 : 방어력 " << _tplayerSkill[i].iDefense << " 증가" << endl;
		cout << "스킬 효과 : 생명력 " << _tplayerSkill[i].iRecovery << " 증가" << endl;
		cout << "---------------------------" << endl;
	}
}

# 알게된 점

  • 파일에 값을 저장할 때에 주소값을 저장하는 것이 아니라 값 자체를 전달하여 저장하기
  • 보유한 스킬, 장착과 보유 아이템 저장 & 불러오기 구현 완료
  •   -> 얕은 복사 주의하기 : https://blog.naver.com/letsreadbook27/223027190148

 

  • 파일 입출력 시에는 주소(포인터 등)를 이용해야 함.
  •  -> 저장할 땐 &로 주소값 전달 및 읽어들일 땐 포인터에 저장하는 등.

 

  • 포인터값에 동적할당을 하고싶을 때에는 이중 포인터로 포인터값을 받아와 동적할당하여 사용 가능함.

# 의문점 / 추가 구현해볼 좋을 내용

  • Class를 사용하여 Text RPG 수정.
  • 동적 할당으로 스킬 배열 추가해보기 -> 실패 시 질문하거나 해결
  • 마무리 시 선택화면 오선택 값 막기