Example #1
0
        /// <summary>
        /// Determines the absolute position of this position for a formation facing this direction.
        /// For instance, for a facing of west, the front right position would be located in the northwest.
        /// </summary>
        /// <param name="facing"></param>
        /// <returns></returns>
        public AbsolutePosition AsAbsolute(Direction facing)
        {
            if (facing == Direction.North)
            {
                return(AbsolutePosition.FromCoordinates(Column, Row));
            }
            if (facing == Direction.South)
            {
                return(AbsolutePosition.FromCoordinates(2 - Column, 2 - Row));
            }
            if (facing == Direction.East)
            {
                return(AbsolutePosition.FromCoordinates(2 - Row, Column));
            }
            if (facing == Direction.West)
            {
                return(AbsolutePosition.FromCoordinates(Row, 2 - Column));
            }

            throw new ArgumentException("Invalid facing specified, not north/south/east/west");
        }
Example #2
0
 private StatsBox FindStatsBox(AbsolutePosition pos)
 {
     if (pos == AbsolutePosition.Northwest)
     {
         return(sbNW);
     }
     if (pos == AbsolutePosition.North)
     {
         return(sbN);
     }
     if (pos == AbsolutePosition.Northeast)
     {
         return(sbNE);
     }
     if (pos == AbsolutePosition.West)
     {
         return(sbW);
     }
     if (pos == AbsolutePosition.Center)
     {
         return(sbC);
     }
     if (pos == AbsolutePosition.East)
     {
         return(sbE);
     }
     if (pos == AbsolutePosition.Southwest)
     {
         return(sbSW);
     }
     if (pos == AbsolutePosition.South)
     {
         return(sbS);
     }
     if (pos == AbsolutePosition.Southeast)
     {
         return(sbSE);
     }
     throw new Exception("Invalid position specified for FindStatsBox");
 }
Example #3
0
        public Color GetColor(AbsolutePosition pos)
        {
            if (Formation == null)
            {
                if (Items.ContainsKey(pos))
                {
                    return(Items[pos].Color);
                }
                return(Terrain.Color);
            }
            var creature = Formation.GetCreature(pos);

            if (creature == null)
            {
                if (Items.ContainsKey(pos))
                {
                    return(Items[pos].Color);
                }
                return(Terrain.Color);
            }
            return(creature.Color);
        }
Example #4
0
        public char GetSymbol(AbsolutePosition pos)
        {
            if (Formation == null)
            {
                if (Items.ContainsKey(pos))
                {
                    return(Items[pos].Symbol);
                }
                return(Terrain.Symbol);
            }
            var creature = Formation.GetCreature(pos);

            if (creature == null)
            {
                if (Items.ContainsKey(pos))
                {
                    return(Items[pos].Symbol);
                }
                return(Terrain.Symbol);
            }
            return(creature.Symbol);
        }
