Exemple #1
0
        private void World_AvatarKilledAvatar(IAvatar attacker, IAvatar defender)
        {
            int    index = Dice.Random(0, VictoryMessages.Length - 1);
            string msg   = String.Format(VictoryMessages[index], attacker.AUpper(), defender.A());

            Game.UpdateTwitter(Strings.EnsureProperSentence(msg));
        }
Exemple #2
0
        /// <summary>
        /// Performs a cast of a spell from the caster onto the target Actor instance.
        /// </summary>
        /// <param name="spell">The spell being cast.</param>
        /// <param name="caster">The avatar casting the spell.</param>
        /// <param name="target">The target Actor instance, avatar or item.</param>
        /// <returns>The results of the casting.</returns>
        public static CastResults PerformCast(
            ISpell spell,
            IAvatar caster,
            IActor target)
        {
            CastResults results = new CastResults();

            // Used for sending messages to the defender's Context.
            IAvatar defender = target as IAvatar;

            // Ensure that the spell can be cast on the target.
            if (Object.ReferenceEquals(caster, target))
            {
                if (spell.IsDamageSpell)
                {
                    caster.Context.Add(new RdlErrorMessage(SR.CastNotSelf));
                    return(results);
                }
            }

            // To determine the effect’s difficulty rating, all foci scores are added together.
            int difficulty = spell.Foci.GetDifficulty();

            //The sphere or discipline skill test is then made vs. Intelligence, opposed by the opposing successes of the difficulty
            //rating roll (see Section 1.2.1). If no successes are remain, then the effect fails and the character burns no mind.
            //If a disastrous failure is rolled, the character takes the effect himself (if it’s offensive), it has its opposite effect, or
            //whatever the GM decides; the character also burns extra mind equal to the extent of the critical failure (if two 10s
            //were rolled on 2d10, the character would eat the effect and burn 2 extra mind).
            //Note that offensive effects with no area foci require a successful combat roll to strike the target, on the sphere or
            //discipline skill in the case of ranged attacks, or on an unarmed combat (or similar) skill in the case of touch effects.
            //Called shots can be made as in normal combat.
            //The defender may be allowed a Dodge roll for defense against being hit by some effects. Generally, if the attacker
            //must make a perception or dexterity roll to hit, the defender will probably be allowed a Dodge roll.
            int casterSuccessCount;

            SkillManager.PerformSkillTest(caster, spell.Skill, AttributeType.Intelligence, difficulty, spell.SkillLevelRequiredToEquip, true, out casterSuccessCount);

            // Raise the OnCastSkillRoll event to determine if the success roll should be overwritten.
            caster.OnCastSkillRoll(spell, ref casterSuccessCount);

            results.CastSuccessCount = casterSuccessCount;

            //Producing an effect, if successful, burns Mind. The amount of Mind burned is equal to the effect’s difficulty
            //minus the number of effective successes rolled (that is, what successes are left after the opposing successes are taken
            //into account), for a minimum of zero.
            int mindValueUsed = (difficulty - casterSuccessCount);

            if (mindValueUsed <= 0)
            {
                mindValueUsed = 1;
            }

            // Caster needs to the required amount of mind value.
            if (caster.Mind < mindValueUsed)
            {
                caster.Context.Add(new RdlErrorMessage("You do not have the required Willpower to cast this spell."));
                return(results);
            }

            if (casterSuccessCount < 0 && spell.IsDamageSpell)
            {
                // Disatrous failure, spell backfires!
                caster.SetMind(caster.Mind - mindValueUsed);
                caster.SetMind(caster.Mind + casterSuccessCount);

                // Apply damage to the caster.
                caster.SetBody(caster.Body - spell.Foci.Power);

                caster.Context.Add(new RdlErrorMessage(SR.CastBackfired));

                if (caster.IsDead)
                {
                    results.CasterDied = true;
                    caster.Context.Add(new RdlErrorMessage(SR.CastBackfiredKilledCaster));
                }
                else if (caster.IsUnconscious)
                {
                    results.CasterUnconscious = true;
                    caster.Context.Add(new RdlErrorMessage(SR.CastBackfiredUnconsciousCaster));
                }
            }
            else if (casterSuccessCount > 0)
            {
                results.CastSuccessful = true;

                // Spell successful.
                caster.SetMind(caster.Mind - mindValueUsed);

                // Inform the caster of the successful cast.
                //caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Positive,
                //    SR.CastSuccess(spell.Name, target.A())));

                spell.Cast(caster, target, results);

                caster.OnCastSuccess(spell);

                // Handle death messages.
                if (defender.IsDead)
                {
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            SR.AttackYouKilledDefender(defender.The())));
                    defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative,
                                                              SR.AttackYouWereKilledByAttacker(caster.The())));
                }
                else if (defender.IsUnconscious)
                {
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            SR.AttackUnconsciousDefender(defender.TheUpper())));
                    defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative,
                                                              SR.AttackYouAreUnconscious));
                }

                // Send down both the body and mind values of both the caster and the target to both the
                // caster and the target.
                RdlTag[] casterTags   = caster.GetRdlProperties(Avatar.BodyProperty, Avatar.MindProperty);
                RdlTag[] defenderTags = null;
                if (defender != null)
                {
                    defenderTags = defender.GetRdlProperties(Avatar.BodyProperty, Avatar.MindProperty);
                }

                caster.Context.AddRange(casterTags);
                if (defenderTags != null)
                {
                    caster.Context.AddRange(defenderTags);
                }

                if (defender != null)
                {
                    defender.Context.AddRange(defenderTags);
                    defender.Context.AddRange(casterTags);
                }
            }
            else
            {
                // Missed.
                caster.Context.Add(new RdlErrorMessage(SR.CastFailed));
                if (defender != null)
                {
                    defender.Context.Add(new RdlErrorMessage(SR.CasterCastFailed(caster.A())));
                }
            }

            //If an effect burns more mind than the character has available, then any overflow causes wounds. This is called
            //channeling, and can be done even when the caster has zero mind. If a character channels to below 0 body, his life
            //begins seeping away (treat it as any other wound below zero), and he must be magically or psionically healed or he
            //will die when he passes his negative physical endurance.
            if (caster.Mind < 0)
            {
                int channelingDamage = caster.Mind;
                caster.SetMind(0);
                caster.SetBody(caster.Body - channelingDamage);
                caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative, SR.CastChanneling));
            }

            // Regardless of outcome advance both the caster and target skills.
            SkillManager.AdvanceSkill(caster, spell.Skill, spell.SkillLevelRequiredToEquip, caster.Context);

            // NOTE: Do not have resist skills...
            //if (defender != null)
            //{
            //    // Use attackerWeapon as the required skill level so the defender can not elevate beyond the skill used
            //    // for the attack.
            //    SkillManager.AdvanceSkill(defender, defensiveSkill, spell.SkillLevelRequiredToEquip, defender.Context);
            //}

            return(results);
        }
