private void RemoveCombatant_Click(object sender, RoutedEventArgs e)
        {
            if (CombatantList.SelectedItem != null)
            {
                if (ActiveCombatant != null)
                {
                    if (ActiveCombatant.Name.Equals((CombatantList.SelectedItem as DD4ECombatant).Name))
                    {
                        var index = CombatantList.Items.IndexOf(ActiveCombatant);
                        if (index >= CombatantList.Items.Count - 1)
                        {
                            ActiveCombatant = CombatantList.Items[0] as DD4ECombatant;
                        }
                        else
                        {
                            ActiveCombatant = CombatantList.Items[index + 1] as DD4ECombatant;
                        }
                    }
                }

                var removeIndex = CombatantList.SelectedIndex;

                CombatantList.SelectedIndex = -1;

                Combatants.RemoveAt(removeIndex);
            }
        }
        private void SortByInitiative()
        {
            for (int i = 0; i < Combatants.Count - 1; i++)
            {
                var highestIndex = i;
                for (int j = i + 1; j < Combatants.Count; j++)
                {
                    if (Combatants[j].Initiative > Combatants[highestIndex].Initiative)
                    {
                        highestIndex = j;
                    }
                    else if (Combatants[j].Initiative == Combatants[highestIndex].Initiative)
                    {
                        if (Combatants[j].InitiativeBonus > Combatants[highestIndex].InitiativeBonus)
                        {
                            highestIndex = j;
                        }
                    }
                }

                if (i != highestIndex)
                {
                    Combatants = (ObservableCollection <DD4ECombatant>)Combatants.Swap(i, highestIndex);
                }
            }
        }
Exemple #3
0
 public override void PlaceCombatants(SafeDictionary <ICombatant, IntVector2> locations)
 {
     if (Sector.SpaceObjects.OfType <WarpPoint>().Any())
     {
         // HACK - warp point in sector, assume someone warped
         // TODO - do this for warp point exits instead since warp points may be one way
         // warp battles start with everyone mashed together to allow blockades
         foreach (var c in Combatants.OrderByDescending(q => q.Size))
         {
             PlaceCombatant(locations, 0, 0, c);
         }
     }
     else
     {
         // place all combatants at the points of a regular polygon
         var sideLength = 20 + (int)Math.Ceiling((double)Combatants.GroupBy(q => q.Owner).Max(q => q.Count()));                 // make sure no one can shoot each other at the start
         // https://stackoverflow.com/questions/32169875/calculating-the-coordinates-of-a-regular-polygon-given-its-center-and-its-side-l
         var radius = sideLength / (2 * Sin(PI / Empires.Count()));
         var combs  = Combatants.ToArray();
         for (int i = 0; i < Empires.Count(); i++)
         {
             var x = radius * Cos(PI / Empires.Count() * (1 + 2 * i));
             var y = radius * Sin(PI / Empires.Count() * (1 + 2 * i));
             foreach (var comb in Combatants.Where(q => q.Owner == Empires.ElementAt(i)).OrderByDescending(q => q.Size))
             {
                 PlaceCombatant(locations, x, y, comb);
             }
         }
     }
 }
        private void PopulateGladiatorList(int numberToBuild)
        {
            var factory = new GladiatorFactory();

            for (var i = 0; i < numberToBuild; i++)
            {
                Combatants.Add(factory.BuildGladiator());
            }
        }
Exemple #5
0
        public void EnemyTurn()
        {
            var highestPresence = Combatants.Max(u => u.Player.Stats.Presence);

            AttackTarget = Combatants.Where(u => u.Player.Stats.Presence == highestPresence).First();
            if (AttackTarget == null)
            {
                Target.Combat = null;
                return;
            }
            if (AttackTarget.Player.Stats.CurrHealth <= 0)
            {
                Target.Combat = null;
                return;
            }
            // Roll to see if the monster lands a hit
            int hit    = Roll(100);
            int attack = Strike;

            if (hit >= AttackTarget.Player.Stats.Agility)
            {
                // Check if the attack is a critical
                int crit = Roll(100);
                if (crit >= AttackTarget.Player.Stats.CritAvoid)
                {
                    AttackTarget.Connection.SendMessage(AttackCriticalFlavor);
                    attack = attack + (Strike / 2);
                }
                if (crit < AttackTarget.Player.Stats.CritAvoid)
                {
                    // If it's not critical, check if it's weak
                    int weak = Roll(100);
                    if (weak <= AttackTarget.Player.Stats.Luck)
                    {
                        AttackTarget.Connection.SendMessage(AttackWeakFlavor);
                        attack = attack - (Strike / 2);
                    }
                    AttackTarget.Connection.SendMessage(AttackSuccessFlavor);
                }
                // If the player is blocking, attack gets a further strike to damage
                if (AttackTarget.Player.IsBlocking)
                {
                    attack = attack - AttackTarget.Player.Stats.Defense;
                    if (attack < 0)
                    {
                        attack = 0;
                    }
                    CombatSay($"{Target.Name} is blocked by {AttackTarget.Name}!");
                }
                AttackTarget.Player.TakeDamage(attack);
                CombatSay($"{Target.Name} deals {Strike} damage to {AttackTarget.Name}");
                AttackTarget.Connection.SendMessage($"Your current health is {AttackTarget.Player.Stats.CurrHealth}");
                return;
            }
            AttackTarget.Connection.SendMessage(AttackFailFlavor);
            AttackTarget.Connection.SendMessage($"Your current health is {AttackTarget.Player.Stats.CurrHealth}");
        }
 private void MoveUp()
 {
     if (SelectedCombatant.TieBreaker != 0)
     {
         var previousCombatant = Combatants.FirstOrDefault(c => c.TieBreaker == SelectedCombatant.TieBreaker - 1);
         previousCombatant.TieBreaker++;
         SelectedCombatant.TieBreaker--;
     }
     Combatants.Sort();
 }
 private void MoveDown()
 {
     if (SelectedCombatant.TieBreaker != Combatants.Count - 1)
     {
         var nextCombatant = Combatants.FirstOrDefault(c => c.TieBreaker == SelectedCombatant.TieBreaker + 1);
         nextCombatant.TieBreaker--;
         SelectedCombatant.TieBreaker++;
     }
     Combatants.Sort();
 }
