코린이 부트캠프 일상

코린이 12일차 TextRpgGame 추가구현

게발인개발자 2023. 11. 14. 20:21
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시까지라 부연 설명은 나중에 수정하겠습니다!!

아직 구현 못한게 있어서