TextRPG

Jaemyeong Lee·2024년 11월 25일
0

어소트락2017

목록 보기
20/20

이 코드는 구조체와 열거형을 활용한 텍스트 기반 RPG 게임으로, 플레이어와 몬스터의 전투, 레벨업, 상점에서의 아이템 구매 및 장착 등의 기능을 구현합니다. 각 줄을 상세히 분석하고 해석하겠습니다.


헤더 파일 포함 및 네임스페이스 사용

#include <iostream>
#include <time.h>
using namespace std;
  • #include <iostream>: 표준 입출력 스트림(cin, cout)을 사용하기 위한 헤더 파일.
  • #include <time.h>: 현재 시간을 기준으로 난수 생성을 위한 헤더 파일.
  • using namespace std;: 표준 네임스페이스(std::) 생략.

열거형 정의

메인 메뉴

enum MAIN_MENU
{
	MM_NONE,
	MM_MAP,
	MM_STORE,
	MM_INVENTORY,
	MM_EXIT
};
  • 메뉴 옵션:
    • MM_NONE: 초기화 상태 또는 잘못된 입력.
    • MM_MAP: 맵 메뉴.
    • MM_STORE: 상점 메뉴.
    • MM_INVENTORY: 인벤토리 메뉴.
    • MM_EXIT: 게임 종료.

맵 난이도

enum MAP_TYPE
{
	MT_NONE,
	MT_EASY,
	MT_NORMAL,
	MT_HARD,
	MT_BACK
};
  • 맵 난이도:
    • MT_EASY: 쉬운 난이도.
    • MT_NORMAL: 보통 난이도.
    • MT_HARD: 어려운 난이도.
    • MT_BACK: 맵 메뉴에서 뒤로가기.

직업

enum JOB
{
	JOB_NONE,
	JOB_KNIGHT,
	JOB_ARCHER,
	JOB_WIZARD,
	JOB_END
};
  • 플레이어 직업:
    • JOB_KNIGHT: 기사.
    • JOB_ARCHER: 궁수.
    • JOB_WIZARD: 마법사.
    • JOB_END: 직업 배열의 끝 (사용 시 배열 크기 계산에 활용).

전투 상태

enum BATTLE
{
	BATTLE_NONE,
	BATTLE_ATTACK,
	BATTLE_BACK
};
  • 전투 메뉴:
    • BATTLE_ATTACK: 공격.
    • BATTLE_BACK: 도망가기.

장비 및 아이템 관련

enum EQUIP
{
	EQ_WEAPON,
	EQ_ARMOR,
	EQ_MAX
};

enum ITEM_TYPE
{
	IT_NONE,
	IT_WEAPON,
	IT_ARMOR,
	IT_BACK
};

enum STORE_MENU
{
	SM_NONE,
	SM_WEAPON,
	SM_ARMOR,
	SM_BACK
};
  1. 장비 부위:
    • EQ_WEAPON: 무기 슬롯.
    • EQ_ARMOR: 방어구 슬롯.
  2. 아이템 타입:
    • IT_WEAPON: 무기.
    • IT_ARMOR: 방어구.
  3. 상점 메뉴:
    • SM_WEAPON: 무기 상점.
    • SM_ARMOR: 방어구 상점.

상수 정의

#define NAME_SIZE		32
#define ITEM_DESC_LENGTH	512
#define INVENTORY_MAX		20
#define STORE_WEAPON_MAX	3
#define STORE_ARMOR_MAX		3
#define LEVEL_MAX		10
  • 이름 및 설명 크기:
    • NAME_SIZE: 이름 최대 길이(32자).
    • ITEM_DESC_LENGTH: 아이템 설명 최대 길이(512자).
  • 제한값:
    • INVENTORY_MAX: 인벤토리 최대 슬롯 수.
    • STORE_WEAPON_MAX, STORE_ARMOR_MAX: 상점 내 아이템 종류 제한.
    • LEVEL_MAX: 최대 레벨.

구조체 정의

아이템

struct _tagItem
{
	char	strName[NAME_SIZE];
	char	strTypeName[NAME_SIZE];
	ITEM_TYPE	eType;
	int		iMin;
	int		iMax;
	int		iPrice;
	int		iSell;
	char	strDesc[ITEM_DESC_LENGTH];
};
  • 아이템 정보:
    • strName: 아이템 이름.
    • strTypeName: 아이템 종류 이름 (e.g., "무기", "방어구").
    • eType: 아이템 타입.
    • iMin, iMax: 최소/최대 공격력(무기) 또는 방어력(방어구).
    • iPrice, iSell: 구매 가격과 판매 가격.
    • strDesc: 아이템 설명.

