예제 #1
0
        public static string GetHeroSkillsIcons(eHero hero)
        {
            switch (hero)
            {
            case eHero.None:
                return(GenericSkills);

            case eHero.Amazon:
                return(AmazonSkills);

            case eHero.Assassin:
                return(AssassinSkills);

            case eHero.Barbarian:
                return(BarbarianSkills);

            case eHero.Druid:
                return(DruidSkills);

            case eHero.Necromancer:
                return(NecromancerSkills);

            case eHero.Paladin:
                return(PaladinSkills);

            case eHero.Sorceress:
                return(SorcererSkills);

            default:
                throw new ArgumentException($"Unknown hero type: {hero}");
            }
        }
예제 #2
0
파일: Hero.cs 프로젝트: beerbu89/Project
    public void SetData()
    {
        Hero currentHero = this;

        var list = BattleMng.Ins.heroDatas.GetEnumerator();

        int idx = 0;

        while (list.MoveNext())
        {
            var temp = list.Current;

            eHero eHeroTemp = (eHero)Enum.Parse(typeof(eHero), temp.strName);

            if (eHero == eHeroTemp)
            {
                data = temp;
                break;
            }
            ++idx;
        }

        ExtensionMethod.HeroSetData(currentHero, data);

        currentHp = nHp;
    }
예제 #3
0
    public void SetPool(Transform hero, Transform monster)
    {
        heroRoot    = hero;
        monsterRoot = monster;

        for (int i = 1; i < (int)eHero.Max; ++i)
        {
            eHero eHero = (eHero)i;
            SetHero(eHero);
        }

        for (int i = 0; i < (int)eMonster.Max; ++i)
        {
            eMonster eMonster    = (eMonster)i;
            string   monsterPath = string.Format(Path.MONSTERPREFAB, eMonster.ToString());

            obj = Instantiate(Resources.Load(monsterPath)) as GameObject;

            obj.transform.parent = monsterRoot;
            obj.SetActive(false);

            monsterPoolList.Add(obj.transform);
            eMonsterList.Add(eMonster);
        }
    }
예제 #4
0
    //10회 소환
    public void SetHeroImg(Image[] Bg, Image[] _hero)
    {
        //if (flagList[heroSlotList[idx+Bg.Length-1]] == false)
        //{
        //    Debug.LogError("슬롯이 닫혀있음");
        //    return;
        //}

        for (int i = 0; i < Bg.Length; ++i)
        {
            heroSlotList[idx].color = Bg[i].color;
            heroList[idx].sprite    = _hero[i].sprite;

            HeroProperty(heroSlotList[idx].color);

            eHeroName = (eHero)Enum.Parse(typeof(eHero), heroList[idx].sprite.name);

            if (eHeroName != eHero.None)
            {
                characters.SetData(eHeroProperty, (int)eHeroName);
            }

            Player.Ins.invenSlotList.Add(heroSlotList[idx]);
            Player.Ins.heroImgList.Add(heroList[idx]);

            ++idx;
            ++heroCount;
        }
    }
예제 #5
0
        public static string GetHeroSkillPanel(eHero hero)
        {
            switch (hero)
            {
            case eHero.Amazon:
                return(SkillsPanelAmazon);

            case eHero.Assassin:
                return(SkillsPanelAssassin);

            case eHero.Barbarian:
                return(SkillsPanelBarbarian);

            case eHero.Druid:
                return(SkillsPanelDruid);

            case eHero.Necromancer:
                return(SkillsPanelNecromancer);

            case eHero.Paladin:
                return(SkillsPanelPaladin);

            case eHero.Sorceress:
                return(SkillsPanelSorcerer);

            default:
                throw new ArgumentException($"Unknown hero type: {hero}");
            }
        }
예제 #6
0
 public SkillInfoAttribute(eHero hero, int spriteIndex = 0, int level /*levelGroup*/ = 0, params eSkill[] skillsRequired)
 {
     Hero           = hero;
     SpriteIndex    = spriteIndex;
     Level          = level;
     SkillsRequired = skillsRequired ?? Array.Empty <eSkill>();
 }
