Problem with take all/drop all

ok, still new @ dialog but this seems like a problem.

the ‘take al/drop alll’ commands seems to ‘cost’ a (tick) with each item taken/dropped instead of just taking one action. this seems like undesired behavior, especially when there are other events (like a series of (select)) firing inappropriately with each item.

see test code:

(intro)
            "Test" 
			(try [look])

#player
(current player *)
(* is #in #test_room)

#test_room
(name *)     It's a room
(room *)
(descr *)    It's an empty room.
(on every tick in *)   
            (select)
                This A block prints.
                (or)
                This B block prints.
                (or)
                This C block prints.
                (or)
                This D block prints.
            (cycling)

#object_1
(name *)    Object 1
(item *)
(* is #in #test_room)

#object_2
(name *)    Object 2
(item *)
(* is #in #test_room)

#object_3
(name *)    Object 3
(item *)
(* is #in #test_room)

I don’t have a solution, but I found some things that might help.

Looking through the dialog source code, it looks like you can run a command called ‘(inhibit next tick)’ which can step the game from running the next tick. The issue is trying to find a way to tell if you’re doing multiple commands in one turn.

You can see the code where they break up ‘all’ statements. I’m just not sure what to do with it:

(parse basic noun [all/everything] as $Result (object $Policy) $ExcludeList 1)
	(just)
	(collect $Obj)
		*($Obj has parent $Policy)
		($Obj is in scope)
		~($Obj is hidden)
		~(excluded from all $Obj)
	(into $Candidates)
	(apply policy to $Candidates $Policy $ExcludeList $Result)

(parse basic noun [all/everything] as $Result $Policy $ExcludeList 1)
	(just)
	(collect $Obj)
		*($Obj is in scope)
		~(excluded from all $Obj)
		~($Obj is hidden)
		(verify object policy $Policy $Obj)
	(into $Candidates)
	(apply policy to $Candidates $Policy $ExcludeList $Result)

(parse basic noun [all/every/each | $Words] as $ObjList $Policy $ExcludeList $)
	*(parse object name $Words as $ObjList 1 $Policy $ExcludeList)

It looks like group actions work for this:

(See the last line!)

1 Like

I’m a bit torn about stuff like this from a game design perspective… does it really make sense for the player to be able to grab 50 things from around the room in a single tick? (In a scene where time is of the essence, are you rewarding players for golfing down their commands?) But it is undeniably convenient…

3 Likes

yup, that fixes it. thx.

group actions are listed in the manual as an advanced topic. i felt free to skip it as the manual suggested but, unfortunately, never returned.

1 Like

Actions with all/everything as object are deconstructed into individual actions with single objects by the library, and each one ticks separately. This is by design. Ben’s solution above works, but group actions are designed to transform specific multi-actions into a logical single action, like eating ham and cheese together example in the manual. If you want all actions with all/everything tick once, you need to add may group rules for all actions, either with separate rules for each or by

(action $ may group $ with $)

The tricky part with group actions is that you can no longer rely on (instead of $) rules for actions, they won’t be invoked with grouped actions. You have to write a (group-instead of $) rule (in addition to a regular instead of rule) in case the action is used with all/everything. Also you need to keep in mind that the grouped actions may create action loopholes, as described in the manual and provide handlers for them.

If you want to keep all actions separate but still a single tick for all/everything objects you can touch these two predicates in the library with the (delayed tick) custom flag:

(try-complex $ComplexAction)
	(now) ~(delayed tick)
	(if) ~(action $ComplexAction preserves the question) (then)
		(now) ~(implicit action is $)
		(now) ~(implicit action wants direction)
	(endif)
	(if) ~(allowed action $ComplexAction) (then)
		(report disallowed action $ComplexAction)
		(stop)
	(elseif) ([] is one of $ComplexAction) (then)
		You're not aware of any such thing!
		(stop)
	(else)
		(strip decorations from $ComplexAction into $MultiAction)
		%% Now we have something like:
		%% [put [#marble1 #marble2 #marblefloor] #in #bowl]
		(if)
			*($Obj is one of $MultiAction)
			{
				(nonempty $Obj)
			(or)
				(object $Obj)
				~(direction $Obj)
				~(relation $Obj)
				~(room $Obj)
			}
		(then)
			(notice player's $Obj)
		(endif)
		(if) *($List is one of $MultiAction) (nonempty $List) (then)
			(exhaust) {
				*(regroup stripped action $MultiAction of
					$MultiAction into $Regrouped $Multi)
				%% Assuming the marbles are fungible, now we
				%% are backtracking over:
				%% [put [#marble1 #marble2] #in #bowl]
				%% [put #marblefloor #in #bowl]
				(if)
					~(empty $Multi)
				(then)
					%% If at least two multi-actions are
					%% implied, describe each step.
					(line)
					(if) (library links enabled) (then)
						(link) (The full $Multi)
					(else)
						(The full $Multi)
					(endif)
					:
				(endif)
				(try regrouped $Regrouped)
			}
		(else)
			%% Optimize the common case.
			(try regrouped $MultiAction)
		(endif)
		(if) (delayed tick) (then)
			(tick)
		(endif)
	(endif)

(try regrouped $Regrouped)
	(exhaust) {
		*($Regrouped recursively contains $O)
		(object $O)
		(now) ~($O is hidden)
	}
	(if)
		*($Elem is one of $Regrouped)
		(nonempty $Elem)
	(then)
		(group-try $Regrouped)
	(else)
		(try $Regrouped)
	(endif)
	(if) ~(command $Regrouped) (then)
		%%(tick)
		(now) (delayed tick)
	(endif)
	(par)

Take note that this modification only affects actions with multiple objects separated by and or , or all/everything as objects. Commands like the following will still tick multiple times:

get object 1 and get object 2
get object 1 then get object 2
get object 1. get object 2
get object 1, get object 2

Edit: typo.
Edit 2: multiple objects definition corrected.

2 Likes