인벤토리

struct _tagInventory
{
	_tagItem	tItem[INVENTORY_MAX];
	int		iItemCount;
	int		iGold;
};
  • 인벤토리 정보:
    • tItem: 아이템 배열 (최대 INVENTORY_MAX개).
    • iItemCount: 현재 보유한 아이템 수.
    • iGold: 현재 소지금.

플레이어

struct _tagPlayer
{
	char	strName[NAME_SIZE];
	char	strJobName[NAME_SIZE];
	JOB	eJob;
	int	iAttackMin, iAttackMax;
	int	iArmorMin, iArmorMax;
	int	iHP, iHPMax;
	int	iMP, iMPMax;
	int	iExp, iLevel;
	_tagItem	tEquip[EQ_MAX];
	bool	bEquip[EQ_MAX];
	_tagInventory	tInventory;
};
  • 플레이어 정보:
    • strName: 이름.
    • strJobName: 직업 이름.
    • eJob: 직업 (JOB_KNIGHT, JOB_ARCHER, JOB_WIZARD).
    • 능력치:
      • iAttackMin, iAttackMax: 공격력.
      • iArmorMin, iArmorMax: 방어력.
      • iHP, iHPMax: 현재 체력/최대 체력.
      • iMP, iMPMax: 현재 마나/최대 마나.
      • iExp, iLevel: 경험치 및 레벨.
    • 장비:
      • tEquip: 장착 중인 무기와 방어구.
      • bEquip: 각 장비 슬롯의 장착 여부.
    • 인벤토리:
      • tInventory: 플레이어가 보유한 인벤토리.

몬스터

struct _tagMonster
{
	char	strName[NAME_SIZE];
	int	iAttackMin, iAttackMax;
	int	iArmorMin, iArmorMax;
	int	iHP, iHPMax;
	int	iMP, iMPMax;
	int	iLevel, iExp;
	int	iGoldMin, iGoldMax;
};
  • 몬스터 정보:
    • strName: 몬스터 이름.
    • 능력치:
      • iAttackMin, iAttackMax: 공격력.
      • iArmorMin, iArmorMax: 방어력.
      • iHP, iHPMax: 체력.
      • iMP, iMPMax: 마나.
      • iLevel: 몬스터 레벨.
      • iExp: 처치 시 획득 경험치.
      • iGoldMin, iGoldMax: 처치 시 획득 가능한 골드 범위.

레벨업 스테이터스

struct _tagLevelUpStatus
{
	int	iAttackMin, iAttackMax;
	int	iArmorMin, iArmorMax;
	int	iHPMin, iHPMax;
	int	iMPMin, iMPMax;
};
  • 레벨업 능력치 증가량:
    • 직업별 레벨업 시 증가하는 공격력, 방어력, 체력, 마나.

코드가 길어 나머지 세부 동작과 메인 함수의 실행 부분은 다음 단계에서 자세히 분석하겠습니다.

맵 이동, 전투, 레벨업, 상점 및 인벤토리 관리 상세 해설


맵 이동

맵 이동 기능은 메인 메뉴에서 맵 메뉴를 선택하여 특정 난이도를 가진 맵으로 이동하는 과정입니다.