Example #5
0
        private void Fight(Tile attackerTile, Tile defenderTile)
        {
            var attackers = attackerTile.Formation;
            var defenders = defenderTile.Formation;

            if (attackers == null || defenders == null)
            {
                return;
            }

            int tileSize = 3;

            foreach (var kvp in attackers.CreaturePositions)
            {
                // who is attacking now?
                var attacker = attackers.CreaturePositions[kvp.Key];

                // is attacker blocked behind another attacker? then he can't attack
                bool             blocked = false;
                RelativePosition pos     = kvp.Key;
                while (true)
                {
                    var apos = pos.AsAbsolute(attackers.Facing);
                    apos = AbsolutePosition.FromCoordinates(apos.Column + attackers.Facing.DeltaX, apos.Row + attackers.Facing.DeltaY);
                    if (apos == null)
                    {
                        break;
                    }
                    pos = apos.RelativeTo(attackers.Facing);
                    if (pos != kvp.Key && attackers.CreaturePositions.ContainsKey(pos))
                    {
                        Log.Append("The " + attacker.Name + " is blocked by the " + attackers.CreaturePositions[pos].Name + ".");
                        blocked = true;
                        break;
                    }
                }
                if (blocked)
                {
                    continue;
                }

                // find nearest target
                Creature         defender = null;
                int              distance;
                var              absPos = kvp.Key.AsAbsolute(attackers.Facing);
                AbsolutePosition targetPos;
                if (attackers.Facing == Direction.North)
                {
                    distance  = absPos.Row;
                    targetPos = AbsolutePosition.FromCoordinates(absPos.Column, tileSize - 1);
                }
                else if (attackers.Facing == Direction.South)
                {
                    distance  = tileSize - 1 - absPos.Row;
                    targetPos = AbsolutePosition.FromCoordinates(absPos.Column, 0);
                }
                else if (attackers.Facing == Direction.East)
                {
                    distance  = tileSize - 1 - absPos.Column;
                    targetPos = AbsolutePosition.FromCoordinates(0, absPos.Column);
                }
                else if (attackers.Facing == Direction.West)
                {
                    distance  = absPos.Column;
                    targetPos = AbsolutePosition.FromCoordinates(tileSize - 1, absPos.Column);
                }
                else
                {
                    throw new Exception("Invalid formation facing, not north/south/east/west");
                }
                foreach (var distanceGroup in AbsolutePosition.All.GroupBy(pos2 => targetPos.DistanceTo(pos2)))
                {
                    var matches = distanceGroup.Where(pos2 =>
                    {
                        var relpos = pos2.RelativeTo(defenders.Facing);
                        return(defenders.CreaturePositions.ContainsKey(relpos) && defenders.CreaturePositions[relpos] != null);
                    });
                    if (matches.Any())
                    {
                        // multiple targets at same distance? pick one at random!
                        defender  = defenders.CreaturePositions[matches.Pick().RelativeTo(defenders.Facing)];
                        distance += distanceGroup.Key;
                        break;
                    }
                }

                // attaaaaack!
                if (defender == null)
                {
                    Log.Append("The " + attacker.Name + " has no one to attack.");                     // everyone's already dead!
                }
                else
                {
                    var    attack = attacker.Attack;
                    var    defense = defender.Defense;
                    var    atkBody = attacker.Body;
                    var    atkMind = attacker.Mind;
                    var    defBody = defender.Body;
                    var    defMind = defender.Mind;
                    int    atkStat, defStat, range;
                    string atkText;
                    if (atkBody - defBody >= atkMind - defMind)
                    {
                        // use physical attack
                        atkStat = atkBody;
                        defStat = defBody;
                        atkText = attacker.PhysicalAttackText;
                        range   = attacker.PhysicalAttackRange;
                    }
                    else
                    {
                        // use mental attack
                        atkStat = atkMind;
                        defStat = defMind;
                        atkText = attacker.MentalAttackText;
                        range   = attacker.MentalAttackRange;
                    }
                    var color = defenders == Heroes ? Color.Yellow : Color.White;

                    // accuracy penalty: 1/3 chance to miss for each subtile out of range
                    bool miss = false;
                    for (int i = 0; i < distance - range; i++)
                    {
                        if (Dice.Range(1, 3) == 1)
                        {
                            miss = true;
                            break;
                        }
                    }

                    string msg;
                    if (miss)
                    {
                        color = Color.Gray;
                        msg   = "The " + attacker.Name + " " + atkText + " the " + defender.Name + ", but misses (attack range " + range + ", target distance " + distance + ").";
                    }
                    else
                    {
                        var atkRoll = Dice.Roll(attack, atkStat);
                        var defRoll = Dice.Roll(defense, defStat);
                        var damage  = Math.Max(0, atkRoll - defRoll);
                        msg              = "The " + attacker.Name + " " + atkText + " the " + defender.Name + " (" + attack + "d" + atkStat + " vs. " + defense + "d" + defStat + ") for " + damage + " damage.";
                        defender.Health -= damage;
                        if (defender.Health <= 0)
                        {
                            msg += " The " + defender.Name + " is slain!";
                            if (defenders == Heroes)
                            {
                                color = Color.Red;
                            }
                            foreach (var p in RelativePosition.All)
                            {
                                if (defenders.CreaturePositions.ContainsKey(p) && defenders.CreaturePositions[p] == defender)
                                {
                                    KillCreature(defenderTile, p);                                     // he's dead, Jim...
                                }
                            }
                            if (!defenders.CreaturePositions.Any())
                            {
                                defenderTile.Formation = null;                                 // they're all dead, Dave...
                            }
                        }
                    }
                    Log.Append(msg, color);
                }
            }
        }