Exemple #3
0
        public override void Cast(IAvatar caster, IActor target, CastResults results)
        {
            IAvatar defender = target as IAvatar;

            // TODO: Defense against spells?
            int power = this.Foci.Power + results.CastSuccessCount;

            target.SetBody(target.Body - power);

            caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                    String.Format(Resources.SpellDamagedTarget, target.A(), power)));
            if (defender != null)
            {
                defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative,
                                                          String.Format(Resources.SpellDamagedByTarget, power, caster.A())));
            }
            if (defender != null)
            {
                defender.Context.AddRange(defender.GetRdlProperties(Avatar.BodyProperty));
            }

            if (target.IsDead)
            {
                results.TargetDied = true;
                if (defender != null)
                {
                    // Killed an Avatar.
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            String.Format(Resources.SpellKilledTarget, target.A())));
                    defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative,
                                                              String.Format(Resources.SpellKilledByTarget, caster.A())));
                }
                else
                {
                    // Destroyed an object.
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            String.Format(Resources.SpellDestroyedTraget, target.A())));
                }
            }
            else if (defender != null && defender.IsUnconscious)
            {
                results.TargetUnconscious = true;
                caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                        String.Format(Resources.SpellUnconsciousTarget, target.A())));
                if (defender != null)
                {
                    defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative,
                                                              String.Format(Resources.SpellUnconsciousByTarget, caster.A())));
                }
            }
        }