Exemple #8
0
        }         // EndTurn()

        public static void VerifyStatus(int targetId, ApplicationDbContext ctx)
        {
            Creature target = Combatants.FirstOrDefault(x => x.Id == targetId);

            if (target.HitPoints < 1)
            {
                target.Alive = false;

                if (target.HitPoints < 0)
                {
                    target.HitPoints = 0;
                }

                AddToLog(new string($"W skutek odniesionych ran {target.Name} pada martwy."));
            }

            if (Hero.Alive == false)
            {
                AddToLog(new string($"To koniec podróży. Oczy {Hero.Name} już na zawsze pozostaną zamknięte. Inni zostaną wysłani, ale czy ktokolwiek odniesie sukces?"));
                GameplayManager.Phase = Enumerators.GamePhase.CharacterCreation;
                GameplayManager.Step  = 0;
                Status = false;
            }

            else
            {
                deadCount = 0;

                foreach (var creature in Enemies)
                {
                    if (creature.Alive == false)
                    {
                        deadCount++;
                    }
                }

                if (Enemies.Count == deadCount)
                {
                    int experience = 0;

                    foreach (var creature in Enemies)
                    {
                        experience += creature.Experience;
                    }

                    Hero.Experience += experience;

                    AddToLog(new string($"{Hero.Name} rozgromił wszystkich przeciwników, których resztki leżą rozrzucone na ziemii. Walka skończona."));
                    AddToLog(new string($"{Hero.Name} Zyskuje {experience} punktów doświadczenia."));

                    CheckLevel(ctx);
                }
            }
        }         // VerifyStatus()
 private void FateOf(Gladiator gladiator)
 {
     if (gladiator.IsAlive())
     {
         Combatants.Add(gladiator);
     }
     else
     {
         Graveyard.Add(gladiator);
     }
 }
Exemple #10
0
        private void Load()
        {
            Combatants.Clear();
            var eventArgs = new SaveEventArgs();

            LoadTriggered?.Invoke(this, eventArgs);
            foreach (Combatant combatant in eventArgs.SaveData)
            {
                Combatants.Add(combatant);
            }
            Combatants.Sort();
        }
        private void MoveDown_Click(object sender, RoutedEventArgs e)
        {
            if (Combatants.Count < 2)
            {
                return;
            }

            if (CombatantList.SelectedIndex >= Combatants.Count - 1)
            {
                return;
            }

            Combatants = (ObservableCollection <DD4ECombatant>)Combatants.MoveDown(CombatantList.SelectedIndex);
        }
 private void AddCombatant(DD4ECombatant combatant)
 {
     if (Combatants.Any(c => c.Name.Equals(combatant.Name) && c.IsPlayer == false))
     {
         int id = Combatants.Count(c => c.Name.Equals(combatant.Name) && c.IsPlayer == false);
         combatant.ID = id;
     }
     else
     {
         if (Combatants.Any(c => c.Name.Equals(combatant.Name)))
         {
             MessageBox.Show("You cannot add the same player character twice.", "Warning");
             return;
         }
     }
     Combatants.Add(combatant);
 }
Exemple #13
0
        private void Previous()
        {
            Combatant activeCombatant = Combatants.FirstOrDefault(c => c.IsActive);

            activeCombatant.IsActive = false;
            int index = Combatants.IndexOf(activeCombatant);

            if (index == 0)
            {
                index = Combatants.Count - 1;
            }
            else
            {
                index--;
            }
            Combatants[index].IsActive = true;
        }
Exemple #14
0
 public void Run(User current, Door run)
 {
     if (Combatants.Count > 1)
     {
         current.Connection.SendMessage("You cannot abandon your allies!");
         return;
     }
     if (run == null)
     {
         current.Connection.SendMessage("There is no escape!");
         return;
     }
     current.Connection.SendMessage($"You manage to escape {run.Direction}!");
     Combatants.Remove(current);
     current.Player.Combat = null;
     current.CurrRoomId    = run.RoomsIConnect[1];
 }
Exemple #15
0
        private void Next()
        {
            Combatant activeCombatant = Combatants.FirstOrDefault(c => c.IsActive);

            activeCombatant.IsActive = false;
            int index = Combatants.IndexOf(activeCombatant);

            if (index == Combatants.Count - 1)
            {
                index = 0;
            }
            else
            {
                index++;
            }
            Combatants[index].IsActive = true;
        }
Exemple #16
0
        }         // OrderOfBattle()

        public static void PrepareBattle(ApplicationDbContext ctx)
        {
            if (Status == false)
            {
                random = new Random();
                OrderOfBattle();
                BattleLog       = new List <string>();
                combatantsCount = Combatants.Count();
                combatantTurn   = 0;
                var first = Combatants.First();
                AddToLog(new string($"Walka rozpoczęta, jako pierwszy uderza {first.Name}"));
                deadCount = 0;
                Status    = true;
            }

            BattleTurn(ctx);
        }         // PrepareBattle()
