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