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)) { 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) { 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 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) { 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 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)) { 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 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 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) ) { if ( interaction.ProtagonistCache.Energy > 0) { Actor protagonist = interaction.Protagonist as Actor; Location source = protagonist.Location; Location target = interaction.Antagonist as Location; if (target.Map == source.Map) { if (source.CanSee(target)) { double dx = target.X - source.X; double dy = target.Y - source.Y; double distance = dx * dx + dy * dy; double sourceCover = source.Traits.ContainsKey("Cover") ? source.Traits["Cover"].Value : Constants.DefaultCover; double targetCover = target.Traits.ContainsKey("Cover") ? target.Traits["Cover"].Value : Constants.DefaultCover; distance = distance * Math.Max(sourceCover, targetCover); double detection = protagonist.Skills["Perception"].Value; double difficulty = distance * Constants.EdificeScouting; int success = 0; bool weary = false; switch (interaction.ProtagonistCache.SkillCheck("Perception", distance * Constants.LocationScouting, Constants.ScoutCost, Constants.ScoutCost, EnergyType.Concentration)) { case SkillResult.PassSufficient: interaction.Results.Add("Location", target); success=1; break; case SkillResult.FailSufficient: break; default: weary = true; break; } switch (interaction.ProtagonistCache.SkillCheck("Perception", difficulty, Constants.ScoutCost, Constants.ScoutCost, EnergyType.Concentration)) { case SkillResult.PassSufficient: success++; interaction.Results.Add("Structures", target.Structures.Where(c => c.Traits.ContainsKey("Visibility") && c.Traits["Visibility"].Value >= detection - difficulty).ToList()); difficulty = distance * Constants.ActorScouting; break; case SkillResult.FailSufficient: break; default: weary = true; break; } switch (interaction.ProtagonistCache.SkillCheck("Perception", difficulty, Constants.ScoutCost, Constants.ScoutCost, EnergyType.Concentration)) { case SkillResult.PassSufficient: difficulty = detection - difficulty; interaction.Results.Add("NPCs", target.Fauna.Where(c => c.Traits.ContainsKey("Visibility") && c.Traits["Visibility"].Value >= difficulty).ToList()); interaction.Results.Add("Avatars", target.Inhabitants.Where(c => c.Traits.ContainsKey("Visibility") && c.Traits["Visibility"].Value >= difficulty).ToList()); success ++; break; case SkillResult.FailSufficient: break; default: weary = true; break; } if (weary) interaction.Log+="Your tired eyes may not be trustworthy, but you"; else interaction.Log+= "You "; switch (success) { case 3: interaction.Success("feel that you have a good view of the area"); break; case 2: interaction.Success("can see the area reasonably well"); break; case 1: interaction.Success("can just about make out the terrain"); break; default: interaction.Failure("can't make anything out", false); break; } } else interaction.Failure("You can't see from here", false); } else interaction.Failure("You are attempting to scout a location you cannot see", true); } else interaction.Failure("You are too tired to focus on scouting", false); } return interaction; }
protected override IInteraction Apply(HengeInteraction interaction) { if (!interaction.Finished && this.Validate(interaction)) { Actor protagonist = interaction.Protagonist as Actor; Component antagonist = interaction.Antagonist; //Hiding a Location is dumb, and will just fail. if (antagonist is Location) { interaction.Failure("You cannot hide a location", true); } else { //You can try to hide pretty much anything else. //I suspect hiding a building is going to be a bit very impossible, //but we can handle that by simply giving Edifices very, very large Conspicuousness values. //Difficulty of hiding something depends upon // 1) Conspicuousness of the thing being hidden // 2) Things interfering // - Up to this point, the running total is cached in interaction.Impedance - // 3) The "Cover" trait of the Location - even if you're useless at hiding stuff, this could make it easier // 4) The protagonists "Hide" skill double visibility = Constants.StandardVisibility; //This is going to cost us Some Energy. The better we hid it, the more effort it took, so... double maxEnergy = interaction.Protagonist.Traits["Energy"].Maximum; double best = interaction.ProtagonistCache.Energy / maxEnergy; double randomNumber = Constants.RandomNumber; randomNumber = (randomNumber > best) ? best : randomNumber; if (randomNumber > 0) { //So, the worst-case visibility is now known. //difficulty is in Impedance, need to modify it by the cover available: switch (interaction.ProtagonistCache.SkillCheck("Hide", interaction.Impedance / protagonist.Location.Traits["Cover"].Value, randomNumber * maxEnergy, randomNumber * maxEnergy, EnergyType.Concentration)) { case SkillResult.PassSufficient: //You've hidden it. But how well? //Let's add our rng result to the hide skill and divide by two visibility -= visibility * (interaction.Protagonist.Skills.ContainsKey("Hide") ? 0.5 * (randomNumber + interaction.Protagonist.Skills["Hide"].Value) : 0.5 * randomNumber); if (antagonist is Avatar) interaction.Success(string.Format("You attempt to conceal {0}", antagonist.Name)); else interaction.Success(string.Format("You attempt to conceal the {0}", antagonist.Inspect(protagonist).ShortDescription)); break; case SkillResult.PassExhausted: interaction.Failure("You are too tired", false); break; default: interaction.Failure("Your skill at concealing things isn't up to the task", false); break; } visibility *= interaction.AntagonistCache.Conspicuousness; if (antagonist is Item && (antagonist as Item).Owner == protagonist) { Item item = antagonist as Item; Trait protagonistWeight = protagonist.Traits["Weight"]; using (interaction.Lock(protagonist.Location.Inventory, item, protagonistWeight, protagonist.Inventory)) { protagonist.Location.Inventory.Add(item); item.Owner = protagonist.Location; protagonist.Traits["Weight"].SetValue(protagonist.Traits["Weight"].Value - item.Traits["Weight"].Value); protagonist.Inventory.Remove(item); } } using (interaction.Lock(antagonist.Traits)) { if (antagonist.Traits.ContainsKey("Visibility")) { // Not sure how safe it is to use recursive locking? using (interaction.Lock(antagonist.Traits["Visibility"])) { antagonist.Traits["Visibility"].SetValue(visibility); } } else antagonist.Traits.Add("Visibility", new Trait(double.MaxValue, 0, visibility)); } } else { interaction.Failure("You can see nowhere to hide that", false); } } } return interaction; }