MikeTaylor / scottkit

Scott Adams adventure toolkit: compile, decompile and play 80s-style adventure games
30 stars 10 forks source link

Compiler auto-continue issue #38

Open jpcompton opened 4 years ago

jpcompton commented 4 years ago

In trying to solve my own problem from #37 by reducing the number of printed messages, I've run into an oddity with the "condition has 6 conditions" error and the compiler's attempts to fix.

This original .sck code (see my source in #37 for full details) compiles and works:

 action give script when here players and flag 5 and here script
    print "We can play the MURDER OF GONZAGO!"
    print "They exit to the throne room"
    print "The play is ABOUT to begin!"
    put script throneroom
    destroy players

Decompiled, it becomes:

action GIV SCR when here Players and flag 5 and here Script
    print "We can play the MURDER OF GONZAGO!"
    print "They exit to the throne room"
    print "The play is ABOUT to begin!"
    continue

occur 0%
    put Script Room1
    destroy Players
    comment "cont"

However, if I edit that action into this:

action give script when here players and flag 5 and here script
    print "We can play the MURDER OF GONZAGO!
They exit to the throne room
The play is ABOUT to begin!"
    put script throneroom
    destroy players

then the following compiler bork occurs:

/Library/Ruby/Gems/2.3.0/gems/scottkit-1.6.0/lib/scottkit/compile.rb:463:in `block in generate_code': condition has 6 conditions (RuntimeError)
    from /Library/Ruby/Gems/2.3.0/gems/scottkit-1.6.0/lib/scottkit/compile.rb:457:in `each'
    from /Library/Ruby/Gems/2.3.0/gems/scottkit-1.6.0/lib/scottkit/compile.rb:457:in `generate_code'
    from /Library/Ruby/Gems/2.3.0/gems/scottkit-1.6.0/lib/scottkit/compile.rb:38:in `compile_to_stdout'
    from /Library/Ruby/Gems/2.3.0/gems/scottkit-1.6.0/lib/scottkit/game.rb:287:in `compile_to_stdout'
    from /Library/Ruby/Gems/2.3.0/gems/scottkit-1.6.0/bin/scottkit:115:in `block in <top (required)>'
    from /Library/Ruby/Gems/2.3.0/gems/scottkit-1.6.0/lib/scottkit/withio.rb:11:in `withIO'
    from /Library/Ruby/Gems/2.3.0/gems/scottkit-1.6.0/bin/scottkit:114:in `<top (required)>'
    from /usr/local/bin/scottkit:22:in `load'
    from /usr/local/bin/scottkit:22:in `<main>'
jpcompton commented 4 years ago

This occurred in a few places during my message combinations, so there are a few places in my current code where I had to keep two or even three prints in order to successfully compile. (search for "issue 38" to find them.) rotten_v1.zip

(Update: As of my third test build, there are a total of eight excess print messages being used to pad around this issue. Since my game is at the 99-message limit this has a genuine impact on my ability to add/enhance content.)

jpcompton commented 4 years ago

Is there any way to make that kind of compile bork more informative? It doesn't give us any information (that I can decode, anyway) about where in the source the issue is happening. If you can't dump line numbers can you at least dump nearby text/symbols? (This had a practical effect on me... when I was first going through and boiling down these multiple print strings to single strings, I created multiple of these bork spots and ultimately had to revert all my changes and start over, doing a test recompile after changing every action block. That's pretty fast on modern hardware, but if I were writing the game from scratch and hit that kind of roadblock it would have been harder to recover from.)

jpcompton commented 4 years ago

As discussed on the intfiction forum, rolling my own fix in ScottKit does work around the problem:

action give script when here players and flag 5 and present script
    print "We can play the MURDER OF GONZAGO!\nThey exit to the throne room\nThe play is ABOUT to begin!"
#   print "We can play the MURDER OF GONZAGO!"
#   print "They exit to the throne room"
#   print "The play is ABOUT to begin!"
    continue

occur 0%
    put players throneroom
    put script throneroom

This does compile and run correctly and saves the two excess messages.

However, the documentation officially forbids this coding approach, so I continue to defer to you, when you have time to address it. :)

continue -- Never use this action. It is used internally to allow a sequence of actions that is too long to fit into a single action slot, but there is no reason at all why you would ever explicitly use it: in fact, this kind of low-level detail is precisely what ScottKit is supposed to protect you from. I don't know why I'm even mentioning it.

MikeTaylor commented 4 years ago

Multi-line messages (with embedded \n) are absolutely fine.

But why can't you just say

action give script when here players and flag 5 and present script
    print "We can play the MURDER OF GONZAGO!\nThey exit to the throne room\nThe play is ABOUT to begin!"
    put players throneroom
    put script throneroom

?

MikeTaylor commented 4 years ago

Ah, OK — I see that very problem is what this issue is about. Sorry.

I'll stop reacting to individual messages and wait till I have time to look at the bugs properly.

dstelzer commented 4 years ago

As far as I can tell, the compiler uses continue as needed to break up over-long sequences of results, but doesn't use it to break up over-long sequences of conditions needed for those results. In this case, it's generating seven conditions from that action (NOP players, NOP throneroom, NOP script, NOP throneroom, here players, flag 5, present script), hence the error.

The obvious solution is to insert continue as needed to break this up (put all the actual conditions in the first action, then distribute the gathered_args as necessary to provide parameters to the results, with no more than five per action). But it might also be worthwhile to remove any arguments from gathered_args that already appear in conds, and rearrange them appropriately: this action shouldn't need a continue at all, if I'm reading this right, because the conditions could be arranged as [here players, NOP throneroom, present script, NOP throneroom, flag 5].

Would this be feasible?

dstelzer commented 4 years ago

…never mind, I spoke too soon. I'd thought that the nouns used in all conditions could be used as result parameters, but it seems it can only use ones with the condition NOP (condition code 0). Ignore that part.

jpcompton commented 4 years ago

A question about Ghost King's published .dat having a continue-within-continue prompted me to look at a decompilation of adv11, and I think there is some evidence there that it isn't necessary to repeat continue, and indeed that there may be an opportunity to introduce more flexibility with conditional checks than we currently have if you wanted to go that route:

action CRUS FLOW when present Flower and !flag 7
    destroy2 Flower
    continue

occur 0% when !flag 18
    print sedated!
    print "I feel"
    print ASPHYXIATED
    die

occur 0% when here Neanderthal
    set_flag 10
    print Neanderthal
    print sedated!

occur 0% when here Neanderthal
    select_counter 2
    set_counter 40
    select_counter 2

action GET NEAN when here Neanderthal
[finally doing different stuff]

Two things jump out at me about that code. For one, there are several occur 0%s which can be evaluated without additional continues (there's no continue between the two "when here Neanderthal" blocks), and for the other, it seems like Adams uses continue in part as a way to evaluate different conditions inside a condition: "is flag 18 unset, or is the Neanderthal here?". adv03 also has examples of this kind of branching inside a continue.