protected override IInteraction Apply(HengeInteraction interaction) { Item item = interaction.Antagonist as Item; Location location = null; Component currentLevel = item; while ((location == null) && (currentLevel != null)) { if (currentLevel is Item) { if (item.Owner is Location) { location = item.Owner as Location; } } else { } } if (this.Validate(interaction) && location!=null) { this.Grow(location, interaction); } return interaction; }
protected virtual IList<Component> PrepareFindList(HengeInteraction interaction, double perception) { var query = from c in (interaction.Antagonist as Location).Inventory where c.Traits.ContainsKey("Visibility") && c.Traits["Visibility"].Value < perception select c; return query.Cast<Component>().ToList(); }
protected override IInteraction Apply(HengeInteraction interaction) { if (this.Validate(interaction)) { this.Grow(interaction.Antagonist as Location, interaction); } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { Location location = (interaction.Antagonist as MapComponent).Location; if (this.Validate(interaction) && location!=null) { this.Grow(location, interaction); } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { if (this.Validate(interaction)) { if (!interaction.Antagonist.Traits.ContainsKey("Nutrition")) interaction.Failure("After a mighty struggle with yourself, you are forced to admit that you cannot bring yourself to try to eat that", false); } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { //TODO: Need to check if the Actor is a logged-out Avatar and give them bonuses if so. if (this.Validate(interaction) && !interaction.Finished) { Actor actor = interaction.Antagonist as Actor; Trait health = actor.Traits["Health"]; Trait energy = actor.Traits["Energy"]; Trait reserve = actor.Traits["Reserve"]; Trait constitution = actor.Traits["Constitution"]; string message = "you rested and recuperated a little"; double constDelta = Constants.Tick.MetabolicRate; double healthDelta = (health.Value < health.Maximum) ? Constants.Tick.Healthy.Heal : 0; double energyDelta = (reserve.Value < reserve.Maximum) ? Constants.Tick.Healthy.Revitalise : 0; constDelta+= (healthDelta + energyDelta); if (constitution.Value <= 0) { // Decrease Health, increase Energy by less healthDelta = Constants.Tick.Ill.Heal; energyDelta = Constants.Tick.Ill.Revitalise; constDelta = -constDelta; message = "you felt weaker"; // Increase Constitution if (constitution.Value == 0) constDelta = 0; } if (health.Value + healthDelta < 0) { using (interaction.Lock(health, reserve, energy, constitution, actor.Ticks)) { //When the actor dies, all ticks should be cancelled actor.Ticks.Clear(); health.SetValue(0); energy.SetValue(0); reserve.SetValue(0); constitution.SetValue(constitution.Minimum); health.Flavour = "Dead"; } interaction.Success("you succumbed to your ailments. Your story is over... will your line continue?"); } else { using (interaction.Lock(health, reserve, constitution)) { health.SetValue(health.Value + healthDelta); reserve.SetValue(reserve.Value + energyDelta); constitution.SetValue(constitution.Value - constDelta); } interaction.Success(message); } } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { // Basic impedance rule for any impeding structure - just use the impedance value in "Impede" if (this.Validate(interaction)) { interaction.Impedance += interaction.Subject.Traits["Impede"].Value; interaction.Log+=string.Format("A {0} hinders your progress", interaction.Subject.Inspect(interaction.Protagonist).ShortDescription); } return interaction; }
protected override IList<Component> PrepareFindList(HengeInteraction interaction, double perception) { ComponentType type = interaction.Arguments["ItemType"] as ComponentType; IList<Component> hiddenItems = new List<Component>(); if (type!=null) { (interaction.Antagonist as Location).Inventory .Where(c => c.Type == type && c.Traits.ContainsKey("Visibility") && c.Traits["Visibility"].Value < perception).ToList() .ForEach(c => hiddenItems.Add(c)); } else interaction.Failure("You don't know what you're looking for", true); return hiddenItems; }
protected override IInteraction Apply(HengeInteraction interaction) { //Here's where we should do diving, if we're moving down if (this.Validate(interaction)) { if (interaction.Arguments.ContainsKey("Transition")) { int height = (int)interaction.Arguments["Transition"]; if (height >0) this.ClimbUp(interaction, height); if (height <0) this.DiveIn(interaction, height); } } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { //Here's where we should do default climbing up and down stuff if (this.Validate(interaction)) { if (interaction.Arguments.ContainsKey("Transition")) { int deltaZ = (int)interaction.Arguments["Transition"]; if (deltaZ > 0) this.ClimbUp(interaction, deltaZ); if (deltaZ < 0) this.ClimbDown(interaction, deltaZ); } } return interaction; }
protected override bool Validate(HengeInteraction interaction) { bool result = false; if (!interaction.Finished) { if (interaction.Antagonist != null) { if (interaction.Antagonist.Traits.ContainsKey("Health") && interaction.Antagonist.Traits["Health"].Flavour=="Dead") { interaction.Failure("You are dead", false); } else result = true; } else interaction.Failure("Interactors are invalid", true); } return result; }
protected override IInteraction Apply(HengeInteraction interaction) { Location antagonist = interaction.Antagonist as Location; double tariff = antagonist.Traits.ContainsKey("Impede")? antagonist.Traits["Impede"].Value : Constants.Impedance; double difficulty = antagonist.Traits["Movement"].Value / Constants.MaxMovementDifficulty; double successTariff = tariff - (1-tariff) * (interaction.Protagonist.Skills.ContainsKey("Swim")? interaction.Protagonist.Skills["Swim"].Value : 0); interaction.Actions.Add( ()=>{ switch (interaction.ProtagonistCache.SkillCheck("Swim", difficulty+interaction.Difficulty, successTariff+interaction.Impedance, tariff+interaction.Impedance, EnergyType.Strength)) { case SkillResult.PassExhausted: if (interaction.Protagonist.Location.Traits.ContainsKey("Movement") && (interaction.Protagonist.Location.Traits["Movement"].Flavour=="Swim")) interaction.Failure("You feel you are too weak to swim that far, and tread water while your strength returns.", false); else interaction.Failure("You begin to swim, but realise you are too tired to swim that far. You return to dry land while you gather your strength", false); break; case SkillResult.PassSufficient: interaction.Log+=("You swim strongly through the water. "); break; default: interaction.Log+= ("You struggle to keep your head above the water. You cough and splutter, panicking, as you realise you can't breathe. "); Trait health = interaction.Protagonist.Traits["Health"]; Trait constitution = interaction.Protagonist.Traits["Constitution"]; using (interaction.Lock(interaction.Protagonist, health, constitution)) { health.Value -= 2; constitution.Value -= 4; if (health.Value<=0) health.Flavour = "Dead"; } if (health.Flavour=="Dead") interaction.Failure("The light of the surface fades above you. Your struggles subside as your breath runs out. You have died.", false); else { if (interaction.Protagonist.Location.Traits.ContainsKey("Movement") && (interaction.Protagonist.Location.Traits["Movement"].Flavour=="Swim")) interaction.Failure("As you flounder, the currents carry you back the way you came", false); else interaction.Failure("As you flounder, the currents carry you back to shore. You haul yourself back out of the water, gasping for breath", false); } break; } }); if (!(interaction.Protagonist.Location.Traits.ContainsKey("Movement") && interaction.Protagonist.Location.Traits["Movement"].Flavour == "Swim")) { this.AddTransition(interaction); } this.AddGuards(interaction); return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { if (this.Validate(interaction)) { Actor protagonist = interaction.Protagonist as Actor; if (protagonist.Location == interaction.Antagonist) { //potentially want to check for interferers here IList<Component> hiddenItems = new List<Component>(); double perception = 1 - (protagonist.Skills.ContainsKey("Perception")? protagonist.Skills["Perception"].Value : Constants.DefaultSkill); this.PrepareFindList(interaction, perception); Constants.Randomise(hiddenItems); interaction.Arguments.Add("Items", hiddenItems); } else interaction.Failure("You're unable to search a location you aren't in", true); } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { if (this.Validate(interaction)) { //put the appropriate guarding trait into the interaction if (interaction.Antagonist is Location || interaction.Antagonist is Edifice) { //for Locations and Edifices, we want to impede entry interaction.Arguments.Add("Impede", null); } if (!(interaction.Antagonist is Location)) { //for everything *except* Locations we want to stop people from stealing or attacking interaction.Arguments.Add("Guard", null); } } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { if (this.Validate(interaction)) { Location antagonist = interaction.Antagonist as Location; double tariff = antagonist.Traits.ContainsKey("Impede")? antagonist.Traits["Impede"].Value : Constants.Impedance; double difficulty = antagonist.Traits["Movement"].Value / Constants.MaxMovementDifficulty; double successTariff = tariff - (1-tariff) * (interaction.Protagonist.Skills.ContainsKey("Climb")? interaction.Protagonist.Skills["Climb"].Value : 0); interaction.Actions.Add( ()=>{ switch (interaction.ProtagonistCache.SkillCheck("Climb", difficulty+interaction.Difficulty, successTariff+interaction.Impedance, tariff+interaction.Impedance, EnergyType.Strength)) { case SkillResult.PassExhausted: interaction.Failure("You can see a likely-looking route over the rocks, but are too tired to follow it. You turn back.", false); break; case SkillResult.PassSufficient: interaction.Log+=("You climb over the rocks. "); break; default: interaction.Log+=("You slip as you climb across the rocks, falling painfully. "); Trait health = interaction.Protagonist.Traits["Health"]; Trait constitution = interaction.Protagonist.Traits["Constitution"]; using (interaction.Lock(interaction.Protagonist, health, constitution)) { health.Value -= 3; constitution.Value -= 3; if (health.Value<=0) { constitution.Value = constitution.Minimum; health.Flavour = "Dead"; } } if (health.Flavour=="Dead") interaction.Failure("You land badly. The fall is enough to kill you.", false); else interaction.Failure("Defeated, you turn back", false); break; } }); this.AddGuards(this.AddTransition(interaction)); } return interaction; }
protected IInteraction Climb(HengeInteraction interaction) { if(this.Validate(interaction)) { Location antagonist = interaction.Antagonist as Location; Actor protagonist = interaction.Protagonist; double tariff = 0.25 * (protagonist.Location.Traits.ContainsKey("Impede")? protagonist.Location.Traits["Impede"].Value : Constants.Impedance); double difficulty = 0.5 * protagonist.Location.Traits["Movement"].Value / Constants.MaxMovementDifficulty; double successTariff = tariff - (1-tariff) * (protagonist.Skills.ContainsKey("Climb")? protagonist.Skills["Climb"].Value : 0); switch (interaction.ProtagonistCache.SkillCheck("Climb", difficulty, successTariff, tariff, EnergyType.Strength)) { case SkillResult.PassExhausted: interaction.Log = string.Empty; interaction.Failure("You feel too weak to set out; you pause to gather your strength.", false); break; case SkillResult.PassSufficient: interaction.Log=string.Format("You climb across the {0}. {1}", interaction.Protagonist.Location.Inspect(interaction.Protagonist).ShortDescription, interaction.Log); break; default: interaction.Log = string.Empty; interaction.Failure("The terrain is too difficult for you to climb through. You appear to be trapped", false); break; } if (!interaction.Finished) { foreach (Action action in interaction.Actions) { if (interaction.Finished) break; else action.Invoke(); } } if (!interaction.Finished) { this.ApplyInteraction(interaction, interaction.Protagonist, antagonist); } } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { if (this.Validate(interaction)) { Location venue = ((Actor)interaction.Protagonist).Location; Item antagonist = interaction.Antagonist as Item; //check no one is guarding the item, if they are then add them to the interferers list if (venue.Inventory.Contains(antagonist)) { venue.Fauna .Where(c => c.Traits.ContainsKey("Guard") && c.Traits["Guard"].Subject == antagonist).ToList() .ForEach(c => interaction.Interferers.Add(c)); venue.Inhabitants .Where(c => c.Traits.ContainsKey("Guard") && c.Traits["Guard"].Subject == antagonist).ToList() .ForEach(c => interaction.Interferers.Add(c)); if (interaction.Interferers.Any()) Constants.Randomise(interaction.Interferers); } else interaction.Failure("The item is no longer here", false); } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { if (!interaction.Finished && this.Validate(interaction)) { Item food = interaction.Antagonist as Item; Actor actor = interaction.Protagonist as Actor; double nutrition = food.Traits["Nutrition"].Value; if (nutrition > 0) { interaction.Success(string.Format("You eat the {0} with relish", food.Inspect(actor))); } else { if (nutrition == 0) interaction.Success(string.Format("You eat the {0}", food.Inspect(actor))); else interaction.Success(string.Format("You eat the {0}. You feel queasy.", food.Inspect(actor))); } if (food.Owner == actor) { Trait weight = actor.Traits["Weight"]; Trait constitution = actor.Traits["Constitution"]; using (interaction.Lock(actor.Inventory, weight, constitution)) { weight.SetValue(weight.Value - food.Traits["Weight"].Value); constitution.SetValue(constitution.Value + nutrition); actor.Inventory.Remove(food); } interaction.Delete(food); } else interaction.Failure("You no longer have that", true); } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { if (!interaction.Finished && this.Validate(interaction)) { if (interaction.ProtagonistCache.UseEnergy(Constants.TalkCost, EnergyType.None)) { if (interaction.Arguments.ContainsKey("Message")) { List<Avatar> recipients = interaction.Arguments["Recipients"] as List<Avatar>; if (recipients==null) recipients = new List<Avatar>(); string target = (recipients.Count > 1) ? "out loud" : "to you"; string message = string.Format("{0} says \"{1}\" {2}.", interaction.Protagonist.Name, interaction.Arguments["Message"] as string, target); DateTime occurred = DateTime.Now; foreach (Avatar recipient in recipients) { //Log the speech using (interaction.Lock(recipient.Log)) { // Possibly inefficient to lock each recipient's log individually. Also, shouldn't // we be using the relational DB for this sort of thing? recipient.Log.Add(new LogEntry(){ Entry = message, Occurred = occurred}); } } if (recipients.Count == 1) { target = string.Format("to {0}", recipients[0].Name); } interaction.Success(string.Format("You say \"{0}\" {0}.", interaction.Arguments["Message"], target)); } else interaction.Failure("You have nothing to say", false); } else interaction.Failure("You are too tired even to speak", false); } return interaction; }
protected override double Visibility(HengeInteraction interaction, out Component subject) { //Don't modify visibility subject = null; return -1; }
protected IInteraction Move(HengeInteraction interaction) { // structure of this rule is // // IF (ConditionsMet(protagonist, antagonists, interaction)) // THEN ApplyChanges (protagonist, antagonists, interaction) // if (this.Validate(interaction)) { Location antagonist = interaction.Antagonist as Location; Location source = interaction.Protagonist.Location; double impedance = 0.25 * (source.Traits.ContainsKey("Impede") ? source.Traits["Impede"].Value : Constants.Impedance); if (!interaction.ProtagonistCache.UseEnergy(impedance, EnergyType.Fitness)) { interaction.Log = string.Empty; if (impedance > interaction.ProtagonistCache.Strength * interaction.Protagonist.Traits["Energy"].Maximum) { interaction.Failure("You seem to be trapped.", false); } else interaction.Failure("You are unable to summon sufficient energy to set out", false); } else { interaction.Log = string.Format("You set off through the {0}. {1}", source.Inspect(interaction.Protagonist).ShortDescription, interaction.Log); foreach (Action action in interaction.Actions) { if (interaction.Finished) break; else action.Invoke(); } } if (!interaction.Finished) { this.ApplyInteraction(interaction, interaction.Protagonist, antagonist); } } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { if (this.Validate(interaction)) interaction.Arguments.Add("Recipients", (interaction.Antagonist as Edifice).Inhabitants); return interaction; }
protected void ApplyInteraction(HengeInteraction interaction, Actor actor, Location target) { int dx = actor.Location.X - target.X; int dy = actor.Location.Y - target.Y; char [] inDirection = new char [] { (dx > 0) ? 'e' : (dx < 0) ? 'w' : '-', (dy > 0) ? 's' : (dy < 0) ? 'n' : '-' }; char [] outDirection = new char [] { (dx < 0) ? 'e' : (dx > 0) ? 'w' : '-', (dy < 0) ? 's' : (dy > 0) ? 'n' : '-' }; double baseTrack = actor.Traits.ContainsKey("Tracks")? actor.Traits["Tracks"].Value : Constants.BaseTrack; double trackOut = baseTrack * (actor.Location.Traits.ContainsKey("Tracks")?actor.Location.Traits["Tracks"].Value : 0); double trackIn = baseTrack * (target.Traits.ContainsKey("Tracks")?target.Traits["Tracks"].Value : 0); if (actor is Avatar) { Dictionary<string, int> timesIn = new Dictionary<string, int>(); Dictionary<string, int> timesOut = new Dictionary<string, int>(); foreach(Trait track in target.TracesOut) { if (DateTime.Now<(DateTime)(track.Expiry)) { Actor person = track.Subject as Actor; if (timesOut.ContainsKey(person.Name)) { timesOut[person.Name]++; } else timesOut.Add(person.Name, 1); } } foreach(Trait track in target.TracesIn) { if(DateTime.Now<(DateTime)(track.Expiry)) { Actor person = track.Subject as Actor; if (timesIn.ContainsKey(person.Name)) { timesIn[person.Name]++; } else timesIn.Add(person.Name, 1); } } bool beenHere = false; foreach(string name in timesIn.Keys) { if (name!=actor.Name) { int outTimes = timesOut.ContainsKey(name)?timesOut[name] : 0; int totalTraffic = timesIn[name] + outTimes; if (totalTraffic <3) { interaction.Log += (name + " has been here. "); } else { if (totalTraffic < 6) { interaction.Log += (name + " has been here more than once. "); } else { interaction.Log += (name + " has been here frequently. "); } } if (outTimes < timesIn[name]) interaction.Log += "You cannot see any of their tracks leading away. "; } else beenHere = true; } if (timesOut.ContainsKey(actor.Name)) { beenHere = true; } if (beenHere) interaction.Log += " It looks like you've been here before. "; Avatar avatar = actor as Avatar; //potential bottleneck here - may want to do smarter locking using (interaction.Lock(avatar, avatar.Location.Inhabitants, target.Inhabitants, avatar.Location.TracesOut, target.TracesIn)) { this.AddTracks(avatar.Location, avatar, false, outDirection.ToString(), trackOut, interaction); this.AddTracks(target, avatar, true, inDirection.ToString(), trackIn, interaction); avatar.Location.Inhabitants.Remove(avatar); target.Inhabitants.Add(avatar); avatar.Location = target; } interaction.Success(string.Format("You reach your destination, a {0}", target.Inspect(avatar).ShortDescription)); } else { Npc npc = actor as Npc; using (interaction.Lock(npc, npc.Location.Fauna, target.Fauna, npc.Location.TracesOut, target.TracesIn)) { this.AddTracks(npc.Location, npc, false, outDirection.ToString(), trackOut, interaction); this.AddTracks(target, npc, true, inDirection.ToString(), trackIn, interaction); npc.Location.Fauna.Remove(npc); target.Fauna.Add(npc); npc.Location = target; } interaction.Success("Moved"); } }
protected override double Visibility(HengeInteraction interaction, out Component subject) { //This does not affect visibility subject = null; return -1; }
protected override IInteraction Apply(HengeInteraction interaction) { return this.Move(interaction); }
private void AddTracks(Location location, Actor actor, bool inbound, string flavour, double strength, HengeInteraction interaction) { IList<Trait> list = inbound? location.TracesIn : location.TracesOut; foreach(Trait track in list) { if ((DateTime)(track.Expiry) >= DateTime.Now) { list.Remove(track); interaction.Delete(track); } } if (strength > 0) { if (list.Count >= Constants.MaximumTracks) { Constants.Randomise(list); Trait overwritten = list[0]; list.RemoveAt(0); interaction.Delete(overwritten); } list.Add(new Trait(Constants.MaximumTrackValue, 0, strength){ Subject=actor, Flavour = flavour, Expiry = DateTime.Now + Constants.TraceLife }); } }
protected override double Visibility(HengeInteraction interaction, out Component subject) { //visibility doesn't change subject = null; return -1; }
protected new bool Validate(HengeInteraction interaction) { bool result = false; if (!interaction.Finished) { Location antagonist = interaction.Antagonist as Location; Location source = interaction.Protagonist.Location; if (base.Validate(interaction)) { if (this.CalculateDistance(source, antagonist) <= 2) { result = true; } else interaction.Failure("You cannot move that far", true); } } return result; }
protected override double Visibility(HengeInteraction interaction, out Component subject) { subject = interaction.Protagonist; return (Constants.StandardVisibility * interaction.SubjectCache.Conspicuousness); }
protected override double Visibility(HengeInteraction interaction, out Component subject) { //Moving; become more obvious: subject = interaction.Protagonist; return (Constants.StandardVisibility * interaction.ProtagonistCache.Conspicuousness); }