using System.Runtime.CompilerServices;
namespace TextRpgGame
{
public class Character
{
public string Name { get; }
public string Job { get; }
public int Level { get; set; }
public int Atk { get; set; }
public int Def { get; set; }
public int MaxHp { get; set; }
public int Hp { get; set; }
public int Exp { get; set; }
public int Gold { get; set; }
public Character(string name, string job, int level, int atk, int def, int maxHp, int hp, int exp, int gold)
{
Name = name;
Job = job;
Level = level;
Atk = atk;
Def = def;
MaxHp = maxHp;
Hp = hp;
Exp = exp;
Gold = gold;
}
}
public class Monster
{
public string Name { get; }
public int Atk { get; }
public int Def { get; }
public int Hp { get; set; }
public int Exp { get; }
public int Gold { get; }
public Monster(string name, int atk, int def, int hp, int exp, int gold)
{
Name = name;
Atk = atk;
Def = def;
Hp = hp;
Exp = exp;
Gold = gold;
}
}
public class Item
{
public string Name { get; }
public string Description { get; }
// 개선포인트 : Enum 활용
public int Type { get; }
public int Atk { get; }
public int Def { get; }
public int Hp { get; }
public bool IsEquiped { get; set; }
public static int ItemCnt = 0;
public Item(string name, string description, int type, int atk, int def, int hp, bool isEquiped = false)
{
Name = name;
Description = description;
Type = type;
Atk = atk;
Def = def;
Hp = hp;
IsEquiped = isEquiped;
}
public void PrintItemStatDescription(bool withNumber = false, int idx = 0)
{
Console.Write("- ");
// 장착관리 전용
if (withNumber)
{
Console.ForegroundColor = ConsoleColor.DarkMagenta;
Console.Write("{0} ", idx);
Console.ResetColor();
}
if (IsEquiped)
{
Console.Write("[");
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("E");
Console.ResetColor();
Console.Write("]");
Console.Write(PadRightForMixedText(Name, 9));
}
else Console.Write(PadRightForMixedText(Name, 12));
Console.Write(" | ");
if (Atk != 0) Console.Write($"Atk {(Atk >= 0 ? "+" : "")}{Atk} ");
if (Def != 0) Console.Write($"Def {(Def >= 0 ? "+" : "")}{Def} ");
if (Hp != 0) Console.Write($"Hp {(Hp >= 0 ? "+" : "")}{Hp}");
Console.Write(" | ");
Console.WriteLine(Description);
}
public static int GetPrintableLength(string str)
{
int length = 0;
foreach (char c in str)
{
if (char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.OtherLetter)
{
length += 2; // 한글과 같은 넓은 문자에 대해 길이를 2로 취급
}
else
{
length += 1; // 나머지 문자에 대해 길이를 1로 취급
}
}
return length;
}
public static string PadRightForMixedText(string str, int totalLength)
{
int currentLength = GetPrintableLength(str);
int padding = totalLength - currentLength;
return str.PadRight(str.Length + padding);
}
}
internal class Program
{
static Character _player;
static Item[] _items;
static Monster _monster1;
static Monster _monster2;
static void Main(string[] args)
{
/// 구성
/// 0. 초기화함
/// 1. 스타팅 로고를 보여줌 (게임 처음 킬때만 보여줌)
/// 2. 선택 화면을 보여줌 (기본 구현사항 - 상태 / 인벤토리)
/// 3. 상태화면을 구현함 (필요 구현 요소 : 캐릭터, 아이템)
/// 4. 인벤토리 화면을 구현함
GameDataSetting();
PrintStartLogo();
StartMenu();
}
static void GameDataSetting()
{
_player = new Character("chad", "전사", 1, 10, 5, 100, 100, 0, 1500);
_monster1 = new Monster("끈적한 슬라임", 6, 5, 80, 100, 1000);
_monster2 = new Monster("1년 안 씻은 고블린 병사", 5, 5, 50, 300, 200);
_items = new Item[10];
AddItem(new Item("무쇠갑옷", "무쇠로 만들어져 튼튼한 갑옷입니다.", 0, 0, 5, 0));
AddItem(new Item("낡은 검", "쉽게 볼 수 있는 낡은 검입니다.", 1, 2, 0, 0));
AddItem(new Item("골든 헬름", "희귀한 광석으로 만들어진 투구입니다.", 1, 0, 9, 0));
}
static void StartMenu()
{
/// 구성
/// 0. 화면 정리
/// 1. 선택 멘트를 줌
/// 2. 선택 결과값을 검증함
/// 3. 선택 결과에 따라 메뉴로 보내줌
Console.Clear();
Console.WriteLine("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■");
Console.WriteLine("스파르타 마을에 오신 여러분 환영합니다.");
Console.WriteLine("이곳에서 던전으로 들어가기 전 활동을 할 수 있습니다.");
Console.WriteLine("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■");
Console.WriteLine("");
Console.WriteLine("1. 상태 보기");
Console.WriteLine("2. 인벤토리");
Console.WriteLine("3. 던전입장");
Console.WriteLine("4. 상점입장");
Console.WriteLine("");
// 1안 : 착한 유저들만 있을 경우
// int keyInput = int.Parse(Console.ReadLine());
// 2안 : 나쁜 유저들도 있는 경우
// int keyInput;
// bool result;
// do
// {
// Console.WriteLine("원하시는 행동을 입력해주세요.");
// result = int.TryParse(Console.ReadLine(), out keyInput);
// } while (result == false || CheckIfValid(keyInput, min : 1, max : 2) == false);
switch (CheckValidInput(1, 4))
{
case 1:
StatusMenu();
break;
case 2:
InventoryMenu();
break;
case 3:
DungeonMenu();
break;
case 4:
StoreMenu();
break;
}
}
private static void StoreMenu()
{
Console.Clear();
Console.WriteLine("■호갱환영■");
Console.WriteLine("친절한 상점에 오신걸 환영합니다.");
Console.WriteLine("");
Console.WriteLine("0. 나가기");
Console.WriteLine("1. 회복하기(최대체력으로 만들기) 100골드");
Console.WriteLine("2. 레벨업 시키기(Lv X 100에 해당하는 Exp면 레벨업가능) 10000골드");
Console.WriteLine("3. 랜덤상자뽑기???? 1000골드 확률극악");
Console.WriteLine("");
switch (CheckValidInput(0, 3))
{
case 0:
StartMenu();
break;
case 1:
HealPlayerHP();
break;
case 2:
LevelUPPlayer();
break;
case 3:
BuyRandomBox();
break;
}
}
private static void HealPlayerHP()
{
if (_player.Hp == _player.MaxHp)
Console.WriteLine("이미 최대체력입니다.");
else
{
_player.Hp = _player.MaxHp;
_player.Gold -= 100;
Console.WriteLine("100골드를 지불했습니다.");
Console.WriteLine("체력을 회복했습니다.");
Console.WriteLine("");
}
switch (CheckValidInput(0, 3))
{
case 0:
StartMenu();
break;
case 1:
HealPlayerHP();
break;
case 2:
LevelUPPlayer();
break;
case 3:
BuyRandomBox();
break;
}
}
static void LevelUp()
{
_player.Exp -= _player.Level * 100;
_player.Gold -= 10000;
_player.Level++;
_player.MaxHp += 20;
_player.Def += 2;
_player.Atk += 2;
}
private static void LevelUPPlayer()
{
if (_player.Exp >= _player.Level * 100 && _player.Gold >= 10000)
{
LevelUp();
Console.WriteLine("1000골드를 지불했습니다.");
Console.WriteLine(_player.Level + "레벨이 되었습니다.");
}
else if( _player.Exp < _player.Level * 100)
{
Console.WriteLine("Exp가 부족합니다.");
}
else
{
Console.WriteLine("골드가 부족합니다.");
}
switch (CheckValidInput(0, 3))
{
case 0:
StartMenu();
break;
case 1:
HealPlayerHP();
break;
case 2:
LevelUPPlayer();
break;
case 3:
BuyRandomBox();
break;
}
}
private static void BuyRandomBox()
{
if (_player.Gold >= 1000)
{
_player.Gold -= 1000;
Console.WriteLine("");
Console.WriteLine("꽝~~~ㅋㅋㄹㅃㅃ 이걸로 건물 세워야지^^");
}
else
{
Console.WriteLine("");
Console.WriteLine("골드부터 가져와야지 상자를 주던 말던 하지;;;");
}
switch (CheckValidInput(0, 3))
{
case 0:
StartMenu();
break;
case 1:
HealPlayerHP();
break;
case 2:
LevelUPPlayer();
break;
case 3:
BuyRandomBox();
break;
}
}
static void DungeonMenu()
{
Console.Clear();
Console.WriteLine("■무시무시한 던전에 입장했습니다.■");
Console.WriteLine(_monster1.Name + "이 출현하였습니다.");
Console.WriteLine("");
Console.WriteLine("0. 도망가기");
Console.WriteLine("1. 몬스터와 전투");
Console.WriteLine("2. 몬스터 정보 보기");
Console.WriteLine("3. 다음 스테이지로 이동");
switch (CheckValidInput(0, 3))
{
case 0:
StartMenu();
break;
case 1:
StartFight();
break;
case 2:
ShowMonsterStatus();
break;
case 3:
//구현중
Console.WriteLine("아직 구현중 입니다.");
NextStage();
break;
}
}
private static void ShowMonsterStatus()
{
Console.WriteLine(_monster1.Name);
Console.WriteLine("공격력 :" + _monster1.Atk);
Console.WriteLine("방어력 :" + _monster1.Def);
Console.WriteLine("체 력 :" + _monster1.Hp);
switch (CheckValidInput(0, 3))
{
case 0:
StartMenu();
break;
case 1:
StartFight();
break;
case 2:
ShowMonsterStatus();
break;
case 3:
NextStage();
break;
}
}
static void StartFight()
{
_monster1.Hp = 80;
do
{
Console.WriteLine("");
if (_player.Def > _monster1.Atk)
{
Console.WriteLine("몬스터의 공격으로 Chad에게 *Miss*의 데미지를 입혔습니다.");
_player.Hp = _player.Hp;
_monster1.Hp -= (_player.Atk + getSumBonusAtk()) - _monster1.Def;
Console.WriteLine("Chad의 공격으로 몬스터에게 *" + ((_player.Atk + getSumBonusAtk()) - _monster1.Def) + "*의 데미지를 입혔습니다.");
}
else if (_monster1.Def > _player.Atk + getSumBonusAtk())
{
Console.WriteLine("Chad의 공격으로 몬스터에게 *Miss*의 데미지를 입혔습니다.");
_monster1.Hp = _monster1.Hp;
_player.Hp -= _monster1.Atk - _player.Def - getSumBonusDef();
Console.WriteLine("몬스터의 공격으로 Chad에게 *" + (_monster1.Atk - _player.Def) + "*의 데미지를 입혔습니다.");
}
else
{
_player.Hp -= _monster1.Atk - (_player.Def + getSumBonusDef());
Console.WriteLine("몬스터의 공격으로 Chad에게 *" + (_monster1.Atk - _player.Def) + "*의 데미지를 입혔습니다.");
_monster1.Hp -= (_player.Atk + getSumBonusAtk()) - _monster1.Def;
Console.WriteLine("Chad의 공격으로 몬스터에게 *" + ((_player.Atk + getSumBonusAtk()) - _monster1.Def) + "*의 데미지를 입혔습니다.");
}
Console.ReadKey();
if (_monster1.Hp <= 0 && _player.Hp > 0)
{
Console.WriteLine("");
Console.WriteLine(_monster1.Name + "를 처치했습니다.");
Console.Write(_monster1.Gold + "골드, ");
Console.Write(_monster1.Exp + "경험치");
_player.Gold += _monster1.Gold;
_player.Exp += _monster1.Exp;
Console.WriteLine("를 습득했습니다.");
Console.WriteLine("");
Console.WriteLine("0. 나가기");
Console.WriteLine("1. 전투 다시하기");
Console.WriteLine("2. 다음 스테이지 이동");
switch (CheckValidInput(0, 2))
{
case 0:
StartMenu();
break;
case 1:
StartFight();
break;
case 2:
NextStage();
break;
}
}
else if (_player.Hp <= 0 && _monster1.Hp > 0)
{
Console.WriteLine("");
Console.WriteLine(_monster1.Name + "에게 당했습니다.");
Console.WriteLine("");
Console.WriteLine("0. 나가기");
switch (CheckValidInput(0, 2))
{
case 0:
StartMenu();
break;
}
}
} while (_monster1.Hp > 0 && _player.Hp > 0);
}
static void NextStage()
{
switch (CheckValidInput(0, 3))
{
case 0:
StartMenu();
break;
case 1:
StartFight();
break;
case 2:
ShowMonsterStatus();
break;
case 3:
//구현중
Console.WriteLine("아직 구현중 입니다.");
NextStage();
break;
}
}
static int CheckValidInput(int min, int max)
{
/// 설명
/// 아래 두 가지 상황은 비정상 -> 재입력 수행
/// (1) 숫자가 아닌 입력을 받은 경우
/// (2) 숫자가 최소값 ~ 최대값의 범위를 넘는 경우
int keyInput;
bool result;
do
{
Console.WriteLine("원하시는 행동을 입력해주세요.");
Console.Write(">>>");
result = int.TryParse(Console.ReadLine(), out keyInput);
} while (result == false || CheckIfValid(keyInput, min, max) == false);
return keyInput;
}
static bool CheckIfValid(int checkable, int min, int max)
{
if (min <= checkable && checkable <= max) return true;
return false;
}
static void AddItem(Item item)
{
if (Item.ItemCnt == 10) return;
_items[Item.ItemCnt] = item;
Item.ItemCnt++;
}
static void StatusMenu()
{
Console.Clear();
ShowHighlightedText("■ 상태 보기 ■");
Console.WriteLine("캐릭터의 정보가 표기됩니다.");
PrintTextWithHighlights("Lv. ", _player.Level.ToString("00"));
Console.WriteLine("");
Console.WriteLine("{0} ( {1} )", _player.Name, _player.Job);
int bonusAtk = getSumBonusAtk();
PrintTextWithHighlights("공격력 : ", (_player.Atk + bonusAtk).ToString(), bonusAtk > 0 ? string.Format(" (+{0})", bonusAtk) : "");
int bonusDef = getSumBonusDef();
PrintTextWithHighlights("방어력 : ", (_player.Def + bonusDef).ToString(), bonusDef > 0 ? string.Format(" (+{0})", bonusDef) : "");
int bonusHp = getSumBonusHp();
PrintTextWithHighlights("체 력 : ", (_player.Hp + bonusHp).ToString(), bonusHp > 0 ? string.Format(" (+{0})", bonusHp) : "");
PrintTextWithHighlights("최대체력 : ", (_player.MaxHp + bonusHp).ToString(), bonusHp > 0 ? string.Format(" (+{0})", bonusHp) : "");
PrintTextWithHighlights("경험치 : ", (_player.Exp).ToString());
PrintTextWithHighlights("Gold : ", _player.Gold.ToString());
Console.WriteLine("");
Console.WriteLine("0. 뒤로가기");
Console.WriteLine("");
switch (CheckValidInput(0, 0))
{
case 0:
StartMenu();
break;
}
}
private static int getSumBonusAtk()
{
int sum = 0;
for (int i = 0; i < Item.ItemCnt; i++)
{
if (_items[i].IsEquiped) sum += _items[i].Atk;
}
return sum;
}
private static int getSumBonusDef()
{
int sum = 0;
for (int i = 0; i < Item.ItemCnt; i++)
{
if (_items[i].IsEquiped) sum += _items[i].Def;
}
return sum;
}
private static int getSumBonusHp()
{
int sum = 0;
for (int i = 0; i < Item.ItemCnt; i++)
{
if (_items[i].IsEquiped) sum += _items[i].Hp;
}
return sum;
}
private static void PrintTextWithHighlights(string s1, string s2, string s3 = "")
{
Console.Write(s1);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(s2);
Console.ResetColor();
Console.WriteLine(s3);
}
static void InventoryMenu()
{
Console.Clear();
ShowHighlightedText("■ 인벤토리 ■");
Console.WriteLine("보유 중인 아이템을 관리할 수 있습니다.");
Console.WriteLine("");
Console.WriteLine("[아이템 목록]");
for (int i = 0; i < Item.ItemCnt; i++)
{
_items[i].PrintItemStatDescription();
}
Console.WriteLine("");
Console.WriteLine("0. 나가기");
Console.WriteLine("1. 장착관리");
Console.WriteLine("");
switch (CheckValidInput(0, 1))
{
case 0:
StartMenu();
break;
case 1:
EquipMenu();
break;
}
}
static void EquipMenu()
{
Console.Clear();
ShowHighlightedText("■ 인벤토리 - 장착 관리 ■");
Console.WriteLine("보유 중인 아이템을 관리할 수 있습니다.");
Console.WriteLine("");
Console.WriteLine("[아이템 목록]");
for (int i = 0; i < Item.ItemCnt; i++)
{
_items[i].PrintItemStatDescription(true, i + 1); // 1, 2, 3에 매핑하기 위해 +1
}
Console.WriteLine("");
Console.WriteLine("0. 나가기");
int keyInput = CheckValidInput(0, Item.ItemCnt);
switch (keyInput)
{
case 0:
InventoryMenu();
break;
default:
ToggleEquipStatus(keyInput - 1); // 유저가 입력하는건 1, 2, 3 : 실제 배열에는 0, 1, 2...
EquipMenu();
break;
}
}
static void ToggleEquipStatus(int idx)
{
_items[idx].IsEquiped = !_items[idx].IsEquiped;
}
static void ShowHighlightedText(string title)
{
Console.ForegroundColor = ConsoleColor.Magenta;
Console.WriteLine(title);
Console.ResetColor();
}
static void PrintStartLogo()
{
// ASCII ART GENERATED BY https://textkool.com/en/ascii-art-generator?hl=default&vl=default&font=Red%20Phoenix
Console.WriteLine("=============================================================================");
Console.WriteLine(" ___________________ _____ __________ ___________ _____ ");
Console.WriteLine(" / _____/\\______ \\ / _ \\ \\______ \\\\__ ___// _ \\ ");
Console.WriteLine(" \\_____ \\ | ___// /_\\ \\ | _/ | | / /_\\ \\ ");
Console.WriteLine(" / \\ | | / | \\| | \\ | | / | \\ ");
Console.WriteLine(" /_______ / |____| \\____|__ /|____|_ / |____| \\____|__ / ");
Console.WriteLine(" \\/ \\/ \\/ \\/ ");
Console.WriteLine(" ________ ____ ___ _______ ________ ___________________ _______");
Console.WriteLine(" \\______ \\ | | \\\\ \\ / _____/ \\_ _____/\\_____ \\ \\ \\");
Console.WriteLine(" | | \\ | | // | \\ / \\ ___ | __)_ / | \\ / | \\\r\n");
Console.WriteLine(" | | \\| | // | \\\\ \\_\\ \\ | \\/ | \\/ | \\\r\n");
Console.WriteLine(" /_______ /|______/ \\____|__ / \\______ //_______ /\\_______ /\\____|__ /\r\n");
Console.WriteLine(" \\/ \\/ \\/ \\/ \\/ \\/");
Console.WriteLine("=============================================================================");
Console.WriteLine(" PRESS ANYKEY TO START ");
Console.WriteLine("=============================================================================");
Console.ReadKey();
}
}
}
- 몬스터와 전투
- 몬스터 사망 후 경험치 및 골드 획득
- 상점 구현 --> 상점에서 골드 지불 체력 회복, 레벨업, 랜덤 상자(내용은 아직 구현못함)
- 레벨업 구현 ---> 레벨업 시 캐릭터 스탯 능력 부여
- 몬스터 스테이지별로 다른 몬스터 출현(구현중....)
과제 제출이 12시까지라 부연 설명은 나중에 수정하겠습니다!!
아직 구현 못한게 있어서
'코린이 부트캠프 일상' 카테고리의 다른 글
코린이 14일차 C# delegate (0) | 2023.11.16 |
---|---|
코린이 13일차 인터페이스 /enum (0) | 2023.11.15 |
코린이 11일차 TextRpgGame 기초 (1) | 2023.11.13 |
코린이 10일차 /텍스트 게임/ (0) | 2023.11.10 |
코린이 8일차 /C# 콘솔로 틱택토(Tic Tac Toe)만들기 (0) | 2023.11.08 |