예제 #7
0
    //1회 소환시 인벤추가
    public void SetHeroImg(Image Bg, Image _hero)
    {
        //Debug.Log(idx);
        //if (flagList[heroSlotList[idx]] == false)
        //{
        //    Debug.LogError("슬롯이 닫혀있음");
        //    return;
        //}

        heroSlotList[idx].color = Bg.color;
        heroList[idx].sprite    = _hero.sprite;

        HeroProperty(heroSlotList[idx].color);

        //Debug.LogError(eHeroProperty.ToString());

        eHeroName = (eHero)Enum.Parse(typeof(eHero), heroList[idx].sprite.name);

        if (eHeroName != eHero.None)
        {
            characters.SetData(eHeroProperty, (int)eHeroName);
        }

        Player.Ins.invenSlotList.Add(heroSlotList[idx]);
        Player.Ins.heroImgList.Add(heroList[idx]);

        ++idx;
        ++heroCount;
    }
예제 #8
0
 private void OnJoinGameHandler(int clientHash, eHero heroType, string playerName)
 {
     gameServer.SpawnNewPlayer(clientHash, playerName, heroType);
     Send(new MFSetSeed(gameServer.Seed), true);
     Send(new MFPlayerInfo(gameServer.Players.Select(x => x.ToPlayerInfo())), true);
     Send(new MFLocatePlayers(gameServer.Players.Select(x => x.ToPlayerLocationDetails())), true);
     Send(new MFFocusOnPlayer(gameServer.Players.First(x => x.ClientHash == clientHash).Id));
 }
예제 #9
0
 public MPQCOF GetPlayerAnimation(eHero hero, eMobMode mobMode, PlayerEquipment equipment)
 => cache.AddOrGetExisting($"COF::{hero}{mobMode.ToToken()}{equipment.HashKey}", () =>
 {
     var path = $"{ResourcePaths.PlayerAnimationBase}\\{hero.ToToken()}\\COF\\{hero.ToToken()}{mobMode.ToToken()}{equipment.WeaponClass.ToToken()}.cof";
     return(MPQCOF.Load(mpqProvider.GetStream(path), Animations, hero, mobMode, equipment));
 }, new System.Runtime.Caching.CacheItemPolicy {
     Priority = System.Runtime.Caching.CacheItemPriority.NotRemovable
 });
예제 #10
0
        public void Initialize(string characterName, eHero hero)
        {
            var random = new Random();

            Seed = random.Next();

            sceneManager.ChangeScene("Game");
            ChangeMap(eLevelId.Act1_Town1);
        }
예제 #11
0
 public static IEnumerable <eSkill> GetHeroSkills(eHero hero)
 {
     foreach (var skill in (eSkill[])Enum.GetValues(typeof(eSkill)))
     {
         if (skill.GetSkillInfo()?.Hero == hero)
         {
             yield return(skill);
         }
     }
 }
예제 #12
0
 public void JoinGame(string playerName, eHero heroType)
 {
     Task.Run(() =>
     {
         Send(new MFJoinGame(playerName, heroType));
         ProcessMessageFrame <MFSetSeed>();
         ProcessMessageFrame <MFPlayerInfo>();
         ProcessMessageFrame <MFLocatePlayers>();
         ProcessMessageFrame <MFFocusOnPlayer>();
     });
 }