Exemple #17
0
        }         // Attack()

        public static void UseItem(int userId, int itemId)
        {
            Creature     user = Combatants.SingleOrDefault(x => x.Id == userId);
            CreatureItem item = user.Items.SingleOrDefault(x => x.ItemId == itemId);

            if (item.Item.ItemType == Enumerators.ItemTypeEnum.Healing)
            {
                user.HitPoints += item.Item.Strength;

                if (user.HitPoints > user.MaxHP)
                {
                    user.HitPoints = user.MaxHP;
                }

                AddToLog(new string($"{user.Name} używa {item.Item.Name}, które przywraca {item.Item.Strength} punktów zdrowia."));
            }

            else if (item.Item.ItemType == Enumerators.ItemTypeEnum.Mana)
            {
                user.Mana += item.Item.Strength;

                if (user.Mana > user.MaxMana)
                {
                    user.Mana = user.MaxMana;
                }

                AddToLog(new string($"{user.Name} używa {item.Item.Name}, które przywraca {item.Item.Strength} punktów many."));
            }

            user.ActionPoints -= item.Item.ActionCost;

            if (item.Qty == 1)
            {
                user.Items.Remove(item);
            }

            else
            {
                item.Qty -= 1;
            }
        }         // UseItem()
        private void Maintenance(int fights)
        {
            var wounded = Combatants.Where(g => g.IsWounded());

            foreach (var g in wounded)
            {
                g.Heal(3);
            }

            //var victoryMax = Combatants.Max(c => c.Victories);

            //if ((new Random()).NextDouble() < 0.05 || Combatants.Count < 10)
            //{
            //    var numberToAdd = (new Random()).Next(0, 30);
            //    numberToAdd = Math.Min(numberToAdd, 1000 - Graveyard.Count - Combatants.Count);
            //    numberToAdd = Math.Max(0, numberToAdd);
            //    //View.Roster(Combatants, fights, Graveyard.Count);
            //    PopulateGladiatorList(numberToAdd);
            //    //View.Roster(Combatants, fights, Graveyard.Count);
            //}
        }
        private (Gladiator, Gladiator) PickPair()
        {
            var r = new Random();

            var eligible = EligibleToFight(Combatants);

            var first = eligible
                        .OrderBy(x => r.NextDouble())
                        .First();

            var second = eligible
                         .Where(g => g != first)
                         //.OrderBy(g => Math.Abs(g.Victories - first.Victories))
                         .OrderBy(x => r.NextDouble())
                         .First();

            Combatants.Remove(first);
            Combatants.Remove(second);

            return(first, second);
        }
Exemple #20
0
        private void Add()
        {
            int initiative;

            if (!int.TryParse(Initiative, out initiative))
            {
                throw new Exception($"{Initiative} is not a valid value.");
            }

            bool initiativeTied = Combatants.Any(c => c.Initiative == initiative);
            var  newCombatant   = new Combatant(Name, initiative, Combatants.Count == 0);

            Combatants.Add(newCombatant);
            if (initiativeTied && InitiativeTied != null)
            {
                newCombatant.TieBreaker = Combatants.Max(c => c.TieBreaker) + 1;
                InitiativeTied?.Invoke(this, new TieInitiativeEventArgs(Combatants.Where(c => c.Initiative == initiative)));
            }
            Combatants.Sort();
            Name       = null;
            Initiative = null;
        }
Exemple #21
0
        public Task AddCombatantAsync(GridEntity entity, ICombatant combatant, string factionKey = "")
        {
            List <IEntity> faction;

            if (entity.IsPlayer())
            {
                Dead.RemoveAll(d => d.Id == entity.Id);
            }

            // some default behaviour will be to find the faction with the matching isPlayer
            if (string.IsNullOrEmpty(factionKey))
            {
                var testFaction = Factions.FirstOrDefault(o => o.Value.Any(e => e.IsPlayer() == entity.IsPlayer()));
                if (testFaction.Value == null)
                {
                    testFaction = Factions.FirstOrDefault(o => o.Value.Count == 0);
                }
                if (testFaction.Value == null)
                {
                    testFaction = Factions.FirstOrDefault();
                }

                faction = testFaction.Value;
            }
            else
            {
                faction = Factions[factionKey];
            }
            if (faction != null)
            {
                faction.Add(entity);
            }

            Combatants.Add(entity, combatant);


            entity.Died += Combatant_Death;
            return(Task.CompletedTask);
        }
Exemple #22
0
 private void Reset()
 {
     Combatants.Clear();
     Name       = null;
     Initiative = null;
 }