Exemple #4
0
        public override void Cast(IAvatar caster, IActor target, CastResults results)
        {
            IAvatar defender = target as IAvatar;

            if (defender != null)
            {
                if (defender is PerenthiaMobile)
                {
                    defender = caster;
                }

                int power = this.Foci.Power + results.CastSuccessCount;
                defender.Attributes.ApplyAffect(this.StatName, power, this.Foci.Duration);
                defender.Context.AddRange(defender.Affects.ToRdl());
                if (Object.ReferenceEquals(caster, defender))
                {
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            String.Format(Resources.SpellStatGained, this.StatName, power)));
                }
                else
                {
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            String.Format(Resources.SpellStatGainedTarget, this.StatName, defender.A(), power)));
                    defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                              String.Format(Resources.SpellStatGainedByTarget, caster.A(), this.StatName, power)));
                    defender.Context.AddRange(defender.Attributes.ToRdl());
                }
            }
            else
            {
                this.NoAffect(caster);
            }
        }
Exemple #5
0
        public override void Cast(IAvatar caster, IActor target, CastResults results)
        {
            IAvatar defender = target as IAvatar;

            // Do not heal creatures or NPCs
            if (defender is Creature || defender is Npc)
            {
                target   = caster;
                defender = caster;
            }

            // Heal the mind value of the target.
            if (defender != null)
            {
                if (defender.Mind == defender.MindMax)
                {
                    this.NoAffect(caster);
                    this.NoAffect(defender);
                }
                else
                {
                    int power = this.Foci.Power + results.CastSuccessCount;
                    defender.SetMind(defender.Mind + power);
                    if (Object.ReferenceEquals(caster, defender))
                    {
                        // Target is self, only need a message to the caster.
                        caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                                String.Format(Resources.SpellWillpowerGained, power)));
                    }
                    else
                    {
                        // Need to inform both the caster the target of healing.
                        caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                                String.Format(Resources.SpellWillpowerGainedTarget, power, target.The())));
                        defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                                  String.Format(Resources.SpellWillpowerGainedByTarget, power, caster.A())));
                    }
                }
            }
            else
            {
                this.NoAffect(caster);
            }
        }
Exemple #6
0
        public override void Cast(IAvatar caster, IActor target, CastResults results)
        {
            IAvatar defender = target as IAvatar;

            // Increase the protection value of the target.
            if (defender != null)
            {
                if (defender is PerenthiaMobile)
                {
                    defender = caster;
                }

                int power = this.Foci.Power + results.CastSuccessCount;
                this.AffectPower = power;
                this.Save();

                // If a protection spell already exists using the same skill then remove it
                // and add the current one.
                // Search the list of spells with the same skill and try to find those spells in the
                // affects collection.
                var spellNames = defender.GetAllChildren().Where(c => c is ISpell && (c as ISpell).Skill == this.Skill).Select(c => c.Name);
                foreach (var spellName in spellNames)
                {
                    // If this protection already exists then remove it and add the new one.
                    if (defender.Affects.ContainsKey(spellName))
                    {
                        this.RemoveAffect(defender, false);
                    }
                }

                defender.Protection += power;
                defender.Affects.Add(this, this.Foci.Duration);
                defender.Context.AddRange(defender.Affects.ToRdl());
                if (Object.ReferenceEquals(caster, defender))
                {
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            String.Format(Resources.SpellProtectionGained, power)));
                }
                else
                {
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            String.Format(Resources.SpellProtectionGainedTarget, target.A(), power)));
                    defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                              String.Format(Resources.SpellProtectionGainedByTarget, power, caster.A())));
                    if (defender != null)
                    {
                        defender.Context.AddRange(defender.GetRdlProperties(Avatar.ProtectionProperty));
                    }
                }
            }
            else
            {
                this.NoAffect(caster);
            }
        }