예제 #13
0
        public int SpawnNewPlayer(int clientHash, string playerName, eHero heroType)
        {
            ILevelExperienceConfig expConfig  = null;
            IHeroTypeConfig        heroConfig = null;

            if (engineDataManager.ExperienceConfigs.ContainsKey(heroType))
            {
                expConfig = engineDataManager.ExperienceConfigs[heroType];
            }
            else
            {
                log.Error("Error: Experience Config not loaded for '" + heroType.ToString() + "'.");
                expConfig = new LevelExperienceConfig(new List <long>()
                {
                    100
                });
                // TODO: should we have a more robust default experience config?
                // or should we just fail in some way here?
            }
            if (engineDataManager.HeroTypeConfigs.ContainsKey(heroType))
            {
                heroConfig = engineDataManager.HeroTypeConfigs[heroType];
            }
            else
            {
                log.Error("Error: Hero Config not loaded for '" + heroType.ToString() + "'.");
                // Do we even need a default?
                //heroConfig = new HeroTypeConfig(10, 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 9,
                //    1, 10, 10, 10, 10, 10, 10, 0, "hth");
                // TODO: should we have a more robust default hero config?
                // or should we just fail in some way here?
                // ... we should probably just fail here
            }

            var newPlayer = new PlayerState(clientHash, playerName, mobManager.GetNextAvailableMobId(), 1, 20.5f, 20.5f, 10, 10, 10, 10, 0, heroType,
                                            heroConfig, expConfig);

            // This is probably not the right place to do this.
            // Only add items with a location set, the other ones go into the inventory - that we do not support yet
            foreach (var item in heroConfig.InitialEquipment)
            {
                if (item.location.Length > 0)
                {
                    newPlayer.UpdateEquipment(item.location, itemManager.getItemInstance(item.name));
                }
            }

            // TODO: Default torso for testing. Remove when... we're done testing.
            newPlayer.UpdateEquipment("tors", itemManager.getItemInstance("aar"));

            mobManager.AddPlayer(newPlayer);
            return(newPlayer.Id);
        }
예제 #14
0
        public void Initialize(string characterName, eHero hero, eSessionType sessionType)
        {
            sessionManager = getSessionManager(sessionType);
            sessionManager.Initialize();

            sessionManager.OnSetSeed       += OnSetSeedEvent;
            sessionManager.OnLocatePlayers += OnLocatePlayers;
            sessionManager.OnPlayerInfo    += OnPlayerInfo;
            sessionManager.OnFocusOnPlayer += OnFocusOnPlayer;

            mapInfo = new List <IMapInfo>();
            sceneManager.ChangeScene(eSceneType.Game);

            sessionManager.JoinGame(characterName, hero);
        }
예제 #15
0
    void SetHero(eHero eHero)
    {
        for (int i = 0; i < nHERO_SIZE; ++i)
        {
            string heroPath = string.Format(Path.HEROPREFAB, eHero.ToString());

            obj = Instantiate(Resources.Load(heroPath)) as GameObject;

            obj.transform.parent = heroRoot;
            obj.SetActive(false);

            heroPoolList.Add(obj.transform);
            eHeroList.Add(eHero);
        }
    }
예제 #16
0
        private void RenderHero(eHero hero)
        {
            var renderInfo = heroRenderInfo[hero];

            switch (renderInfo.Stance)
            {
            case eHeroStance.Idle:
                renderWindow.Draw(renderInfo.IdleSprite, (int)(renderInfo.IdleSprite.TotalFrames * secondTimer));
                break;

            case eHeroStance.IdleSelected:
                renderWindow.Draw(renderInfo.IdleSelectedSprite, (int)(renderInfo.IdleSelectedSprite.TotalFrames * secondTimer));
                break;

            case eHeroStance.Approaching:
            {
                var framePct = renderInfo.SpecialFrameTime / (float)renderInfo.ForwardWalkTimeMs;
                renderWindow.Draw(renderInfo.ForwardWalkSprite, (int)(renderInfo.ForwardWalkSprite.TotalFrames * framePct));
                if (renderInfo.ForwardWalkSpriteOverlay != null)
                {
                    renderWindow.Draw(renderInfo.ForwardWalkSpriteOverlay, (int)(renderInfo.ForwardWalkSpriteOverlay.TotalFrames * framePct));
                }
            }
            break;

            case eHeroStance.Selected:
            {
                var framePct = renderInfo.SpecialFrameTime / (float)1000;
                renderWindow.Draw(renderInfo.SelectedSprite, (int)(renderInfo.SelectedSprite.TotalFrames * framePct));
                if (renderInfo.SelectedSpriteOverlay != null)
                {
                    renderWindow.Draw(renderInfo.SelectedSpriteOverlay, (int)(renderInfo.SelectedSpriteOverlay.TotalFrames * framePct));
                }
            }
            break;

            case eHeroStance.Retreating:
            {
                var framePct = renderInfo.SpecialFrameTime / (float)renderInfo.BackWalkTimeMs;
                renderWindow.Draw(renderInfo.BackWalkSprite, (int)(renderInfo.BackWalkSprite.TotalFrames * framePct));
                if (renderInfo.BackWalkSpriteOverlay != null)
                {
                    renderWindow.Draw(renderInfo.BackWalkSpriteOverlay, (int)(renderInfo.BackWalkSpriteOverlay.TotalFrames * framePct));
                }
            }
            break;
            }
        }
