public async Task <HasActionsLeft> DoStateBasedAction(
            ActionString trigger,
            ActionString exitCondition,
            ActionString action,
            int planId,
            string planKey
            )
        {
            if (await _session.ExistsPlan(planId))
            {
                if (await _engine.PossessionSatisfiesLevel(exitCondition.location, exitCondition.first, exitCondition.second))
                {
                    await _session.DeletePlan(planId);

                    return(HasActionsLeft.Available);
                }

                var hasActionsLeft = await DoAction(action);

                return(hasActionsLeft);
            }

            if (await _engine.PossessionSatisfiesLevel(trigger.location, trigger.first, trigger.second))
            {
                await _session.CreatePlan(planId, planKey);

                return(await DoAction(action));
            }

            return(HasActionsLeft.Available);
        }
        public async Task <HasActionsLeft> LowerGenericMenace(string menace, int trigger, int clear, int planId, string planKey)
        {
            var triggerstr = new ActionString($"Menaces,{menace},{trigger}");
            var exitc      = new ActionString($"Menaces,{menace},<{clear}");
            var action     = new ActionString($"require,Menaces,{menace},<1");

            return(await DoStateBasedAction(triggerstr, exitc, action, planId, planKey));
        }
 public async Task <HasActionsLeft> Acquire(ActionString actionstr, bool dryRun = false)
 {
     if (dryRun)
     {
         RecordAction(actionstr);
         return(HasActionsLeft.Consumed);
     }
     return(await Handler.DoAction(actionstr));
 }
Exemple #4
0
        public async Task <HasActionsLeft> NavigateIntoAction(ActionString action)
        {
            await GoBackIfInStorylet();

            if (_cachedList == null)
            {
                // was return false <- hasmoreactions?
                throw new Exception("invalid state after goback");
            }

            await MoveIfNeeded(action.location);

            // this is a remnant from before the time of prereq in the acq engine
            // if (action.location == "carnival" && action.first != "Buy")
            // {
            //  var hasActionsLeft = await EnsureTickets()
            //  if (!hasActionsLeft)
            //  {
            //      return false;
            //  }
            // }

            bool success = await EnterStorylet(action.first);

            if (_cachedList == null)
            {
                Log.Warning($"storylet {action.first} not found");
                return(HasActionsLeft.Faulty);
            }

            var ac = new List <string> {
                action.second
            };

            if (action.third != null)
            {
                ac.AddRange(action.third);
            }

            return(await PerformActions(ac));
        }
        public async Task <HasActionsLeft> HandleForcedAction()
        {
            var name = await _state.GetStoryletName();

            var r         = new Regex(name, RegexOptions.IgnoreCase);
            var simplekey = ForcedActionFile.simple.Keys.FirstOrDefault(k => r.IsMatch(k));

            if (simplekey != null)
            {
                await _state.PerformAction(ForcedActionFile.simple[simplekey]);

                return(HasActionsLeft.Consumed);
            }
            var complexkey = ForcedActionFile.complex.Keys.FirstOrDefault(k => r.IsMatch(k));

            if (complexkey != null)
            {
                foreach (var entry in ForcedActionFile.complex[complexkey])
                {
                    var total     = entry.Conditions.Length;
                    var satisfied = 0;
                    foreach (var cond in entry.Conditions)
                    {
                        var a = new ActionString(cond);
                        if (await _engine.PossessionSatisfiesLevel(a.location, a.first, a.second))
                        {
                            satisfied++;
                        }
                    }
                    if (total == satisfied)
                    {
                        await _state.PerformAction(entry.Action);

                        return(HasActionsLeft.Consumed);
                    }
                }
            }

            throw new Exception($"stuck in forced action named {name}, can't proceed without manual interaction");
        }
 public void RecordAction(ActionString action)
 {
     ActionHistory.Add(action);
 }
        public async Task <HasActionsLeft> DoAction(ActionString action)
        {
            if (action.IsEmpty())
            {
                Log.Error("cant do empty action");
                return(HasActionsLeft.Faulty);
            }
            Log.Info($"doing action {action}");

            //  bazaar can usually be done even in storylet, i think?
            //  require is best done doing its inventory checks before doing goback and move, to aviod extra liststorylet calls
            //  inventory just needs to make sure we do gobackifinstorylet first
            if (action.location == "buy")
            {
                if (action.third == null)
                {
                    throw new Exception($"invalid buy action {action}");
                }
                var n = action.third[0].AsNumber();
                if (!n.HasValue)
                {
                    throw new Exception($"invalid buy action {action}");
                }
                await _session.BuyPossession(action.first, action.second, n.Value);

                return(HasActionsLeft.Mismatch);
            }
            else if (action.location == "sell")
            {
                var n = action.second.AsNumber();
                if (!n.HasValue)
                {
                    throw new Exception($"invalid sell action {action}");
                }
                await _session.SellPossession(action.first, n.Value);

                return(HasActionsLeft.Mismatch);
            }
            else if (action.location == "equip")
            {
                await _session.Equip(action.first);

                return(HasActionsLeft.Mismatch);
            }
            else if (action.location == "unequip")
            {
                await _session.Unequip(action.first);

                return(HasActionsLeft.Mismatch);
            }
            // todo require, but if faulty, return available, use for tea with vicar wich needs to start with a card
            // gives Stories,Advising the Loquacious Vicar,1 then
            // ladybones,More Tea with the Vicar,1
            // ladybones,The Vicar's Search for Knowledge,the nature
            // ladybones,A Matter of Mortality with the Loquacious Vicar,ask around
            // ladybones,Looking to Warmer Climes with the Loquacious Vicar,remnants
            // ladybones,The Loquacious Vicar's Great Work,material
            else if (action.location == "require")
            {
                string level = action.third?.FirstOrDefault();
                string tag   = action.third?.Skip(1)?.FirstOrDefault();

                var hasActionsLeft = await _engine.Require(action.first, action.second, level, tag);

                return(hasActionsLeft);
            }
            else if (action.location == "inventory")
            {
                if (action.third == null)
                {
                    throw new Exception($"invalid inventory action {action}");
                }
                var hasActionsLeft = await _state.DoInventoryAction(action.first, action.second, action.third[0]);

                return(hasActionsLeft);
            }
            else if (action.location == "grind_money")
            {
                return(await GrindMoney());
            }
            else if (action.location == "handle_profession")
            {
                return(await HandleProfession());
            }
            return(await _state.NavigateIntoAction(action));
        }