Exemple #23
0
        }         // AddToLog()

        public static void Attack(int attackerId, int attackType, int targetId, ApplicationDbContext ctx)
        {
            //attackType 0 - fast, 1 - normal, 2 - strong

            int  chanceLevel = 0;
            bool HitSucces   = false;

            Creature attacker = Combatants.FirstOrDefault(x => x.Id == attackerId);

            if (random.Next(1, 100) == 50)
            {
                targetId = attackerId;

                AddToLog(new string($"{attacker.Name} chybia cel raniąc siebie."));
            }             // fail - 1% chance, the attacker hitting itself

            Creature target = Combatants.FirstOrDefault(x => x.Id == targetId);

            if (attackType == 0)
            {
                attacker.ActionPoints -= (attacker.Weapon.ActionCost - 1);
            }

            else if (attackType == 1)
            {
                attacker.ActionPoints -= attacker.Weapon.ActionCost;
            }

            else
            {
                attacker.ActionPoints -= (attacker.Weapon.ActionCost + 1);
            }

            #region Hit chance
            if (targetId != attackerId)
            {
                if (attackType == 0)
                {
                    chanceLevel = attacker.Weapon.HitChance + 10 + attacker.Agility - target.Agility;                     // +10 as fast attack is more likely to hit
                }

                else if (attackType == 1)
                {
                    chanceLevel = attacker.Weapon.HitChance + attacker.Agility - target.Agility;
                }

                else
                {
                    chanceLevel = attacker.Weapon.HitChance - 10 + attacker.Agility - target.Agility;                     // -10 as strong attack is less likely to hit
                }

                int calculateHit = random.Next(0, 100);

                if (calculateHit <= chanceLevel)
                {
                    HitSucces = true;
                }

                else
                {
                    HitSucces = false;
                    AddToLog($"{attacker.Name} chybia.");
                }
            }

            else
            {
                HitSucces = true;
            }

            #endregion

            #region  HitSucces true
            if (HitSucces == true)
            {
                double attackPower      = (double)attacker.Weapon.BaseDamage;
                double attackMagicPower = (double)attacker.Weapon.MagicDamage;
                double criticalSuccess  = 1;

                if (random.Next(1, 100) == 50)
                {
                    criticalSuccess = 2;
                }                 // 1% chance to deal double damage

                if (attackType == 0)
                {
                    if (attacker.Strength >= 4)
                    {
                        attackPower      *= (double)attacker.Strength / 4 * (random.NextDouble() * (0.8 - 0.65) + 0.65);
                        attackMagicPower *= (double)attacker.Strength / 4 * (random.NextDouble() * (0.8 - 0.65) + 0.65);
                    }

                    else
                    {
                        attackPower      *= 2 * random.NextDouble() * (0.8 - 0.65) + 0.65;
                        attackMagicPower *= 2 * random.NextDouble() * (0.8 - 0.65) + 0.65;
                    }
                }

                else if (attackType == 1)
                {
                    if (attacker.Strength >= 4)
                    {
                        attackPower      *= (double)attacker.Strength / 4 * (random.NextDouble() * (1.1 - 0.9) + 0.9);
                        attackMagicPower *= (double)attacker.Strength / 4 * (random.NextDouble() * (1.1 - 0.9) + 0.9);
                    }

                    else
                    {
                        attackPower      *= 2 * random.NextDouble() * (1.1 - 0.9) + 0.9;
                        attackMagicPower *= 2 * random.NextDouble() * (1.1 - 0.9) + 0.9;
                    }
                }

                else
                {
                    if (attacker.Strength >= 4)
                    {
                        attackPower      *= (double)attacker.Strength / 4 * (random.NextDouble() * (1.35 - 1.2) + 1.2);
                        attackMagicPower *= (double)attacker.Strength / 4 * (random.NextDouble() * (1.35 - 1.2) + 1.2);
                    }

                    else
                    {
                        attackPower      *= 2 * random.NextDouble() * (1.35 - 1.2) + 1.2;
                        attackMagicPower *= 2 * random.NextDouble() * (1.35 - 1.2) + 1.2;
                    }
                }

                double damage  = (attackPower * (100 / (100 + (double)target.DamageResistance)) - attackPower / 2) * criticalSuccess;
                double MDamage = (attackMagicPower * (100 / (100 + (double)target.MagicResistance)) - attackPower / 2) * criticalSuccess;

                int realDMG  = (int)Math.Round(damage);
                int realMDMG = (int)Math.Round(MDamage);

                if (criticalSuccess == 2)
                {
                    AddToLog(new string($"Cios jaki wyprowadza {attacker.Name} uderza ze zdwojoną siłą."));
                }

                if (realDMG > 0 && realMDMG > 0)
                {
                    target.HitPoints -= realDMG;
                    target.HitPoints -= realMDMG;
                    AddToLog(new string($"{attacker.Name} trafia {target.Name} zadając {realDMG} fizycznych i {realMDMG} magicznych puntków obrażeń."));
                }

                else if (realDMG > 0)
                {
                    target.HitPoints -= realDMG;
                    AddToLog(new string($"{attacker.Name} trafia {target.Name} zadając {realDMG} puntków obrażeń."));
                }

                else if (realMDMG > 0)
                {
                    target.HitPoints -= realMDMG;
                    AddToLog(new string($"{attacker.Name} trafia {target.Name} zadając {realMDMG} magicznych puntków obrażeń."));
                }

                VerifyStatus(targetId, ctx);
            }     // HitSucces true
            #endregion
        }         // Attack()
Exemple #24
0
        /// <summary>
        /// Resolves the battle.
        /// </summary>
        public void Resolve()
        {
            // update memories
            foreach (var sobj in StarSystem.SpaceObjects.Where(x => !x.IsMemory).ToArray())
            {
                sobj.UpdateEmpireMemories();
            }

            Current.Add(this);
            var reloads = new SafeDictionary <Component, double>();
            var seekers = new Dictionary <Seeker, int>();

            // let all combatants scan each other
            foreach (var c in Combatants)
            {
                c.UpdateEmpireMemories();
            }

            for (int i = 0; i < Mod.Current.Settings.SpaceCombatTurns; i++)
            {
                LogRound(i + 1);
                // TODO - real 2D combat mechanics
                foreach (var seeker in seekers.Keys.ToArray())
                {
                    seekers[seeker]--;
                    if (seekers[seeker] <= 0)
                    {
                        seekers.Remove(seeker);
                        var minrng = seeker.LaunchingComponent.Template.WeaponMinRange;
                        var maxrng = seeker.LaunchingComponent.Template.WeaponMinRange;
                        var range  = Dice.Next(maxrng - minrng) + minrng;                        // just pick a random valid range
                        var shot   = new Shot(seeker.LaunchingCombatant, seeker.LaunchingComponent, seeker.Target, range);
                        Log.Add(seeker.CreateLogMessage(seeker + " detonates! " + seeker.Target + " takes " + shot.FullDamage + " damage."));
                        seeker.Target.TakeDamage(new Hit(shot, seeker.Target, seeker.Damage.Value));
                    }
                    else
                    {
                        Log.Add(seeker.CreateLogMessage(seeker + " moves closer to " + seeker.Target + " (" + seekers[seeker] + " rounds to detonation)"));
                    }
                }
                foreach (var launcher in Combatants.ToArray())
                {
                    // find launchable units
                    var unitsToLaunch = new List <SpaceVehicle>();
                    if (launcher is Planet)
                    {
                        // planets can launch infinite units per turn
                        var p = (Planet)launcher;
                        if (p.Cargo != null && p.Cargo.Units != null)
                        {
                            unitsToLaunch.AddRange(p.Cargo.Units.OfType <SpaceVehicle>());
                        }
                    }
                    else if (launcher is ICargoTransferrer)
                    {
                        // ships, etc. can launch units based on abilities
                        var ct = (ICargoTransferrer)launcher;
                        foreach (var vt in Enum.GetValues(typeof(VehicleTypes)).Cast <VehicleTypes>().Distinct())
                        {
                            var rate = ct.GetAbilityValue("Launch/Recover " + vt.ToSpacedString() + "s").ToInt();
                            unitsToLaunch.AddRange(ct.Cargo.Units.Where(u => u.Design.VehicleType == vt).OfType <SpaceVehicle>().Take(rate));
                        }
                    }

                    // launch them temporarily for combat
                    foreach (var unit in unitsToLaunch)
                    {
                        Combatants.Add(unit);
                    }
                }
                foreach (var attacker in Combatants.Shuffle(Dice).Where(sobj => sobj.Weapons.Any()).ToArray())
                {
                    if (!attacker.IsAlive)
                    {
                        continue;
                    }

                    var defenders = Combatants.Where(sobj => attacker.CanTarget(sobj) && sobj.IsAlive);
                    if (!defenders.Any())
                    {
                        continue;                         // no one to shoot at
                    }
                    var defender = defenders.PickRandom(Dice);

                    int dmg = 0;
                    foreach (var weapon in attacker.Weapons.Where(w => w.CanTarget(defender)))
                    {
                        while (reloads[weapon] <= 0)
                        {
                            // fire
                            var winfo = weapon.Template.ComponentTemplate.WeaponInfo;
                            if (winfo is SeekingWeaponInfo)
                            {
                                // launch a seeker
                                var swinfo = (SeekingWeaponInfo)winfo;
                                var seeker = new Seeker(this, attacker.Owner, attacker, weapon, defender);
                                seekers.Add(seeker, 20 / swinfo.SeekerSpeed);
                                LogLaunch(seeker);
                            }
                            else
                            {
                                // direct fire
                                var minrng = weapon.Template.WeaponMinRange;
                                var maxrng = weapon.Template.WeaponMinRange;
                                var range  = Dice.Next(maxrng - minrng) + minrng;                                // just pick a random valid range
                                var shot   = new Shot(attacker, weapon, defender, range);
                                dmg += shot.FullDamage;
                                defender.TakeDamage(new Hit(shot, defender, weapon.Template.GetWeaponDamage(range)));
                            }
                            // TODO - mounts that affect reload rate?
                            reloads[weapon] += weapon.Template.ComponentTemplate.WeaponInfo.ReloadRate;
                        }

                        // reload
                        reloads[weapon] -= 1;
                    }
                    LogSalvo(attacker, defender, dmg);
                }
            }

            // validate fleets since some ships might have died
            foreach (var fleet in Sector.SpaceObjects.OfType <Fleet>())
            {
                fleet.Validate();
            }

            // replenish combatants' shields
            foreach (var combatant in Sector.SpaceObjects.OfType <ICombatant>())
            {
                combatant.ReplenishShields();
            }

            // mark battle complete
            Current.Remove(this);
            Previous.Add(this);

            // update memories
            foreach (var sobj in Combatants.OfType <ISpaceObject>().Where(x => !x.IsMemory).ToArray())
            {
                foreach (var emp in Empires)
                {
                    emp.UpdateMemory(sobj);;
                }
            }
        }