예제 #17
0
    //던전입장
    public void BattleEntrance()
    {
        if (monster == null)
        {
            sMonsterName = SceneMng.Ins.sMonsterName;
        }

        var list = heroDatas.GetEnumerator();

        int idx = 0;

        while (list.MoveNext())
        {
            var data = list.Current;

            eHero eHero = (eHero)Enum.Parse(typeof(eHero), data.strPrefab);

            for (int i = 0; i < pool.eHeroList.Count; ++i)
            {
                if (eHero == pool.eHeroList[i])
                {
                    if (pool.heroPoolList[i].gameObject.activeSelf == false)
                    {
                        pool.heroPoolList[i].gameObject.SetActive(true);
                        pool.heroPoolList[i].position = heroRespawn[idx].position;

                        heroObjList[idx] = pool.heroPoolList[i];

                        heroList.Add(pool.heroPoolList[i].GetComponent <Hero>());
                        inGameHeroList.Add(heroList[idx]);

                        heroSpawnEffect[idx].SetActive(true);

                        break;
                    }
                }
            }
            ++idx;
        }


        StartCoroutine(StartDungeon());
    }
예제 #18
0
        public PlayerState(int clientHash, string name, int id, int level, float x, float y,
                           int vitality, int strength, int energy, int dexterity, long experience, eHero herotype,
                           IHeroTypeConfig heroconfig, ILevelExperienceConfig expconfig)
            : base(name, id, level, 0, x, y)
        {
            this.ClientHash = clientHash;
            Stamina         = new Stat(0, 0, 0, true);
            Mana            = new Stat(0, 0, 0, true);
            ManaRegen       = new Stat(0, heroconfig.StartingManaRegen, heroconfig.StartingManaRegen, true);

            Vitality  = new Stat(0, vitality, vitality, true);
            Strength  = new Stat(0, strength, strength, true);
            Energy    = new Stat(0, energy, energy, true);
            Dexterity = new Stat(0, dexterity, dexterity, true);

            AttackRating  = new Stat(0, 0, 0, false);
            DefenseRating = new Stat(0, 0, 0, false);

            WalkVelocity = new Stat(0, heroconfig.WalkVelocity, 100, false); // TODO: what should max velocity be? (replace the 100)
            RunVelocity  = new Stat(0, heroconfig.RunVelocity, 100, false);  // TODO: what should max velocity be?
            RunDrain     = new Stat(0, heroconfig.RunDrain, heroconfig.RunDrain, true);

            Experience = experience; // how much total exp do they have


            HeroType         = herotype;
            HeroTypeConfig   = heroconfig;
            ExperienceConfig = expconfig;

            AddFlag(eMobFlags.PLAYER);

            RefreshMaxes(); // initialize the max health / mana / energy
            Health.SetCurrent(Health.GetMax());
            Mana.SetCurrent(Mana.GetMax());
            Energy.SetCurrent(Energy.GetMax());
            RefreshDerived();
        }
