it'presents selections to player'doget'/',From:'Dude8',SkipToState:'D1S108'expect(last_response.body).toinclude("what is the solution?\n1) Six\n2) Sixteen\n3) I wasn't paying attention")endit'respects selections from player'doget'/',From:'Dude8',SkipToState:'D1S108'get'/',From:'Dude8',Body:'1'expect(last_response.body).toinclude('Wrong. You haven\'t been paying attention, have you?')endit'rejects non-numeric selections from player'doget'/',From:'Dude9',SkipToState:'D1S108'get'/',From:'Dude9',Body:'Dan'expect(last_response.body).toinclude("what is the solution?\n1) Six\n2) Sixteen\n3) I wasn't paying attention")endit'rejects invalid selections from player'doget'/',From:'Dude',SkipToState:'D1S108'get'/',From:'Dude',Body:'4'expect(last_response.body).toinclude("what is the solution?\n1) Six\n2) Sixteen\n3) I wasn't paying attention")end
It may change in the future, but numeric choices seemed the best initial interface. Implementing
the selections changed the engine code significantly.
First we have to change states based on the player’s input:
## State transitionifparams.key?('SkipToState')state=params['SkipToState']elsifGameStates.states[state].key?('selection')# handle using the input to choose selectionif(index=body.to_i)!=0selections=GameStates.states[state]['selection'].to_aifselections.length>=indexstate=selections[index-1].lastelseputs"selections.length #{selections.length} index #{index}"puts"Player selected #{body} but selections are #{selections}"endelseputs"Player gave non-numeric selection: #{body}"endelsifGameStates.states[state].key?('next')state=GameStates.states[state]['next']elseputs"Not sure where to go from state: #{GameStates.states[state]}"end
This was initially a bit of a struggle, as can be seen with the debugging that I left in. A big
result was the GameStates module replacing the awkward global I had before:
# The set of game states. After being loaded from a JSON file, should never change.moduleGameStates@states={}defself.load@states=JSON.parse(File.open('script.json','r').read)enddefself.states@statesenddefself.story(state)if@states[state]&&@states[state].key?('story')String.new(@states[state]['story'])else''endenddefself.selections(state)response=''if@states[state]&&@states[state].key?('selection')@states[state]['selection'].keys.each_with_indexdo|selection,index|response+="\n#{index+1}) #{selection}"endendresponseendend
I’ve been migrating the appropriate logic into it, so that (for example) creating the output with
story text and selections is as simple as:
it'can be played all the way through'doget'/',From:'Dude'Timeout::timeout(10)dountillast_response.body.include?('And you won\'t be alone...')||last_response.body.include?('Royalty does not concern itself with common dances.')||last_response.body.include?('True power is slow dancing with someone who could beat you senseless.')||last_response.body.include?('Thirst for knowledge. Hunger for power. No feast is fine enough.')doget'/',From:'Dude',Body:['1','2','3'].sampleputslast_response.bodyendendend
(The .sample is to avoid spinning forever in the narrative loops that exist. Not elegant, but
simple.)
Player Dude has data {"state"=>"M00"}
Processing input for player {"state"=>"M00"} params {"From"=>"Dude", "Body"=>"2"}
Not sure where to go from state: {"beholder"=>"mox", "beholderPos"=>"center", "beholderExp"=>"neutral", "bg"=>"SoccerField", "namePlate"=>":name:", "conditionalSelection"=>{"condition"=>{"mox-kick"=>"known"}, "constants"=
Job's log exceeded limit of 4194304 bytes.
So I guess we need to start handling conditionalSelection. Tomorrow.