case MM_MAP:
	while (true)
	{
		system("cls");
		cout << "**************************** 맵 ****************************" << endl;
		cout << "1. 쉬움" << endl;
		cout << "2. 보통" << endl;
		cout << "3. 어려움" << endl;
		cout << "4. 뒤로가기" << endl;
		cout << "맵을 선택하세요 : ";
		cin >> iMenu;

		if (cin.fail())
		{
			cin.clear();
			cin.ignore(1024, '\n');
			continue;
		}

		if (iMenu == MT_BACK)
			break;

		// 선택한 맵 난이도에 따라 몬스터 설정
		_tagMonster tMonster = tMonsterArr[iMenu - 1];
  1. 맵 메뉴 출력:

    • 1: 쉬움, 2: 보통, 3: 어려움, 4: 뒤로가기.
    • 입력값에 따라 난이도를 선택.
  2. 입력 검증:

    • cin.fail()로 비정상 입력 방지.
    • 4(뒤로가기)를 입력하면 루프 종료.
  3. 몬스터 설정:

    • 입력값(iMenu)에서 1을 빼서 몬스터 배열의 인덱스를 가져옴.
    • 해당 맵 난이도에 해당하는 몬스터를 복사.

전투

맵 이동 후 몬스터와 전투를 진행하는 부분입니다.

플레이어와 몬스터 정보 출력

// 플레이어 정보 출력
cout << "================== Player ==================" << endl;
cout << "이름 : " << tPlayer.strName << "\t직업 : " << tPlayer.strJobName << endl;
cout << "레벨 : " << tPlayer.iLevel << "\t경험치 : " << tPlayer.iExp << " / " << iLevelUpExp[tPlayer.iLevel - 1] << endl;

// 무기 장착 여부에 따라 공격력 출력
if (tPlayer.bEquip[EQ_WEAPON])
	cout << "공격력 : " << tPlayer.iAttackMin << " + " << tPlayer.tEquip[EQ_WEAPON].iMin 
		<< " ~ " << tPlayer.iAttackMax << " + " << tPlayer.tEquip[EQ_WEAPON].iMax << endl;
else
	cout << "공격력 : " << tPlayer.iAttackMin << " ~ " << tPlayer.iAttackMax << endl;

// 방어구 장착 여부에 따라 방어력 출력
if (tPlayer.bEquip[EQ_ARMOR])
	cout << "방어력 : " << tPlayer.iArmorMin << " + " << tPlayer.tEquip[EQ_ARMOR].iMin 
		<< " ~ " << tPlayer.iArmorMax << " + " << tPlayer.tEquip[EQ_ARMOR].iMax << endl;
else
	cout << "방어력 : " << tPlayer.iArmorMin << " ~ " << tPlayer.iArmorMax << endl;

cout << "체력 : " << tPlayer.iHP << " / " << tPlayer.iHPMax 
	<< "\t마나 : " << tPlayer.iMP << " / " << tPlayer.iMPMax << endl;
cout << "보유골드 : " << tPlayer.tInventory.iGold << " Gold" << endl;

// 몬스터 정보 출력
cout << "====================== Monster ======================" << endl;
cout << "이름 : " << tMonster.strName << "\t레벨 : " << tMonster.iLevel << endl;
cout << "공격력 : " << tMonster.iAttackMin << " - " << tMonster.iAttackMax 
	<< "\t방어력 : " << tMonster.iArmorMin << " - " << tMonster.iArmorMax << endl;
cout << "체력 : " << tMonster.iHP << " / " << tMonster.iHPMax << endl;
  • 플레이어 정보 출력:
    • 레벨, 경험치, 공격력, 방어력, 체력, 마나, 장비 상태, 보유 골드 출력.
    • 무기/방어구 장착 여부에 따라 공격력과 방어력 계산.
  • 몬스터 정보 출력:
    • 이름, 레벨, 공격력 범위, 방어력 범위, 체력 출력.

전투 진행

cout << "1. 공격" << endl;
cout << "2. 도망가기" << endl;
cin >> iMenu;

if (cin.fail())
{
	cin.clear();
	cin.ignore(1024, '\n');
	continue;
}

else if (iMenu == BATTLE_BACK)
	break;

switch (iMenu)
{
case BATTLE_ATTACK:
	int iAttack = rand() % (tPlayer.iAttackMax - tPlayer.iAttackMin + 1) + tPlayer.iAttackMin;
	int iArmor = rand() % (tMonster.iArmorMax - tMonster.iArmorMin + 1) + tMonster.iArmorMin;

	int iDamage = iAttack - iArmor;
	iDamage = iDamage < 1 ? 1 : iDamage;
	tMonster.iHP -= iDamage;

	cout << tPlayer.strName << " 가 " << tMonster.strName << "에게 " << iDamage << " 피해를 입혔습니다." << endl;
  • 공격:
    • 플레이어의 공격력 랜덤값(iAttack)과 몬스터의 방어력 랜덤값(iArmor) 계산.
    • iDamage: 공격력 - 방어력. 최소 데미지는 1로 보장.
    • 몬스터 체력 감소.

몬스터 사망 및 보상

if (tMonster.iHP <= 0)
{
	cout << tMonster.strName << " 몬스터가 사망하였습니다." << endl;

	tPlayer.iExp += tMonster.iExp;
	int iGold = (rand() % (tMonster.iGoldMax - tMonster.iGoldMin + 1)) + tMonster.iGoldMin;
	tPlayer.tInventory.iGold += iGold;

	cout << tMonster.iExp << " 경험치를 획득하였습니다." << endl;
	cout << iGold << " Gold를 획득하였습니다." << endl;
}
  • 보상:
    • 몬스터 처치 시 경험치와 골드 획득.
    • 경험치는 몬스터의 iExp 값만큼 증가.
    • 골드는 iGoldMin ~ iGoldMax 범위 내 랜덤값.

레벨업

if (tPlayer.iExp >= iLevelUpExp[tPlayer.iLevel - 1])
{
	tPlayer.iExp -= iLevelUpExp[tPlayer.iLevel - 1];
	++tPlayer.iLevel;

	cout << "레벨업 하였습니다." << endl;

	int iJobIndex = tPlayer.eJob - 1;
	int iHPUp = rand() % (tLvUpTable[iJobIndex].iHPMax - tLvUpTable[iJobIndex].iHPMin + 1) + tLvUpTable[iJobIndex].iHPMin;
	int iMPUp = rand() % (tLvUpTable[iJobIndex].iMPMax - tLvUpTable[iJobIndex].iMPMin + 1) + tLvUpTable[iJobIndex].iMPMin;

	tPlayer.iAttackMin += tLvUpTable[iJobIndex].iAttackMin;
	tPlayer.iAttackMax += tLvUpTable[iJobIndex].iAttackMax;
	tPlayer.iArmorMin += tLvUpTable[iJobIndex].iArmorMin;
	tPlayer.iArmorMax += tLvUpTable[iJobIndex].iArmorMax;
	tPlayer.iHPMax += iHPUp;
	tPlayer.iMPMax += iMPUp;

	tPlayer.iHP = tPlayer.iHPMax;
	tPlayer.iMP = tPlayer.iMPMax;
}
  • 경험치 확인 및 레벨업:
    • 누적 경험치가 필요 경험치를 초과하면 레벨 증가.
    • tLvUpTable에서 직업별 능력치 증가량 적용.

상점

for (int i = 0; i < STORE_WEAPON_MAX; ++i)
{
	cout << i + 1 << ". 이름 : " << tStoreWeapon[i].strName 
		<< "\t공격력 : " << tStoreWeapon[i].iMin << " ~ " << tStoreWeapon[i].iMax << endl;
	cout << "판매가격 : " << tStoreWeapon[i].iPrice << endl;
}
  • 아이템 목록 출력:
    • 무기/방어구 각각 최대 3개 출력.
if (tPlayer.tInventory.iGold < tStoreWeapon[iWeaponIndex].iPrice)
{
	cout << "골드가 부족합니다." << endl;
	continue;
}
  • 구매 가능 여부 확인:
    • 보유 골드가 부족하면 구매 불가.
tPlayer.tInventory.tItem[tPlayer.tInventory.iItemCount] = tStoreWeapon[iWeaponIndex];
++t

Player.tInventory.iItemCount;
tPlayer.tInventory.iGold -= tStoreWeapon[iWeaponIndex].iPrice;
  • 구매 완료:
    • 아이템을 인벤토리에 추가.
    • 골드 차감.

인벤토리 관리

cout << "장착할 아이템을 선택하세요 : ";
cin >> iMenu;

int idx = iMenu - 1;
EQUIP eq = (tPlayer.tInventory.tItem[idx].eType == IT_WEAPON) ? EQ_WEAPON : EQ_ARMOR;
  • 장착 아이템 선택:
    • 선택한 아이템의 타입에 따라 무기(EQ_WEAPON) 또는 방어구(EQ_ARMOR)로 결정.
if (tPlayer.bEquip[eq])
{
	_tagItem tSwap = tPlayer.tEquip[eq];
	tPlayer.tEquip[eq] = tPlayer.tInventory.tItem[idx];
	tPlayer.tInventory.tItem[idx] = tSwap;
}
else
{
	tPlayer.tEquip[eq] = tPlayer.tInventory.tItem[idx];
	for (int i = idx; i < tPlayer.tInventory.iItemCount - 1; ++i)
		tPlayer.tInventory.tItem[i] = tPlayer.tInventory.tItem[i + 1];
	--tPlayer.tInventory.iItemCount;
	tPlayer.bEquip[eq] = true;
}
  • 아이템 장착:
    • 기존 장착 아이템이 있으면 인벤토리와 교체.
    • 없으면 새로 장착하고 인벤토리에서 제거.

이로써 맵 이동, 전투, 레벨업, 상점 및 인벤토리 관리의 모든 세부 구현을 설명했습니다. 필요시 특정 부분에 대한 추가 설명도 가능합니다!

profile
李家네_공부방

0개의 댓글