예제 #19
0
        private void PlayHeroDeselected(eHero hero)
        {
            switch (hero)
            {
            case eHero.Barbarian:
                sfxChannel2 = soundProvider.PlaySfx(sfxDictionary[ResourcePaths.SFXBarbarianDeselect]);
                break;

            case eHero.Necromancer:
                sfxChannel2 = soundProvider.PlaySfx(sfxDictionary[ResourcePaths.SFXNecromancerDeselect]);
                break;

            case eHero.Paladin:
                sfxChannel2 = soundProvider.PlaySfx(sfxDictionary[ResourcePaths.SFXPaladinDeselect]);
                break;

            case eHero.Assassin:
                sfxChannel2 = soundProvider.PlaySfx(sfxDictionary[ResourcePaths.SFXAssassinDeselect]);
                break;

            case eHero.Sorceress:
                sfxChannel2 = soundProvider.PlaySfx(sfxDictionary[ResourcePaths.SFXSorceressDeselect]);
                break;

            case eHero.Amazon:
                sfxChannel2 = soundProvider.PlaySfx(sfxDictionary[ResourcePaths.SFXAmazonDeselect]);
                break;

            case eHero.Druid:
                sfxChannel2 = soundProvider.PlaySfx(sfxDictionary[ResourcePaths.SFXDruidDeselect]);
                break;

            default:
                break;
            }
        }
예제 #20
0
 public void LoadFrom(BinaryReader br)
 {
     HeroType   = (eHero)br.ReadByte();
     PlayerName = br.ReadString();
 }
예제 #21
0
 public static string ToToken(this eHero source) => tokens[source];
예제 #22
0
파일: UI_Info.cs 프로젝트: beerbu89/Project
    public void SetInfo()
    {
        var list = BattleMng.Ins.heroDatas.GetEnumerator();

        int idx  = 0;
        int size = BattleMng.Ins.heroDatas.Count;

        int currentSkillIdx = 0;

        while (list.MoveNext())
        {
            var data = list.Current;

            string imgPath = string.Format(Path.IMG, data.strName);

            li_HeroImg[idx].sprite = Resources.Load <Sprite>(imgPath) as Sprite;

            li_HeroHpBar[idx].SetHpBar(data);

            BattleMng.Ins.heroList[idx].hpBar = li_HeroHpBar[idx];

            eHero eHero = (eHero)data.nID;
            var   temp  = eHero.GetHeroSkillData();

            var s = temp.strSkill.Split(',');

            int sIdx = 0;

            if (currentSkillIdx >= li_Skill.Count)
            {
                return;
            }

            for (int i = 0; i < nSKILL_COUNT; ++i)
            {
                string path = string.Format(Path.IMG, s[sIdx]);

                li_Skill[currentSkillIdx].sprite = Resources.Load <Sprite>(path) as Sprite;

                SkillMng.Ins.li_DeActiveSkillCoolTime.Add(li_Skill[currentSkillIdx]);

                SkillMng.Ins.li_ActiveSkill.Add(li_Skill[currentSkillIdx]);

                ++sIdx;
                ++currentSkillIdx;
            }

            currentIdx = currentSkillIdx;

            ++idx;
        }

        SkillMng.Ins.Init();

        for (int i = currentSkillIdx; i < li_Skill.Count; ++i)
        {
            li_Skill[i].gameObject.SetActive(false);
        }

        for (int i = size; i < li_HeroImg.Count; ++i)
        {
            li_HeroImg[i].gameObject.SetActive(false);
            li_HeroHpBar[i].gameObject.SetActive(false);
        }
    }
예제 #23
0
 public static HeroSkillData GetHeroSkillData(this eHero eHero)
 {
     return(TableMng.Ins.GetValue <int, HeroSkillData>(eTable.HeroSkill, (int)eHero));
 }