Exemple #25
0
        }         // UseItem()

        public static void CastSpell(int userId, int targetId, int spellId, ApplicationDbContext ctx)
        {
            Creature user = Combatants.SingleOrDefault(x => x.Id == userId);
            Creature target;
            Spell    spell = new GetSpell(ctx).Get(spellId);

            user.Mana         -= spell.ManaCost;
            user.ActionPoints -= spell.ActionCost;

            if ((spell.Level * 10) >= random.Next(1, 100))
            {
                int selfharm;
                selfharm        = (int)Math.Round((double)(spell.Strength / 4));
                user.HitPoints -= selfharm;

                if (spell.Type == Enumerators.SpellTypeEnum.Healing)
                {
                    AddToLog(new string($"Zaklęcie {spell.Name} wymyka się spod kontoli i {user.Name} zamiast uleczyć rani się tracąc {selfharm} punktów życia."));
                }

                else
                {
                    AddToLog(new string($"Zaklęcie {spell.Name} wymyka się spod kontoli i {user.Name} zamiast trafić w przeciwnika rani siebie tracąc {selfharm} punktów życia."));
                }
            }             /// higher spell level means higher chance for failure and % of dmg done to the caster 0 - 0% , 10 - 10%

            else
            {
                if (userId != targetId)
                {
                    target = Combatants.SingleOrDefault(x => x.Id == targetId);
                }

                else
                {
                    target = user;
                }

                if (spell.Type == Enumerators.SpellTypeEnum.Healing)
                {
                    user.HitPoints += spell.Strength;

                    if (user.HitPoints > user.MaxHP)
                    {
                        user.HitPoints = user.MaxHP;
                    }

                    AddToLog(new string($"{user.Name} rzuca {spell.Name}, które przywraca {spell.Strength} punktów zdrowia."));
                }

                else
                {
                    if (random.Next(0, 100) < target.Willpower)
                    {
                        AddToLog(new string($"{target.Name} dzięki sile woli odrzuca zaklęcie wychodząc z ataku bez szwanku."));
                    }

                    else
                    {
                        int damage = (int)Math.Round((double)(spell.Strength * (100 / (100 + (double)target.MagicResistance))));

                        if (damage > 0)
                        {
                            target.HitPoints -= damage;
                        }

                        AddToLog(new string($"{user.Name} rzuca {spell.Name}, które trafia {target.Name} zadając mu {damage} punktów obrażeń."));
                    }
                }

                VerifyStatus(targetId, ctx);
            }
        }         // CastSpell()
