/// <summary> /// Exits the Avatar from a previous Place and enters the current place. Sends notification to other avatars in the Place. /// </summary> /// <param name="who">The Avatar entering the room.</param> /// <param name="direction">The direction from which the avatar is entering.</param> public void Enter(IAvatar who, Direction direction) { if (who.Place != null) { who.Place.Exit(who, direction.CounterDirection); } who.Place = this; this.Children.Add(who); // Clear the target of the current avatar and the avatar's target's target. if (who.Target != null) { IAvatar target = who.Target as IAvatar; if (target != null) { target.Target = null; target.Context.AddRange(target.GetRdlProperties(Avatar.TargetIDProperty)); } who.Target = null; who.Context.AddRange(who.GetRdlProperties(Avatar.TargetIDProperty)); } // Send down the new x,y,z of the current avatar. who.Context.AddRange(who.GetRdlProperties(Avatar.XProperty, Avatar.YProperty, Avatar.ZProperty)); // Raise the OnEnter event on the current place. if (!who.IsBuilder) { this.OnEnter(who, who.Context, direction); if (who is IPlayer) { (who as IPlayer).OnPlaceEntered(); } // Raise an event on all avatar instances in the current place that a new avatar has entered. var avatars = (from c in this.Children where c is IAvatar select c as IAvatar); var whoRdl = who.ToSimpleRdl(); foreach (var avatar in avatars) { if (avatar.ID != who.ID) { avatar.OnEnter(who, who.Context, direction); } } } // Cause the newly entered avatar to look at the place. this.Look(who); }
public void Resurrect(IAvatar avatar) { avatar.SetBody(avatar.BodyMax); avatar.SetMind(avatar.MindMax); avatar.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Positive, "You have been resurrected!")); avatar.Context.AddRange(avatar.GetRdlProperties( Avatar.BodyProperty, Avatar.BodyMaxProperty, Avatar.MindProperty, Avatar.MindMaxProperty)); this.Enter(avatar, Direction.Empty); // Don't want to send down the whole map. Just send down the zone. //avatar.Context.AddRange(this.World.GetRdlMap(avatar.X, avatar.Y)); Character player = avatar as Character; if (player != null) { MapManager.MapDetail detail = this.World.Map.GetDetail(player.Location); if (detail != null) { string zone = player.Properties.GetValue <string>(Character.ZoneProperty); if (detail.Name != zone) { player.Properties.SetValue(Character.ZoneProperty, detail.Name); player.Context.Add(new RdlProperty(player.ID, Character.ZoneProperty, zone)); } } } }
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()))); } }
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()))); } } }
private void RemoveAffect(IAvatar avatar, bool wornOff) { int power = this.AffectPower; if (power == 0) { power = this.Foci.Power; } avatar.Protection -= power; if (wornOff) { avatar.Context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.None, String.Format("The affects of the {0} spell have worn off.", this.Name))); } avatar.Context.AddRange(avatar.GetRdlProperties(Avatar.ProtectionProperty)); avatar.Context.Add(new RdlCommand("AFFECTREMOVE", String.Concat(avatar.Affects.Prefix, this.Name))); }
/// <summary> /// Advances the skill level of the specified Avatar, accordng to the current level of the specified skill. /// </summary> /// <param name="avatar">The Avatar advancing the skill.</param> /// <param name="skillName">The name of the skill to advance.</param> /// <param name="context">The IMessageContext instance to write out the results to.</param> public static void AdvanceSkill(IAvatar avatar, string skillName, int requiredSkillLevel, IMessageContext context) { double skillLevel = avatar.Skills[skillName]; // Can not advance skill beyond the required skill level + max skill offset. if (skillLevel >= (requiredSkillLevel + MaxSkillLevelOffset)) { // Do not advance skill. Logger.LogDebug("[ {0} ] maxed at {1}, can not advance", skillName, skillLevel); return; } // Advance the skill level. if (skillLevel > 0 && skillLevel < 10) { skillLevel += 0.025; } else if (skillLevel >= 10 && skillLevel < 20) { skillLevel += 0.0075; } else if (skillLevel >= 20 && skillLevel < 30) { skillLevel += 0.005; } else if (skillLevel >= 30 && skillLevel < 40) { skillLevel += 0.0025; } else if (skillLevel >= 40 && skillLevel < 50) { skillLevel += 0.001; } else if (skillLevel >= 50 && skillLevel < 60) { skillLevel += 0.0005; } else if (skillLevel >= 60 && skillLevel < 70) { skillLevel += 0.00025; } else if (skillLevel >= 70 && skillLevel < 80) { skillLevel += 0.0001; } else if (skillLevel >= 80 && skillLevel < 90) { skillLevel += 0.000075; } else if (skillLevel >= 100) { skillLevel += 0.00005; } else { skillLevel += 0.000001; } int prevLevel = (int)avatar.Skills[skillName]; avatar.Skills[skillName] = skillLevel; Logger.LogDebug("[ {0} ] :: prevSkill = {1}, updatedSkill = {2}", skillName, prevLevel, skillLevel); if ((int)skillLevel > prevLevel) { // Notify of skill advancement. context.Add(new RdlSystemMessage(RdlSystemMessage.PriorityType.Level, SR.SkillAdvanced(skillName.Trim(), (int)skillLevel))); // Send down the actual skill value. context.AddRange(avatar.GetRdlProperties(avatar.Skills.GetSkillKey(skillName))); } }
/// <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); }