예제 #24
0
        public static MPQCOF Load(Stream stream, Dictionary <string, List <AnimationData> > animations, eHero hero, eMobMode mobMode, PlayerEquipment equipment)
        {
            var result = new MPQCOF
            {
                MobMode = mobMode,
                Hero    = hero
            };

            var br = new BinaryReader(stream);

            result.NumberOfLayers     = br.ReadByte();
            result.FramesPerDirection = br.ReadByte();
            result.NumberOfDirections = br.ReadByte(); // Number of directions

            br.ReadBytes(25);                          // Skip 25 unknown bytes...

            var layers = new List <COFLayer>();

            result.CompositLayers = new Dictionary <eCompositType, int>();

            for (var layerIdx = 0; layerIdx < result.NumberOfLayers; layerIdx++)
            {
                var layer = new COFLayer
                {
                    COF          = result,
                    CompositType = (eCompositType)br.ReadByte(),
                    Shadow       = br.ReadByte()
                };
                br.ReadByte(); // Unknown
                layer.IsTransparent = br.ReadByte() != 0;
                layer.DrawEffect    = (eDrawEffect)br.ReadByte();
                layer.WeaponClass   = Encoding.ASCII.GetString(br.ReadBytes(4)).Trim('\0').ToWeaponClass();
                layers.Add(layer);
                result.CompositLayers[layer.CompositType] = layerIdx;
            }
            result.Layers          = layers.ToArray();
            result.AnimationFrames = br.ReadBytes(result.FramesPerDirection).Select(x => (eAnimationFrame)x);
            result.Priority        = br.ReadBytes(result.FramesPerDirection * result.NumberOfLayers * result.NumberOfDirections).Select(x => (eCompositType)x).ToArray();

            var cofName = $"{hero.ToToken()}{mobMode.ToToken()}{equipment.WeaponClass.ToToken()}".ToUpper();

            result.Animations = animations[cofName];
            br.Dispose();
            return(result);
        }
예제 #25
0
        public string GetCharacterDccPath(eHero hero, eMobMode mobMode, eCompositType compositType, PlayerEquipment equipment)
        {
            var fileName  = $@"{ResourcePaths.PlayerAnimationBase}\{hero.ToToken()}\{compositType.ToToken()}\{hero.ToToken()}{compositType.ToToken()}".ToLower();
            var armorType = eArmorType.Lite;

            // Override default armor type based on equipped torso
            if (equipment.Torso != null && (equipment.Torso.Item as Armor).ArmorTypes.ContainsKey(compositType))
            {
                armorType = (equipment.Torso.Item as Armor).ArmorTypes[compositType];
            }

            switch (compositType)
            {
            case eCompositType.Head:
                fileName += $"{equipment.Head?.Item.Code ?? eArmorType.Lite.ToToken()}{mobMode.ToToken()}";
                return(_mpqLookup.ContainsKey($"{fileName}{equipment.WeaponClass.ToToken()}.dcc".ToLower())
                        ? $"{fileName}{equipment.WeaponClass.ToToken()}.dcc".ToLower()
                        : $"{fileName}{eWeaponClass.HandToHand.ToToken()}.dcc".ToLower());

            case eCompositType.Torso:
            case eCompositType.Legs:
            case eCompositType.RightArm:
            case eCompositType.LeftArm:
                fileName += $"{armorType.ToToken()}{mobMode.ToToken()}";
                return(_mpqLookup.ContainsKey($"{fileName}{equipment.WeaponClass.ToToken()}.dcc".ToLower())
                        ? $"{fileName}{equipment.WeaponClass.ToToken()}.dcc".ToLower()
                        : $"{fileName}{eWeaponClass.HandToHand.ToToken()}.dcc".ToLower());

            case eCompositType.RightHand:
                if (!(equipment.RightArm?.Item is Weapon))
                {
                    return(null);
                }
                fileName += $"{equipment.RightArm.Item.Code}{mobMode.ToToken()}{equipment.WeaponClass.ToToken()}.dcc".ToLower();
                return(fileName);

            case eCompositType.LeftHand:
                if (!(equipment.LeftArm?.Item is Weapon))
                {
                    return(null);
                }
                fileName += $"{equipment.LeftArm.Item.Code}{mobMode.ToToken()}{equipment.WeaponClass.ToToken()}.dcc".ToLower();
                return(fileName);

            case eCompositType.Shield:
                if (!(equipment.LeftArm?.Item is Armor))
                {
                    return(null);
                }
                fileName += $"{equipment.LeftArm.Item.Code}{mobMode.ToToken()}";
                return(_mpqLookup.ContainsKey($"{fileName}{equipment.WeaponClass.ToToken()}.dcc".ToLower())
                        ? $"{fileName}{equipment.WeaponClass.ToToken()}.dcc".ToLower()
                        : $"{fileName}{eWeaponClass.HandToHand.ToToken()}.dcc".ToLower());

            // TODO: Figure these out...
            case eCompositType.Special1:
            case eCompositType.Special2:
                fileName += $"{armorType.ToToken()}{mobMode.ToToken()}{equipment.WeaponClass}.dcc".ToLower();
                return(_mpqLookup.ContainsKey(fileName)
                        ? fileName
                        : null); // TODO: Should we silence this?

            case eCompositType.Special3:
            case eCompositType.Special4:
            case eCompositType.Special5:
            case eCompositType.Special6:
            case eCompositType.Special7:
            case eCompositType.Special8:
            default:
                return(null);
            }
        }