Example #6
0
 /// <summary>
 /// Computes Manhattan distance from this position to the target.
 /// </summary>
 /// <param name="target"></param>
 /// <returns></returns>
 public int DistanceTo(AbsolutePosition target)
 {
     return(Math.Abs(Column - target.Column) + Math.Abs(Row - target.Row));
 }
Example #7
0
 public Creature GetCreature(AbsolutePosition pos)
 {
     return(GetCreature(pos.RelativeTo(Facing)));
 }
Example #8
0
        private void DrawSubtile(Tile tile, Graphics g, Font font, int border, int x, int y, AbsolutePosition pos)
        {
            var charSize = font.Size;

            g.DrawString(tile.GetSymbol(pos).ToString(), font, GetBrush(tile.GetColor(pos)), new PointF(x + charSize * (pos.Column + border), y + charSize * (pos.Row + border)));
        }
Example #9
0
        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (heroesDead)
            {
                return;                 // no doing stuff when you're dead!
            }
            if (heroBeingPlaced >= 0)
            {
                if (e.KeyCode == Keys.F)
                {
                    heroBeingPlaced = -1;                     // cancel
                    Log.Append("Never mind, then.");
                }
                else
                {
                    // place the hero
                    var pos = AbsolutePosition.FromKey(e.KeyCode);
                    if (pos == null)
                    {
                        Log.Append("Use the numeric keypad to place the " + map.Heroes.CreaturePositions.Values.ElementAt(heroBeingPlaced).Name + " or press F to cancel.");
                    }
                    else
                    {
                        if (newHeroPositions.Keys.Contains(pos))
                        {
                            Log.Append("The " + newHeroPositions[pos].Name + " is already in the " + pos.Name + ". Try again or press F to cancel.");
                        }
                        else
                        {
                            // set placement
                            newHeroPositions[pos] = map.Heroes.CreaturePositions.Values.ElementAt(heroBeingPlaced);

                            // move on to next hero, or be done if last hero was placed
                            heroBeingPlaced++;
                            if (heroBeingPlaced >= map.Heroes.CreaturePositions.Values.Count)
                            {
                                map.Heroes.CreaturePositions.Clear();
                                foreach (var kvp in newHeroPositions)
                                {
                                    map.Heroes.CreaturePositions.Add(kvp.Key.RelativeTo(map.Heroes.Facing), kvp.Value);
                                }
                                heroBeingPlaced = -1;
                                Log.Append("The heroes rearrange their formation.");
                                map.Heroes.Act(map.Tiles[map.HeroX, map.HeroY].Terrain.MovementCost);
                                map.LetMonstersAct();
                            }
                            else
                            {
                                Log.Append("Please choose a position for the " + map.Heroes.CreaturePositions.Values.ElementAt(heroBeingPlaced).Name + ".");
                            }
                        }
                    }
                }
            }
            else if (mode == 's')
            {
                if (heroDoingStuff != null)
                {
                    if (e.KeyCode == Keys.S)
                    {
                        // cancel
                        mode           = ' ';
                        heroDoingStuff = null;
                        Log.Append("Never mind, then.");
                    }
                    else
                    {
                        // pick skill
                        var skillIdx   = GetNumberFromKey(e.KeyCode) - 1;
                        var skillToUse = heroDoingStuff.Skills.ElementAtOrDefault(skillIdx);

                        if (skillToUse == null)
                        {
                            // prompt for skill to use
                            Log.Append("What skill will the " + heroDoingStuff.Name + " use? (press S again to cancel)");
                            int skillNum = 0;
                            foreach (var skill in heroDoingStuff.Skills)
                            {
                                skillNum++;
                                Log.Append(skillNum + ": " + skill.Name + " (" + skill.ManaCost + " mana) - " + skill.Description);
                            }
                        }
                        else if (skillToUse.ManaCost > heroDoingStuff.Mana)
                        {
                            // not enough mana, cancel
                            Log.Append("The " + heroDoingStuff.Name + " lacks the mana for " + skillToUse.Name + "!");
                            mode           = ' ';
                            heroDoingStuff = null;
                            Log.Append("Never mind, then.");
                        }
                        else
                        {
                            // use skill
                            Log.Append("The " + heroDoingStuff.Name + " " + skillToUse.Verb + " " + skillToUse.Name + "!");
                            int  x      = map.HeroX + map.Heroes.Facing.DeltaX;
                            int  y      = map.HeroY + map.Heroes.Facing.DeltaY;
                            Tile target = null;
                            if (map.CoordsInBounds(x, y))
                            {
                                target = map.Tiles[x, y];
                            }
                            skillToUse.Use(heroDoingStuff, map.Heroes, target, map);

                            // spend mana
                            heroDoingStuff.Mana -= skillToUse.ManaCost;

                            // use time
                            map.Heroes.Act(map.Tiles[map.HeroX, map.HeroY].Terrain.MovementCost);
                            map.LetMonstersAct();

                            // done using skill
                            mode           = ' ';
                            heroDoingStuff = null;
                        }
                    }
                }
                else
                {
                    if (e.KeyCode == Keys.S)
                    {
                        // cancel
                        mode           = ' ';
                        heroDoingStuff = null;
                        Log.Append("Never mind, then.");
                    }
                    else
                    {
                        // pick hero
                        var heroIdx = GetNumberFromKey(e.KeyCode) - 1;
                        heroDoingStuff = map.Heroes.CreaturePositions.Values.ElementAtOrDefault(heroIdx);
                        if (heroDoingStuff == null)
                        {
                            // didn't pick a hero
                            Log.Append("Who will use a skill? (press S again to cancel)");
                            int heroNum = 0;
                            foreach (var hero in map.Heroes.CreaturePositions.Values)
                            {
                                heroNum++;
                                Log.Append(heroNum + ": " + hero.Name, hero.Color);
                            }
                        }
                        else
                        {
                            // prompt for skill to use
                            Log.Append("What skill will the " + heroDoingStuff.Name + " use? (press S again to cancel)");
                            int skillNum = 0;
                            foreach (var skill in heroDoingStuff.Skills)
                            {
                                skillNum++;
                                Log.Append(skillNum + ": " + skill.Name + " (" + skill.ManaCost + " mana) - " + skill.Description);
                            }
                        }
                    }
                }
            }
            else if (mode == 'w')
            {
                if (heroDoingStuff != null)
                {
                    if (e.KeyCode == Keys.W)
                    {
                        // cancel
                        mode           = ' ';
                        heroDoingStuff = null;
                        Log.Append("Never mind, then.");
                    }
                    else
                    {
                        // pick weapon
                        var idx       = GetNumberFromKey(e.KeyCode) - 1;
                        var available = Weapon.All.Where(w => w.Hero == heroDoingStuff && w.HasBeenFound);
                        var weapon    = available.ElementAtOrDefault(idx);

                        if (weapon == null)
                        {
                            if (!available.Any())
                            {
                                // nothing to equip
                                Log.Append("The " + heroDoingStuff.Name + " doesn't have any weapons to equip!");
                                mode           = ' ';
                                heroDoingStuff = null;
                            }
                            else
                            {
                                // prompt for weapon to equip
                                Log.Append("What weapon will the " + heroDoingStuff.Name + " equip? (press W again to cancel)");
                                int num = 0;
                                foreach (var w in available)
                                {
                                    num++;
                                    Log.Append(num + ": " + w.Name + " (" + w.Description + ")");
                                }
                            }
                        }
                        else
                        {
                            if (heroDoingStuff.Weapon == weapon)
                            {
                                // nothing to do
                                Log.Append("But the " + heroDoingStuff.Name + " has already equipped the " + weapon.Name + "!"); mode = ' ';
                                heroDoingStuff = null;
                            }
                            else
                            {
                                // equip weapon
                                Log.Append("The " + heroDoingStuff.Name + " equips the " + weapon.Name + ".");
                                heroDoingStuff.Weapon = weapon;

                                // use time
                                map.Heroes.Act(map.Tiles[map.HeroX, map.HeroY].Terrain.MovementCost);
                                map.LetMonstersAct();

                                // done equipping
                                mode           = ' ';
                                heroDoingStuff = null;
                            }
                        }
                    }
                }
                else
                {
                    if (e.KeyCode == Keys.W)
                    {
                        // cancel
                        mode           = ' ';
                        heroDoingStuff = null;
                        Log.Append("Never mind, then.");
                    }
                    else
                    {
                        // pick hero
                        var heroIdx = GetNumberFromKey(e.KeyCode) - 1;
                        heroDoingStuff = map.Heroes.CreaturePositions.Values.ElementAtOrDefault(heroIdx);
                        if (heroDoingStuff == null)
                        {
                            // didn't pick a hero
                            Log.Append("Who will equip a weapon? (press W again to cancel)");
                            int heroNum = 0;
                            foreach (var hero in map.Heroes.CreaturePositions.Values)
                            {
                                heroNum++;
                                Log.Append(heroNum + ": " + hero.Name, hero.Color);
                            }
                        }
                        else
                        {
                            var available = Weapon.All.Where(w => w.Hero == heroDoingStuff && w.HasBeenFound);
                            if (!available.Any())
                            {
                                // nothing to equip
                                Log.Append("The " + heroDoingStuff.Name + " doesn't have any weapons to equip!");
                                mode           = ' ';
                                heroDoingStuff = null;
                            }
                            else
                            {
                                // prompt for weapon to equip
                                Log.Append("What weapon will the " + heroDoingStuff.Name + " equip? (press W again to cancel)");
                                int num = 0;
                                foreach (var w in available)
                                {
                                    num++;
                                    Log.Append(num + ": " + w.Name + " (" + w.Description + ")");
                                }
                            }
                        }
                    }
                }
            }
            else if (mode == 'a')
            {
                if (heroDoingStuff != null)
                {
                    if (e.KeyCode == Keys.A)
                    {
                        // cancel
                        mode           = ' ';
                        heroDoingStuff = null;
                        Log.Append("Never mind, then.");
                    }
                    else
                    {
                        // pick armor
                        var idx       = GetNumberFromKey(e.KeyCode) - 1;
                        var available = Armor.All.Where(a => a.Hero == heroDoingStuff && a.HasBeenFound);
                        var armor     = available.ElementAtOrDefault(idx);

                        if (armor == null)
                        {
                            if (!available.Any())
                            {
                                // nothing to equip
                                Log.Append("The " + heroDoingStuff.Name + " doesn't have any armor to equip!");
                                mode           = ' ';
                                heroDoingStuff = null;
                            }
                            else
                            {
                                // prompt for armor to equip
                                Log.Append("What armor will the " + heroDoingStuff.Name + " equip? (press A again to cancel)");
                                int num = 0;
                                foreach (var a in available)
                                {
                                    num++;
                                    Log.Append(num + ": " + a.Name + " (" + a.Description + ")");
                                }
                            }
                        }
                        else
                        {
                            if (heroDoingStuff.Armor == armor)
                            {
                                // nothing to do
                                Log.Append("But the " + heroDoingStuff.Name + " has already equipped the " + armor.Name + "!");
                                mode           = ' ';
                                heroDoingStuff = null;
                            }
                            else
                            {
                                // equip armor
                                Log.Append("The " + heroDoingStuff.Name + " equips the " + armor.Name + ".");
                                heroDoingStuff.Armor = armor;

                                // use time
                                map.Heroes.Act(map.Tiles[map.HeroX, map.HeroY].Terrain.MovementCost);
                                map.LetMonstersAct();

                                // done equipping
                                mode           = ' ';
                                heroDoingStuff = null;
                            }
                        }
                    }
                }
                else
                {
                    if (e.KeyCode == Keys.A)
                    {
                        // cancel
                        mode           = ' ';
                        heroDoingStuff = null;
                        Log.Append("Never mind, then.");
                    }
                    else
                    {
                        // pick hero
                        var heroIdx = GetNumberFromKey(e.KeyCode) - 1;
                        heroDoingStuff = map.Heroes.CreaturePositions.Values.ElementAtOrDefault(heroIdx);
                        if (heroDoingStuff == null)
                        {
                            // didn't pick a hero
                            Log.Append("Who will equip armor? (press A again to cancel)");
                            int heroNum = 0;
                            foreach (var hero in map.Heroes.CreaturePositions.Values)
                            {
                                heroNum++;
                                Log.Append(heroNum + ": " + hero.Name, hero.Color);
                            }
                        }
                        else
                        {
                            var available = Armor.All.Where(a => a.Hero == heroDoingStuff && a.HasBeenFound);
                            if (!available.Any())
                            {
                                // nothing to equip
                                Log.Append("The " + heroDoingStuff.Name + " doesn't have any armor to equip!");
                                mode           = ' ';
                                heroDoingStuff = null;
                            }
                            else
                            {
                                // prompt for armor to equip
                                Log.Append("What armor will the " + heroDoingStuff.Name + " equip? (press A again to cancel)");
                                int num = 0;
                                foreach (var a in available)
                                {
                                    num++;
                                    Log.Append(num + ": " + a.Name + " (" + a.Description + ")");
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                if (e.KeyCode == Keys.F)
                {
                    // F: set formation
                    heroBeingPlaced  = 0;
                    newHeroPositions = new Dictionary <AbsolutePosition, Creature>();
                    Log.Append("Please choose a position for the " + map.Heroes.CreaturePositions.Values.ElementAt(heroBeingPlaced).Name + ".");
                }
                else if (e.KeyCode == Keys.S)
                {
                    // S: use skill
                    mode = 's';
                    Log.Append("Who will use a skill? (press S again to cancel)");
                    int heroNum = 0;
                    foreach (var hero in map.Heroes.CreaturePositions.Values)
                    {
                        heroNum++;
                        Log.Append(heroNum + ": " + hero.Name, hero.Color);
                    }
                }
                else if (e.KeyCode == Keys.W)
                {
                    // W: change weapon
                    mode = 'w';
                    Log.Append("Who will change his weapon? (press W again to cancel)");
                    int heroNum = 0;
                    foreach (var hero in map.Heroes.CreaturePositions.Values)
                    {
                        heroNum++;
                        Log.Append(heroNum + ": " + hero.Name, hero.Color);
                    }
                }
                else if (e.KeyCode == Keys.A)
                {
                    // W: change weapon
                    mode = 'a';
                    Log.Append("Who will change his armor? (press A again to cancel)");
                    int heroNum = 0;
                    foreach (var hero in map.Heroes.CreaturePositions.Values)
                    {
                        heroNum++;
                        Log.Append(heroNum + ": " + hero.Name, hero.Color);
                    }
                }
                else if (e.KeyCode == Keys.D5 || e.KeyCode == Keys.NumPad5 || e.KeyCode == Keys.Clear)
                {
                    // wait a turn
                    map.Heroes.Act(map.Tiles[map.HeroX, map.HeroY].Terrain.MovementCost);
                    map.LetMonstersAct();
                }
                else
                {
                    var dir = Direction.FromKey(e.KeyCode);
                    if (dir != null)
                    {
                        // movement
                        if (ModifierKeys.HasFlag(Keys.Shift))
                        {
                            // shift-arrow moves without rotating (strafe move)
                            map.Move(map.Heroes, dir);
                        }
                        else
                        {
                            // just plain arrow attempts to rotate instead of move if not facing direction of movement
                            map.MoveOrTurn(map.Heroes, dir);
                        }
                        map.LetMonstersAct();
                        if (!map.CoordsInBounds(map.HeroX, map.HeroY))
                        {
                            heroesDead = true;
                            Log.Append("Oh no! The heroes have fallen...", Color.Red);
                        }
                    }
                }
            }

            // see if final boss is dead
            if (!winner && !map.Tiles.Cast <Tile>().Any(t => t.Formation != null && t.Formation.CreaturePositions.Values.Any(c => c.Name == MonsterTemplate.ChaosLord.Archetype.Name)))
            {
                Log.Append("Congratulations! The Chaos Lord has been vanquished! The brave heroes can now retire to a life of fame... or they can continue slaying the foul minions that still plague the land!", Color.Magenta);
                winner = true;
                Text   = "TriQuest - *WINNER*";
            }

            // see if all monsters are dead
            if (map.Tiles.Cast <Tile>().All(t => t.Formation == null || t.Formation == map.Heroes))
            {
                Log.Append("Wow! You're really dedicated! You actually managed to slay every last monster! Double congratulations!!! Now go take a well-deserved rest!", Color.Magenta);
                omnicide = true;
                Text     = "TriQuest - +*OMNICIDE*+";
            }

            // refresh screen
            picMap.Invalidate();
            picMinimap.Invalidate();
            BindStatsBoxes(map.Heroes);
            RefreshLog();
        }