이 코드는 구조체와 열거형을 활용한 텍스트 기반 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
};
EQ_WEAPON
: 무기 슬롯.EQ_ARMOR
: 방어구 슬롯.IT_WEAPON
: 무기.IT_ARMOR
: 방어구.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];
맵 메뉴 출력:
입력 검증:
cin.fail()
로 비정상 입력 방지.몬스터 설정:
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;
}
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;
}
이로써 맵 이동, 전투, 레벨업, 상점 및 인벤토리 관리의 모든 세부 구현을 설명했습니다. 필요시 특정 부분에 대한 추가 설명도 가능합니다!