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) { 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)) { 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 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 (!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 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 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; }