sms_beholder.rb 4.34 KB
Newer Older
Joe Libipl's avatar
Joe Libipl committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
require 'json'
require 'sinatra/base'

# Sinatra-derived class for easy testing
class SMSBeholder < Sinatra::Base
  configure do
    # Don't log them. We'll do that ourself
    set :dump_errors, false

    # Don't capture any errors. Throw them up the stack
    set :raise_errors, true

    # Disable internal middleware for presenting errors
    # as useful HTML pages
    set :show_exceptions, false
  end

  # The set of game states. After being loaded from a JSON file, should never change.
  module GameStates
    @states = {}

    def self.load
      @states = JSON.parse(File.open('script.json', 'r').read)
    end

    def self.states
      @states
    end

    def self.story(state)
      if @states[state] && @states[state].key?('story')
        String.new(@states[state]['story'])
      else
        ''
      end
    end

Joe Libipl's avatar
Joe Libipl committed
38
    def self.selections(state, player)
39
      selections = []
Joe Libipl's avatar
Joe Libipl committed
40
      if @states[state] && @states[state].key?('selection')
Joe Libipl's avatar
Joe Libipl committed
41
        @states[state]['selection'].each do |selection|
42
          selections << selection
Joe Libipl's avatar
Joe Libipl committed
43
44
        end
      end
Joe Libipl's avatar
Joe Libipl committed
45
      if @states[state] && @states[state].key?('conditionalSelection')
Joe Libipl's avatar
Joe Libipl committed
46
        @states[state]['conditionalSelection']['constants'].each do |selection|
47
          selections << selection
Joe Libipl's avatar
Joe Libipl committed
48
        end
Joe Libipl's avatar
Joe Libipl committed
49
50
51
52
53
54
55
56
57
58
59
60
61

        conditions_met = true
        @states[state]['conditionalSelection']['condition'].each_pair do | key, value |
          puts "Checking player #{player} for key #{key} value #{value}"
          if player[key] != value
            puts "nope"
            conditions_met = false
          else
            puts "yep" 
          end
        end

        if conditions_met
Joe Libipl's avatar
Joe Libipl committed
62
          @states[state]['conditionalSelection']['ifConditionTrue'].each do |selection|
63
            selections << selection
Joe Libipl's avatar
Joe Libipl committed
64
65
66
          end
        end

Joe Libipl's avatar
Joe Libipl committed
67
      end
Joe Libipl's avatar
Joe Libipl committed
68
      puts "returning selections: #{selections}"
69
      selections
Joe Libipl's avatar
Joe Libipl committed
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    end
  end

  player_data = {}
  GameStates.load

  def process_input(params, player)
    puts "Processing input for player #{player} params #{params}"

    body = params['Body'] || 'NoBody'

    ## State is the state that was last shown
    state = player['state']

    # Handle input
    if GameStates.states[state].key?('textEntry')
      text_entry_key = GameStates.states[state]['textEntry']['key']
      puts "Player #{player} State #{state} adding text Key #{text_entry_key} value #{body}"
      player[text_entry_key] = String.new(body)
    end

    ## State transition

Joe Libipl's avatar
Joe Libipl committed
93
94
95
96
    if params.key?('SetKey')
      puts "setting key #{params['SetKey']} to #{params['SetKeyValue']}"
      player[params['SetKey']] = params['SetKeyValue']
    end
Joe Libipl's avatar
cleanup    
Joe Libipl committed
97

Joe Libipl's avatar
Joe Libipl committed
98
99
    if params.key?('SkipToState')
      state = params['SkipToState']
Joe Libipl's avatar
Joe Libipl committed
100
    elsif GameStates.states[state].key?('selection') || GameStates.states[state].key?('conditionalSelection')
Joe Libipl's avatar
Joe Libipl committed
101
102
      # handle using the input to choose selection
      if (index = body.to_i) != 0
Joe Libipl's avatar
Joe Libipl committed
103
        selections = GameStates.selections(state, player)
Joe Libipl's avatar
Joe Libipl committed
104
105
106
107
108
109
110
        if selections.length >= index
          state = selections[index - 1].last
        else
          puts "selections.length #{selections.length} index #{index}"
          puts "Player selected #{body} but selections are #{selections}"
        end
      else
Joe Libipl's avatar
typo    
Joe Libipl committed
111
        puts "Player gave non-numeric selection: #{body}"
Joe Libipl's avatar
Joe Libipl committed
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
      end
    elsif GameStates.states[state].key?('next')
      state = GameStates.states[state]['next']
    else
      puts "Not sure where to go from state: #{GameStates.states[state]}"
    end

    ## Now state is the state to be shown
    player['state'] = state

    player
  end

  def process_output(player)
    state = player['state']

128
129
    response = GameStates.story(state)
    GameStates.selections(state, player).each_with_index do |selection, index|
Joe Libipl's avatar
Joe Libipl committed
130
      response += "\n#{index + 1}) #{selection.first}"
131
    end
Joe Libipl's avatar
Joe Libipl committed
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

    # Fill in values in response
    player.keys.each do |key|
      puts "Filling in key #{key}"
      response.gsub!(":#{key}:", player[key])
    end

    response
  end

  get '/' do
    source = params['From']

    if player_data.key?(source)
      puts "Player #{source} has data #{player_data[source]}"
      player_data[source] = process_input(params, player_data[source])
    else
      puts "Player #{source} is a new player!"
      player_data[source] = {}
      player_data[source]['state'] = params['SkipToState'] || 'SPLASH'
    end

    response = process_output(player_data[source])

    response
  end

  run! if app_file == $PROGRAM_NAME
end