it 'presents selections to player'do
get '/', From: 'Dude8', SkipToState: 'D1S108'
expect(last_response.body).to include("what is the solution?\n1) Six\n2) Sixteen\n3) I wasn't paying attention")
end
it 'respects selections from player'do
get '/', From: 'Dude8', SkipToState: 'D1S108'
get '/', From: 'Dude8', Body: '1'
expect(last_response.body).to include('Wrong. You haven\'t been paying attention, have you?')
end
it 'rejects non-numeric selections from player'do
get '/', From: 'Dude9', SkipToState: 'D1S108'
get '/', From: 'Dude9', Body: 'Dan'
expect(last_response.body).to include("what is the solution?\n1) Six\n2) Sixteen\n3) I wasn't paying attention")
end
it 'rejects invalid selections from player'do
get '/', From: 'Dude', SkipToState: 'D1S108'
get '/', From: 'Dude', Body: '4'
expect(last_response.body).to include("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 transitionif params.key?('SkipToState')
state = params['SkipToState']elsifGameStates.states[state].key?('selection')
# handle using the input to choose selectionif (index = body.to_i) !=0
selections =GameStates.states[state]['selection'].to_a
if selections.length >= index
state = selections[index -1].last
elseputs"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.module GameStates
@states = {}
defself.load
@states =JSON.parse(File.open('script.json', 'r').read)
enddefself.states
@states
enddefself.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_index do|selection, index|
response +="\n#{index +1}) #{selection}"endend
response
endend
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'do
get '/', From: 'Dude'Timeout::timeout(10) dountil last_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.') do
get '/', From: 'Dude', Body: ['1','2','3'].sample
puts last_response.body
endendend
(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.