예제 #26
0
 public MFJoinGame(string playerName, eHero heroType)
 {
     PlayerName = playerName;
     HeroType   = heroType;
 }
예제 #27
0
        private void UpdateHeroSelectionHover(eHero hero, long ms, bool canSelect)
        {
            if (hero == eHero.None)
            {
                return;
            }
            var renderInfo = heroRenderInfo[hero];

            if (renderInfo.Stance == eHeroStance.Approaching)
            {
                renderInfo.SpecialFrameTime += ms;
                if (renderInfo.SpecialFrameTime >= renderInfo.ForwardWalkTimeMs)
                {
                    renderInfo.Stance           = eHeroStance.Selected;
                    renderInfo.SpecialFrameTime = 0;
                }

                return;
            }

            if (renderInfo.Stance == eHeroStance.Retreating)
            {
                renderInfo.SpecialFrameTime += ms;
                if (renderInfo.SpecialFrameTime >= renderInfo.BackWalkTimeMs)
                {
                    renderInfo.Stance           = eHeroStance.Idle;
                    renderInfo.SpecialFrameTime = 0;
                }

                return;
            }

            if (renderInfo.Stance == eHeroStance.Selected)
            {
                renderInfo.SpecialFrameTime += ms;
                while (renderInfo.SpecialFrameTime >= 1000)
                {
                    renderInfo.SpecialFrameTime -= 1000;
                }
                return;
            }

            if (!canSelect)
            {
                return;
            }

            // No need to highlight a hero if they are next to the campfire
            if (renderInfo.Stance == eHeroStance.Selected)
            {
                return;
            }

            var mouseX = mouseInfoProvider.MouseX;
            var mouseY = mouseInfoProvider.MouseY;

            var b          = renderInfo.SelectionBounds;
            var mouseHover = (mouseX >= b.Left) && (mouseX <= b.Left + b.Width) && (mouseY >= b.Top) && (mouseY <= b.Top + b.Height);

            if (mouseHover && mouseInfoProvider.LeftMouseDown)
            {
                showEntryUi                 = true;
                renderInfo.Stance           = eHeroStance.Approaching;
                renderInfo.SpecialFrameTime = 0;


                foreach (var ri in heroRenderInfo)
                {
                    if (ri.Value.Stance != eHeroStance.Selected)
                    {
                        continue;
                    }

                    PlayHeroDeselected(ri.Key);
                    ri.Value.Stance           = eHeroStance.Retreating;
                    ri.Value.SpecialFrameTime = 0;
                    break;
                }

                selectedHero = hero;
                UpdateHeroText();
                PlayHeroSelected(hero);

                return;
            }

            heroRenderInfo[hero].Stance = mouseHover ? eHeroStance.IdleSelected : eHeroStance.Idle;

            if (selectedHero == null && mouseHover)
            {
                selectedHero = hero;
                UpdateHeroText();
            }
        }