Exemple #26
0
        /// <summary>
        /// Resolves the battle.
        /// </summary>
        public void Resolve()
        {
            // update memories
            foreach (var sobj in StarSystem.SpaceObjects.Where(x => !x.IsMemory).ToArray())
            {
                sobj.UpdateEmpireMemories();
            }

            Current.Add(this);

            var reloads   = new SafeDictionary <Component, double>();
            var locations = new SafeDictionary <ICombatant, IntVector2>();

            PlaceCombatants(locations);

            Events = new List <IList <IBattleEvent> >();

            UpdateBounds(0, locations.Values);

            // let all combatants scan each other
            foreach (var c in Combatants)
            {
                c.UpdateEmpireMemories();
            }

            // make a query so we can check who's alive
            var alives = Combatants.Where(q => q.IsAlive);

            for (int i = 0; i < MaxRounds; i++)
            {
                var combatSpeeds = new SafeDictionary <ICombatant, double>();
                var multiplex    = new SafeDictionary <ICombatant, HashSet <ICombatant> >(true);
                foreach (var c in Combatants)
                {
                    combatSpeeds[c] = c.CombatSpeed;
                }

                int GetCombatSpeedThisRound(ICombatant c)
                {
                    return((int)(combatSpeeds[c] + CombatSpeedBuffer[c]));
                }

                Events.Add(new List <IBattleEvent>());

                if (i == 0)
                {
                    // first round, all combatants appear
                    foreach (var c in Combatants)
                    {
                        Events.Last().Add(new CombatantAppearsEvent(this, c, locations[c]));
                    }
                }

                var turnorder = alives.OrderBy(x => x is Seeker ? 1 : 0).ThenBy(x => combatSpeeds[x]).ThenShuffle(Dice).ToArray();

                // phase 0: reload weapons
                foreach (var w in turnorder.SelectMany(q => q.Weapons))
                {
                    reloads[w]--;
                    if (reloads[w] < 0)
                    {
                        reloads[w] = 0;
                    }
                }

                // phase 1: combatants move starting with the slowest (so the faster ships get to react to their moves) - but seekers go last so they get a chance to hit
                foreach (var c in turnorder)
                {
                    var oldpos = locations[c];
                    if (c is Seeker s)
                    {
                        if (locations[s] == null)
                        {
                            continue;                             // HACK - seeker is destroyed but still showing up in turn order
                        }
                        if (locations[s.Target] == null)
                        {
                            s.Hitpoints = 0;                             // seekers self destruct when their target is destroyed
                            Events.Last().Add(new CombatantDestroyedEvent(this, s, locations[s]));
                            continue;
                        }
                        s.DistanceTraveled += Math.Min(GetCombatSpeedThisRound(c), locations[s].DistanceToEightWay(locations[s.Target]));
                        locations[s]        = IntVector2.InterpolateEightWay(locations[s], locations[s.Target], GetCombatSpeedThisRound(c));
                        if (s.DistanceTraveled > s.WeaponInfo.MaxRange)
                        {
                            s.Hitpoints = 0;
                            Events.Last().Add(new CombatantDestroyedEvent(this, s, locations[s]));
                        }
                    }
                    else
                    {
                        // TODO - both pursue target and evade scary enemies at the same time using heatmap
                        // find out how good each target is
                        var targetiness = new SafeDictionary <ICombatant, double>();
                        foreach (var target in alives.Where(x =>
                                                            c.IsHostileTo(x.Owner) &&
                                                            (c.CanTarget(x) || (x is Planet && c is ICargoContainer cc && cc.Cargo.Units.OfType <Troop>().Any()))))
                        {
                            targetiness[target] = 1d / (locations[target] - locations[c]).LengthEightWay;
                        }

                        if (!targetiness.Any())
                        {
                            // evade enemies
                            var heatmap = new HeatMap();
                            foreach (var e in alives.Where(x => x.IsHostileTo(c.Owner) && x.CanTarget(c)))
                            {
                                int threat;
                                if (e.Weapons.Any())
                                {
                                    threat = GetCombatSpeedThisRound(e) + e.Weapons.Where(w => w.CanTarget(c)).Max(w => w.Template.WeaponMaxRange);
                                }
                                else
                                {
                                    threat = 0;
                                }
                                heatmap.AddLinearGradientEightWay(locations[e], threat, threat, -1);
                            }
                            if (c.FillsCombatTile)
                            {
                                // only one ship/base/planet per tile
                                foreach (var tile in heatmap.ToArray())
                                {
                                    if (locations.Any(q => q.Key.FillsCombatTile && q.Value == tile.Key))
                                    {
                                        heatmap.Remove(tile.Key);
                                    }
                                }
                            }
                            if (heatmap.Any())
                            {
                                locations[c] = heatmap.FindMin(locations[c], GetCombatSpeedThisRound(c));
                            }
                        }
                        else
                        {
                            // move to max range that we can inflict max damage on best target
                            var        goodTargets = targetiness.Where(x => !IgnoredTargets[c].Contains(x.Key)).WithMax(x => x.Value);
                            ICombatant bestTarget  = null;
                            if (goodTargets.Any())
                            {
                                bestTarget = goodTargets.First().Key;
                            }
                            if (bestTarget == null)
                            {
                                // try previously ignored targets
                                IgnoredTargets[c].Clear();
                                goodTargets = targetiness.Where(x => !IgnoredTargets[c].Contains(x.Key)).WithMax(x => x.Value);
                                if (goodTargets.Any())
                                {
                                    bestTarget = goodTargets.First().Key;
                                }
                            }
                            if (bestTarget != null)
                            {
gotosAreEvil:
                                var maxdmg = 0;
                                var maxdmgrange = 0;
                                if (c.Weapons.Any())
                                {
                                    for (var range = 0; range < c.Weapons.Max(w => w.Template.WeaponMaxRange); range++)
                                    {
                                        var dmg = c.Weapons.Where(w => w.CanTarget(bestTarget)).Sum(w => w.Template.GetWeaponDamage(range));
                                        if (dmg >= maxdmg)
                                        {
                                            maxdmg      = dmg;
                                            maxdmgrange = range;
                                        }
                                    }
                                }
                                if (c.Weapons.Any(w => w.Template.ComponentTemplate.WeaponInfo.IsSeeker) &&
                                    locations[c].DistanceToEightWay(locations[bestTarget]) > DistancesToTargets[c])
                                {
                                    // adjust desired range due to seeker speed and target speed if retreating
                                    var roundsToClose = c.Weapons.Where(w => w.Template.ComponentTemplate.WeaponInfo.IsSeeker).Max(w =>
                                                                                                                                   (int)Math.Ceiling((double)w.Template.WeaponMaxRange / (double)(w.Template.ComponentTemplate.WeaponInfo as SeekingWeaponInfo).SeekerSpeed));
                                    var distanceAdjustment = (int)Ceiling(combatSpeeds[bestTarget] * roundsToClose);
                                    maxdmgrange -= distanceAdjustment;
                                    if (maxdmgrange < 0)
                                    {
                                        maxdmgrange = 0;
                                    }
                                }
                                var targetPos = locations[bestTarget];
                                var tiles     = new HashSet <IntVector2>();
                                for (var x = targetPos.X - maxdmgrange; x <= targetPos.X + maxdmgrange; x++)
                                {
                                    tiles.Add(new IntVector2(x, targetPos.Y - maxdmgrange));
                                    tiles.Add(new IntVector2(x, targetPos.Y + maxdmgrange));
                                }
                                for (var y = targetPos.Y - maxdmgrange; y <= targetPos.Y + maxdmgrange; y++)
                                {
                                    tiles.Add(new IntVector2(targetPos.X - maxdmgrange, y));
                                    tiles.Add(new IntVector2(targetPos.X + maxdmgrange, y));
                                }
                                if (c.FillsCombatTile)
                                {
                                    foreach (var tile in tiles.ToArray())
                                    {
                                        if (locations.Any(q => q.Key.FillsCombatTile && q.Value == tile))
                                        {
                                            tiles.Remove(tile);
                                        }
                                    }
                                }
                                if (tiles.Any())
                                {
                                    var closest = tiles.WithMin(t => t.DistanceToEightWay(locations[c])).First();
                                    locations[c] = IntVector2.InterpolateEightWay(locations[c], closest, GetCombatSpeedThisRound(c), vec => locations.Values.Contains(vec));
                                    var newdist = locations[c].DistanceToEightWay(locations[bestTarget]);
                                    if (DistancesToTargets.ContainsKey(c) && newdist >= DistancesToTargets[c] && combatSpeeds[c] <= combatSpeeds[bestTarget] && !c.Weapons.Any(w => w.Template.WeaponMaxRange >= newdist))
                                    {
                                        DistancesToTargets.Remove(c);
                                        IgnoredTargets[c].Add(bestTarget);                                         // can't catch it, might as well find a new target
                                        goodTargets = targetiness.Where(x => !IgnoredTargets[c].Contains(x.Key)).WithMax(x => x.Value);
                                        bestTarget  = null;
                                        if (goodTargets.Any())
                                        {
                                            bestTarget = goodTargets.First().Key;
                                        }
                                        if (bestTarget == null)
                                        {
                                            goto gotosAreVeryEvil;
                                        }
                                        goto gotosAreEvil;
                                    }
                                    else
                                    {
                                        DistancesToTargets[c] = newdist;
                                    }
                                }
                            }
                            else
                            {
                                DistancesToTargets.Remove(c);
                            }
                        }
                    }
gotosAreVeryEvil:
                    if (locations[c] != oldpos)
                    {
                        Events.Last().Add(new CombatantMovesEvent(this, c, oldpos, locations[c]));
                    }
                }

                UpdateBounds(i, locations.Values);

                // phase 2: combatants launch units
                foreach (var c in turnorder)
                {
                    // find launchable units
                    var unitsToLaunch = new List <(ICombatant Launcher, SpaceVehicle Launchee)>();
                    if (c is Planet)
                    {
                        // planets can launch infinite units per turn
                        var p = (Planet)c;
                        if (p.Cargo != null && p.Cargo.Units != null)
                        {
                            foreach (var u in p.Cargo.Units.OfType <SpaceVehicle>())
                            {
                                unitsToLaunch.Add((p, u));
                            }
                        }
                    }
                    else if (c is ICargoTransferrer)
                    {
                        // ships, etc. can launch units based on abilities
                        var ct = (ICargoTransferrer)c;
                        foreach (var vt in Enum.GetValues(typeof(VehicleTypes)).Cast <VehicleTypes>().Distinct())
                        {
                            var rate = ct.GetAbilityValue("Launch/Recover " + vt.ToSpacedString() + "s").ToInt();
                            foreach (var u in ct.Cargo.Units.Where(u => u.Design.VehicleType == vt).OfType <SpaceVehicle>().Take(rate))
                            {
                                unitsToLaunch.Add((c, u));
                            }
                        }
                    }

                    // launch them temporarily for combat
                    foreach (var info in unitsToLaunch)
                    {
                        Launchers[info.Launchee] = info.Launcher;
                        if (info.Launcher is ICargoTransferrer ct && info.Launchee is IUnit u)
                        {
                            ct.RemoveUnit(u);
                        }

                        Combatants.Add(info.Item2);
                        StartCombatants[info.Item2.ID] = info.Item2.Copy();
                        for (var ix = 0; ix < info.Item2.Weapons.Count(); ix++)
                        {
                            var w  = info.Item2.Weapons.ElementAt(ix);
                            var wc = StartCombatants[info.Item2.ID].Weapons.ElementAt(ix);
                        }
                        locations[info.Launchee] = new IntVector2(locations[info.Launcher]);
                        Events.Last().Add(new CombatantLaunchedEvent(this, info.Launcher, info.Launchee, locations[info.Launchee]));
                    }
                }

                turnorder = alives.OrderBy(x => x.CombatSpeed).ThenShuffle(Dice).ToArray();

                // phase 3: combatants fire point defense non-warhead weapons starting with the fastest (so the faster ships get to inflict damage first and possibly KO enemies preventing them from firing back)
                foreach (var c in turnorder.Reverse())
                {
                    foreach (var w in c.Weapons.Where(w => w.Template.ComponentTemplate.WeaponInfo.IsPointDefense && !w.Template.ComponentTemplate.WeaponInfo.IsWarhead))
                    {
                        TryFireWeapon(c, w, reloads, locations, multiplex);
                    }
                }

                turnorder = alives.OrderBy(x => x.CombatSpeed).ThenShuffle(Dice).ToArray();

                // phase 4: point defense seekers detonate
                foreach (var s in turnorder.Reverse().OfType <Seeker>().Where(s => s.WeaponInfo.IsPointDefense))
                {
                    CheckSeekerDetonation(s, locations);
                }

                turnorder = alives.OrderBy(x => x.CombatSpeed).ThenShuffle(Dice).ToArray();

                // phase 5: ships fire non-PD non-warhead weapons starting with the fastest (so the faster ships get to inflict damage first and possibly KO enemies preventing them from firing back)
                foreach (var c in turnorder.Reverse())
                {
                    foreach (var w in c.Weapons.Where(w => !w.Template.ComponentTemplate.WeaponInfo.IsPointDefense && !w.Template.ComponentTemplate.WeaponInfo.IsWarhead))
                    {
                        TryFireWeapon(c, w, reloads, locations, multiplex);
                    }
                }

                turnorder = alives.OrderBy(x => x.CombatSpeed).ThenShuffle(Dice).ToArray();

                // phase 6: non-PD seekers detonate
                foreach (var s in turnorder.Reverse().OfType <Seeker>().Where(s => !s.WeaponInfo.IsPointDefense))
                {
                    CheckSeekerDetonation(s, locations);
                }

                turnorder = alives.OrderBy(x => x.CombatSpeed).ThenShuffle(Dice).ToArray();

                // phase 7: ramming! only activates if ship has no other weapons
                foreach (var c in turnorder.Reverse())
                {
                    if (!c.Weapons.Any(w => !w.Template.ComponentTemplate.WeaponInfo.IsWarhead))
                    {
                        // TODO - add damage from ship HP on both sides
                        foreach (var w in c.Weapons.Where(w => w.Template.ComponentTemplate.WeaponInfo.IsWarhead))
                        {
                            TryFireWeapon(c, w, reloads, locations, multiplex);
                        }
                    }
                }

                turnorder = alives.OrderBy(x => x.CombatSpeed).ThenShuffle(Dice).ToArray();

                // TODO - boarding

                // phase 8: drop troops
                foreach (var c in turnorder.Reverse())
                {
                    if (c is ICargoTransferrer cc && cc.AllUnits.OfType <Troop>().Any())
                    {
                        // find enemy planets in the same square
                        var dropTargets = locations.Where(q => q.Key != c && q.Value == locations[c] && q.Key is Planet p && c.IsHostileTo(p.Owner)).Select(q => q.Key).Cast <Planet>();
                        var dropTarget  = dropTargets.PickRandom(Dice);
                        if (dropTarget != null)
                        {
                            var cd = new CargoDelta();
                            cd.UnitTypeTonnage.Add(VehicleTypes.Troop, null);
                            cc.TransferCargo(cd, dropTarget, cc.Owner, true);
                            var groundBattle = new GroundBattle(dropTarget);
                            groundBattle.Resolve();
                        }
                    }
                }

                // clear used combat speed buffer speed
                foreach (var x in Combatants)
                {
                    CombatSpeedBuffer[x] += x.CombatSpeed - Floor(x.CombatSpeed);
                    CombatSpeedBuffer[x] -= Floor(CombatSpeedBuffer[x]);
                }

                UpdateBounds(i, locations.Values);

                bool hostile = false;
                foreach (var a in alives)
                {
                    foreach (var b in alives)
                    {
                        // TODO - check if ships want to ram even if they have no weapons
                        if (a.IsHostileTo(b.Owner) && a.Weapons.Any())
                        {
                            hostile = true;
                            break;
                        }
                    }
                    if (hostile)
                    {
                        break;
                    }
                }
                if (!hostile)
                {
                    break;
                }
            }

            // recover units
            var orphans = new List <IUnit>();

            foreach (var u in Combatants.OfType <IUnit>())
            {
                if (Launchers[u] is ICargoTransferrer cc && cc.CargoStorageFree() >= u.Design.Hull.Size && u.Owner == cc.Owner)
                {
                    cc.Cargo.Units.Add(u);
                }
Exemple #27
0
        private void ACTExtension(bool isImport, LogLineEventArgs e)
        {
            string[]    data        = e.logLine.Split('|');
            MessageType messageType = (MessageType)Convert.ToInt32(data[0]);

            switch (messageType)
            {
            case MessageType.LogLine:
                if (Convert.ToInt32(data[2], 16) == 56)
                {
                    ReadFFxivEcho(data[4]);
                }
                break;

            case MessageType.ChangeZone:
                ChangeZoneEvent(data);
                break;

            case MessageType.ChangePrimaryPlayer:
                DetectMyName(data);
                break;

            case MessageType.AddCombatant:
                if (!Combatants.ContainsKey(data[2]))
                {
                    CombatData cd = new CombatData();
                    cd.PlayerID   = Convert.ToUInt32(data[2], 16);
                    cd.PlayerJob  = Convert.ToUInt32(data[4], 16);
                    cd.PlayerName = data[3];
                    cd.MaxHP      = cd.CurrentHP = Convert.ToInt64(data[5], 16);
                    cd.MaxMP      = cd.CurrentMP = Convert.ToInt64(data[6], 16);
                    if (data[8] != "0")
                    {
                        cd.IsPet   = true;
                        cd.OwnerID = Convert.ToUInt32(data[8]);
                    }
                    Combatants.Add(data[2], cd);
                    SendCombatantList();
                }
                break;

            case MessageType.RemoveCombatant:
                if (Combatants.ContainsKey(data[2]))
                {
                    Combatants.Remove(data[2]);
                    SendCombatantList();
                }
                break;

            case MessageType.PartyList:
                UpdatePartyList(data);
                break;

            case MessageType.NetworkStartsCasting:
            case MessageType.NetworkCancelAbility:
            case MessageType.NetworkDoT:
            case MessageType.NetworkDeath:
            case MessageType.NetworkBuff:
            case MessageType.NetworkTargetIcon:
            case MessageType.NetworkRaidMarker:
            case MessageType.NetworkTargetMarker:
            case MessageType.NetworkBuffRemove:
                break;

            case MessageType.NetworkAbility:
            case MessageType.NetworkAOEAbility:
                Ability(messageType, data);
                break;
            }
        }