Exemple #7
0
        public override void Cast(IAvatar caster, IActor target, CastResults results)
        {
            IAvatar defender = target as IAvatar;

            // Do not heal creatures or NPCs
            if (defender is PerenthiaMobile)
            {
                target   = caster;
                defender = caster;
            }

            // Heal or increase the body value of the target.
            if (target.Body == target.BodyMax)
            {
                this.NoAffect(caster);
                if (defender != null)
                {
                    this.NoAffect(defender);
                }
            }
            else
            {
                int power = this.Foci.Power + results.CastSuccessCount;
                target.SetBody(target.Body + power);
                if (Object.ReferenceEquals(caster, target))
                {
                    // Target is self, only need a message to the caster.
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            String.Format(Resources.SpellHealthGained, power)));
                }
                else
                {
                    // Need to inform both the caster the target of healing.
                    caster.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                            String.Format(Resources.SpellHealthGainedTarget, power, target.The())));
                    if (defender != null)
                    {
                        defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Cast,
                                                                  String.Format(Resources.SpellHealthGainedByTarget, power, caster.A())));
                    }
                }
            }
        }
        public static void SetTarget(this IAvatar avatar, IAvatar target)
        {
            // If the target's target is not null then check to see if the target's target is in the current
            // place, if not release the target.
            // Will not need to do this because mobiles are cloned.
            //IAvatar targetTarget = target.Target as IAvatar;
            //if (targetTarget != null)
            //{
            //    if (targetTarget.Location != target.Location)
            //    {
            //        target.Target = null;
            //    }
            //}

            avatar.Target = target;
            if (target != null)
            {
                target.Target = avatar;

                // Send notification to avatar.
                avatar.Context.AddRange(avatar.GetRdlProperties(Avatar.TargetIDProperty));
                avatar.Context.AddRange(target.ToSimpleRdl());
                avatar.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.None,
                                                        String.Format(Resources.TargetSet, target.A())));

                // Send notification to target
                target.Context.AddRange(target.GetRdlProperties(Avatar.TargetIDProperty));
                target.Context.AddRange(avatar.ToSimpleRdl());
                // Do not send a message to the target, not really needed.
                //target.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.None,
                //    String.Format(Resources.TargetSet, avatar.A())));
            }
        }
        /// <summary>
        /// Performs a simple combat turn.
        /// </summary>
        /// <param name="attacker">The attacking avatar.</param>
        /// <param name="attackerWeapon">The weapon to be used during the attack.</param>
        /// <param name="defender">The defending avatar.</param>
        /// <param name="defensiveSkill">The skill used to defender against the attack.</param>
        /// <param name="defenderAttributeType">The attribute used to defend.</param>
        /// <param name="range">The range from the attacker to the defender.</param>
        /// <returns>True if the defender was killed during the attack; otherwise false.</returns>
        public static bool PerformSimpleCombatTurn(
            IAvatar attacker,
            IWeapon attackerWeapon,
            string offensiveSkill,
            IAvatar defender,
            string defensiveSkill,
            AttributeType defenderAttributeType,
            int range)
        {
            // Only true if the defender gets killed.
            bool result = false;

            int defenderProtection = defender.GetArmor().Protection;

            //Phase 1: The Combat Skill Test
            //The attacker makes a combat skill test vs. Physical Dexterity (in the case of melee attacks or point blank ranged
            //attacks) or Mental Perception (in the case of ranged attacks at short range or greater), while the defender makes a
            //defense skill test against an appropriate combative or defensive skill, to determine the number of opposing successes.
            //If the number of successes scored by the attacker do not exceed the number of successes scored by the defender, then
            //the target has been hit.
            int attackerSkillLevel = (int)attacker.Skills[offensiveSkill];
            int defenderSkillLevel = (int)defender.Skills[defensiveSkill];

            if (attackerWeapon.Durability <= 0)
            {
                attackerSkillLevel = 0;
            }

            AttributeType attackerAttrType = AttributeType.Strength;             // Was Dex, should it go back to Dex?

            if (attackerWeapon.Range > 1)
            {
                attackerAttrType = AttributeType.Perception;
            }

            // Perform skill rolls.
            int attackerSuccessCount;

            SkillManager.PerformSkillTest(attacker, offensiveSkill, attackerAttrType, 0, attackerWeapon.SkillLevelRequiredToEquip, false, out attackerSuccessCount);

            int defenderSuccessCount;

            SkillManager.PerformSkillTest(defender, defensiveSkill, defenderAttributeType, 0, defender.GetArmor().SkillLevelRequiredToEquip, false, out defenderSuccessCount);

            // TODO: Implement disatrous failure in combat.
            //• In the case of a disastrous failure, the character has fumbled and loses his next attack. A very high degree
            //(3+) disastrous failure may indicate weapon breakage. This applies to both the offensive and defense sides of
            //the combat.

            // Range
            //• While a ranged attack at point blank range suffers no penalty, other ranged attacks will incur a penalty to
            //the attack roll target number based on the distance to the target. Attacks attempted within short range for
            //the weapon will suffer a penalty of -1, while attacks within medium range will suffer a -2 penalty and attacks
            //within long range will suffer a penalty of -4.
            if (range > 1)
            {
                attackerSuccessCount -= range;
                if (attackerSuccessCount == 0)
                {
                    attacker.Context.Add(new RdlSystemMessage(0, SR.AttackOutOfRange));
                }
            }

            int outcome = attackerSuccessCount - defenderSuccessCount;

            // Raise an event on the attacker so that the outcome can be modified based on world specific conditions.
            attacker.OnAttack(ref outcome);

            if (outcome > 0)
            {
                // DEFENDER WAS HIT.

                //Phase 2: Damage Determination
                //The damage value of the attacker’s weapon is added to the number of combat successes that the attacker has
                //remaining. This is the Damage Value.
                //Small weapons will typically cause 1 point of damage, medium weapons 2 points, and heavy weapons 3 points of
                //damage. Additionally, melee weapon damage is modified by a value equal to the attacker’s strength value minus 5.
                //If a character is exceptionally weak, this will subtract damage from the final value (base damage plus successes). The
                //modified damage value can never be less than zero.
                int damage = attackerSuccessCount + attackerWeapon.Power;
                damage += attacker.Attributes[AttributeType.Strength] - 5;
                if (damage <= 0)
                {
                    damage = 1;
                }

                //Phase 3: Application of Armor
                //A piece of armor has two statistics, coverage rating (CR) and absorption rating (AR). CR ranges from 1 (very
                //little coverage) to 5 (complete coverage). AR can range from as little as 1 for thin leather or heavy cloth to as much
                //as 8 or more for magical or unusual armors.
                //The attacker’s remaining successes are applied to the coverage rating. If the number of successes exceeds the
                //armor’s coverage rating, then the armor has been bypassed (a better executed hit is more likely to bypass armor), in
                //which case all damage goes straight to the defender. If the attack fails to bypass the armor, then the armor removes
                //one point of damage per point of absorption. Any damage equal to or beyond the armor’s absorption rating indicates
                //that the armor has been pierced or rendered ineffective in some way. When this happens, any excess damage is
                //applied to the character (see below), and the armor’s coverage rating is reduced by one (the armor is damaged) until
                //it can be repaired by someone with the appropriate skill (this could include the character if they have said skills).
                //Armor with a CR of 5+ cannot be damaged by penetration. This CR is usually only used for creatures with
                //natural armor or who are made of unnaturally hard substances.
                defender.OnApplyProtection(attacker, ref damage);
                //if (attackerSuccessCount <= (defenderProtection * 0.5))
                //{
                //    // Let armor absrob some or all of the damage.
                //    // Do not reduce damage more than half because of armor.
                //    int newDmg = damage - (int)(defenderProtection * 0.5);
                //    if (newDmg < (damage * 0.5))
                //    {
                //        damage = (int)(damage * 0.5);
                //    }
                //    if (damage <= 0) damage = 1;
                //}

                if (damage > 0)
                {
                    // Decrement the durability of the defender's armor.
                    defender.GetArmor().Durability--;

                    //Phase 4: Apply Damage
                    //Any remaining wounds after the application of armor are subtracted from the character’s Body stat.
                    defender.SetBody(defender.Body - damage);
                    attacker.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Melee, SR.AttackHitDefender(defender.The(), damage)));
                    defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative, SR.AttackHitByAttacker(attacker.The(), damage)));

                    if (defender.IsDead)
                    {
                        result = true;
                        attacker.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Melee,
                                                                  SR.AttackYouKilledDefender(defender.The())));
                        defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative,
                                                                  SR.AttackYouWereKilledByAttacker(attacker.The())));
                    }
                    else if (defender.IsUnconscious)
                    {
                        attacker.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Melee,
                                                                  SR.AttackUnconsciousDefender(defender.TheUpper())));
                        defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative,
                                                                  SR.AttackYouAreUnconscious));
                    }
                }
                else
                {
                    attacker.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative, SR.AttackFailed));
                    defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.None, SR.AttackAttackerFailed(attacker.A())));
                }
            }
            else
            {
                // Attacker missed.
                attacker.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Negative, SR.AttackMiss));
                defender.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.None, SR.AttackAttackerFailed(attacker.A())));
            }

            // Regardless of outcome advance the skill of the attacker and the defender.
            SkillManager.AdvanceSkill(attacker, attackerWeapon.Skill, attackerWeapon.SkillLevelRequiredToEquip, attacker.Context);
            // Use attackerWeapon as the required skill level so the defender can not elevate beyond the skill used
            // for the attack.
            SkillManager.AdvanceSkill(defender, defensiveSkill, attackerWeapon.SkillLevelRequiredToEquip, defender.Context);

            // Return result of the combat action
            return(result);
        }