|
ferencd@0
|
1 require 'net/http/server'
|
|
ferencd@0
|
2 require 'pp'
|
|
ferencd@0
|
3 require 'ellers'
|
|
ferencd@0
|
4 require 'wilsons'
|
|
ferencd@0
|
5 require 'distance_grid'
|
|
ferencd@0
|
6 require 'pg'
|
|
ferencd@0
|
7 require 'base62-rb'
|
|
ferencd@0
|
8 require 'zlib'
|
|
ferencd@0
|
9 require 'wlang'
|
|
ferencd@0
|
10 require 'set'
|
|
ferencd@0
|
11 require 'descends'
|
|
ferencd@0
|
12 require 'pg'
|
|
ferencd@0
|
13 require 'database'
|
|
ferencd@0
|
14 require 'openssl'
|
|
ferencd@0
|
15 require 'game'
|
|
ferencd@0
|
16 require 'gs_logger'
|
|
ferencd@0
|
17 require 'gamedata'
|
|
ferencd@0
|
18
|
|
ferencd@0
|
19 #
|
|
ferencd@0
|
20 # Starting the App, updating things that need to be
|
|
ferencd@0
|
21 #
|
|
ferencd@0
|
22 $LOG.info 'gameserver 0.1 starting'
|
|
ferencd@0
|
23 Database.initialize
|
|
ferencd@0
|
24
|
|
ferencd@0
|
25 #
|
|
ferencd@0
|
26 # Constants
|
|
ferencd@0
|
27 #
|
|
ferencd@0
|
28 CONTENT_TYPE = 'Content-Type'
|
|
ferencd@0
|
29 MAIN_HTML = 'lab.html'
|
|
ferencd@0
|
30 CONTENT_TYPES =
|
|
ferencd@0
|
31 {
|
|
ferencd@0
|
32 :png => 'image/png',
|
|
ferencd@0
|
33 :gif => 'image/gif',
|
|
ferencd@0
|
34 :js => 'application/javascript'
|
|
ferencd@0
|
35 }
|
|
ferencd@0
|
36
|
|
ferencd@0
|
37 GAME_TYPE_MAZE = 1
|
|
ferencd@0
|
38 GAME_TYPE_ADVENTURE = 2
|
|
ferencd@0
|
39 GAME_TYPE_STORY = 3
|
|
ferencd@0
|
40
|
|
ferencd@0
|
41 #################################################################################################################
|
|
ferencd@0
|
42 # Helper classes
|
|
ferencd@0
|
43 #################################################################################################################
|
|
ferencd@0
|
44
|
|
ferencd@0
|
45 #
|
|
ferencd@0
|
46 # Used to get some extra numbers
|
|
ferencd@0
|
47 #
|
|
ferencd@0
|
48 class Integer
|
|
ferencd@0
|
49 N_BYTES = [42].pack('i').size
|
|
ferencd@0
|
50 N_BITS = N_BYTES * 16
|
|
ferencd@0
|
51 MAX = 2 ** (N_BITS - 2) - 1
|
|
ferencd@0
|
52 MIN = -MAX - 1
|
|
ferencd@0
|
53 end
|
|
ferencd@0
|
54
|
|
ferencd@0
|
55 #
|
|
ferencd@0
|
56 # An extension to the plain string class to provide b62 validations
|
|
ferencd@0
|
57 #
|
|
ferencd@0
|
58 class String
|
|
ferencd@0
|
59 def valid_b62?
|
|
ferencd@0
|
60 !!match(/^[[:alnum:]]+$/)
|
|
ferencd@0
|
61 end
|
|
ferencd@0
|
62
|
|
ferencd@0
|
63 def is_i?
|
|
ferencd@0
|
64 /\A[-+]?\d+\z/ === self
|
|
ferencd@0
|
65 end
|
|
ferencd@0
|
66
|
|
ferencd@0
|
67 def encrypt(key)
|
|
ferencd@0
|
68 cipher = OpenSSL::Cipher::Cipher.new('DES-EDE3-CBC').encrypt
|
|
ferencd@0
|
69 cipher.key = Digest::SHA1.hexdigest key
|
|
ferencd@0
|
70 s = cipher.update(self) + cipher.final
|
|
ferencd@0
|
71 s.unpack('H*')[0].upcase
|
|
ferencd@0
|
72 end
|
|
ferencd@0
|
73
|
|
ferencd@0
|
74 def decrypt(key)
|
|
ferencd@0
|
75 cipher = OpenSSL::Cipher::Cipher.new('DES-EDE3-CBC').decrypt
|
|
ferencd@0
|
76 cipher.key = Digest::SHA1.hexdigest key
|
|
ferencd@0
|
77 s = [self].pack('H*').unpack('C*').pack('c*')
|
|
ferencd@0
|
78 cipher.update(s) + cipher.final
|
|
ferencd@0
|
79 end
|
|
ferencd@0
|
80
|
|
ferencd@0
|
81 end
|
|
ferencd@0
|
82
|
|
ferencd@0
|
83 #
|
|
ferencd@0
|
84 # Simple class to NOT to escape HTML code in the wlang renderer
|
|
ferencd@0
|
85 #
|
|
ferencd@0
|
86 class SimpleHtmlRenderer < WLang::Dialect
|
|
ferencd@0
|
87
|
|
ferencd@0
|
88 def highlight(buf, fn)
|
|
ferencd@0
|
89 var_name = render(fn)
|
|
ferencd@0
|
90 var_value = evaluate(var_name)
|
|
ferencd@0
|
91 buf << var_value
|
|
ferencd@0
|
92 end
|
|
ferencd@0
|
93
|
|
ferencd@0
|
94 tag '$', :highlight
|
|
ferencd@0
|
95 end
|
|
ferencd@0
|
96
|
|
ferencd@0
|
97
|
|
ferencd@0
|
98 #################################################################################################################
|
|
ferencd@0
|
99 # Helper methods #
|
|
ferencd@0
|
100 #################################################################################################################
|
|
ferencd@0
|
101
|
|
ferencd@0
|
102 #
|
|
ferencd@0
|
103 # Provides a fully completed template for the template engine
|
|
ferencd@0
|
104 #
|
|
ferencd@0
|
105 def complete_templates(templates)
|
|
ferencd@0
|
106 (1..5).each do | v |
|
|
ferencd@0
|
107 templates["gotext#{v}".to_sym] = '' unless templates.has_key? "gotext#{v}".to_sym
|
|
ferencd@0
|
108 end
|
|
ferencd@0
|
109 templates
|
|
ferencd@0
|
110 end
|
|
ferencd@0
|
111
|
|
ferencd@0
|
112 #
|
|
ferencd@0
|
113 # Just returns page not found
|
|
ferencd@0
|
114 #
|
|
ferencd@0
|
115 def page_not_found
|
|
ferencd@0
|
116 content_type = {CONTENT_TYPE => 'text/html'}
|
|
ferencd@0
|
117 retv = [ '<html><center><strong>404 :-(</strong></center></html>' ]
|
|
ferencd@0
|
118 code = 404
|
|
ferencd@0
|
119 return code, content_type, retv
|
|
ferencd@0
|
120 end
|
|
ferencd@0
|
121
|
|
ferencd@0
|
122 def internal_server_error
|
|
ferencd@0
|
123 content_type = {CONTENT_TYPE => 'text/html'}
|
|
ferencd@0
|
124 retv = [ '<html><center><strong>500 :-(</strong></center></html>' ]
|
|
ferencd@0
|
125 code = 500
|
|
ferencd@0
|
126 return code, content_type, retv
|
|
ferencd@0
|
127 end
|
|
ferencd@0
|
128
|
|
ferencd@0
|
129
|
|
ferencd@0
|
130 #
|
|
ferencd@0
|
131 # Will create a random room in the grid
|
|
ferencd@0
|
132 #
|
|
ferencd@0
|
133 def create_room(grid)
|
|
ferencd@0
|
134
|
|
ferencd@0
|
135 tries = 0
|
|
ferencd@0
|
136 can_not_make = false
|
|
ferencd@0
|
137 begin
|
|
ferencd@0
|
138
|
|
ferencd@0
|
139 max_width = [grid.columns/10, 6].max
|
|
ferencd@0
|
140 max_height = [grid.rows/10, 6].max
|
|
ferencd@0
|
141
|
|
ferencd@0
|
142 grid_width = rand(2 .. max_width) + 2
|
|
ferencd@0
|
143 grid_height = rand(2 .. max_height) + 2
|
|
ferencd@0
|
144
|
|
ferencd@0
|
145 x1 = rand(grid.columns - grid_width - 4)
|
|
ferencd@0
|
146 x2 = x1 + grid_width
|
|
ferencd@0
|
147 y1 = rand(grid.rows - grid_height - 4)
|
|
ferencd@0
|
148 y2 = y1 + grid_height
|
|
ferencd@0
|
149
|
|
ferencd@0
|
150 tries += 1
|
|
ferencd@0
|
151 can_not_make = !grid.can_make_room(x1,y1,x2,y2)
|
|
ferencd@0
|
152
|
|
ferencd@0
|
153 end while can_not_make && tries > 5
|
|
ferencd@0
|
154
|
|
ferencd@0
|
155 return '' if tries >= 5
|
|
ferencd@0
|
156
|
|
ferencd@0
|
157 grid.create_room x1, y1, x2, y2
|
|
ferencd@0
|
158
|
|
ferencd@0
|
159 # Place the door
|
|
ferencd@0
|
160 door_x_cell = x1 + grid_width / 2
|
|
ferencd@0
|
161 door_y_top_cell = y1
|
|
ferencd@0
|
162 door_y_bottom_cell = y1 + 1
|
|
ferencd@0
|
163
|
|
ferencd@0
|
164 "{r:#{door_y_bottom_cell},c:#{door_x_cell},v:0}, {r:#{door_y_top_cell},c:#{door_x_cell},v:1}"
|
|
ferencd@0
|
165 end
|
|
ferencd@0
|
166
|
|
ferencd@0
|
167 #
|
|
ferencd@0
|
168 # Calculates the distance from the goal cell on the given grid towards the cell_to_go
|
|
ferencd@0
|
169 # and returns the final_len and final_path
|
|
ferencd@0
|
170 #
|
|
ferencd@0
|
171 def distance_calculator(goal, grid, cell_to_go, final_len, final_path)
|
|
ferencd@0
|
172 another_distances = goal.distances
|
|
ferencd@0
|
173 grid.distances = another_distances.path_to(cell_to_go)
|
|
ferencd@0
|
174 jsv2 = grid.distances_js_array_path
|
|
ferencd@0
|
175 final_len += jsv2.length
|
|
ferencd@0
|
176 final_path += jsv2
|
|
ferencd@0
|
177 return final_len, final_path
|
|
ferencd@0
|
178 end
|
|
ferencd@0
|
179
|
|
ferencd@0
|
180 #
|
|
ferencd@0
|
181 # Generates a path for the given walker
|
|
ferencd@0
|
182 #
|
|
ferencd@0
|
183 def create_walker_path(grid, r, c)
|
|
ferencd@0
|
184 # making a new path from the furthest point from there
|
|
ferencd@0
|
185 new_distances = grid[r, c].distances
|
|
ferencd@0
|
186
|
|
ferencd@0
|
187 # goal will be the cell which is the furthest from the new_start and max_dist the length of it
|
|
ferencd@0
|
188 goal, _ = new_distances.max
|
|
ferencd@0
|
189 grid.distances = new_distances.path_to(goal)
|
|
ferencd@0
|
190
|
|
ferencd@0
|
191 jsv = grid.distances_js_array_path
|
|
ferencd@0
|
192 final_path = jsv
|
|
ferencd@0
|
193 final_len = final_path.length
|
|
ferencd@0
|
194
|
|
ferencd@0
|
195 # And the goal is that the walker will take a round around the maze
|
|
ferencd@0
|
196
|
|
ferencd@0
|
197 # Now add in another path to (0,0)
|
|
ferencd@0
|
198 final_len, final_path = distance_calculator(goal, grid, grid[0, 0],final_len, final_path)
|
|
ferencd@0
|
199 final_len, final_path = distance_calculator(grid[0, 0], grid, grid[0, grid.columns - 1],final_len, final_path)
|
|
ferencd@0
|
200 final_len, final_path = distance_calculator(grid[0, grid.columns - 1], grid, grid[grid.rows - 1, grid.columns - 1],final_len, final_path)
|
|
ferencd@0
|
201
|
|
ferencd@0
|
202 s = ''
|
|
ferencd@0
|
203 s << "path_len:#{final_len},r:#{r},c:#{c},p:'#{final_path}'"
|
|
ferencd@0
|
204 s
|
|
ferencd@0
|
205
|
|
ferencd@0
|
206 end
|
|
ferencd@0
|
207
|
|
ferencd@0
|
208 # will generate a few walking characters
|
|
ferencd@0
|
209 def generate_walkers(grid, max_nr)
|
|
ferencd@0
|
210 walkers = []
|
|
ferencd@0
|
211 return walkers if max_nr == 0
|
|
ferencd@0
|
212
|
|
ferencd@0
|
213 walker_count = rand(1 .. max_nr + 1)
|
|
ferencd@0
|
214 $LOG.info"Generating #{walker_count} walkers\n"
|
|
ferencd@0
|
215 #walkers << {:body => 0, :row => 0, :col => 1, :path => "path_len:3,r:0,c:1,p:'EEE'"}
|
|
ferencd@0
|
216 #walkers << {:body => 0, :row => 0, :col => 4, :path => "path_len:3,r:0,c:4,p:'WWW'"}
|
|
ferencd@0
|
217 dbg_cwa = 0
|
|
ferencd@0
|
218 (1..walker_count).each do
|
|
ferencd@0
|
219 walker_body = dbg_cwa #rand(3)
|
|
ferencd@0
|
220 dbg_cwa = 1 if dbg_cwa == 0
|
|
ferencd@0
|
221 walker_row = rand(1 .. grid.rows - 2) + 1
|
|
ferencd@0
|
222 walker_col = rand(1 .. grid.columns - 2) + 1
|
|
ferencd@0
|
223 walkers <<
|
|
ferencd@0
|
224 {
|
|
ferencd@0
|
225 :body => walker_body,
|
|
ferencd@0
|
226 :row => walker_row,
|
|
ferencd@0
|
227 :col => walker_col,
|
|
ferencd@0
|
228 :path => create_walker_path(grid,walker_row,walker_col)
|
|
ferencd@0
|
229 }
|
|
ferencd@0
|
230 end
|
|
ferencd@0
|
231 walkers
|
|
ferencd@0
|
232 end
|
|
ferencd@0
|
233
|
|
ferencd@0
|
234
|
|
ferencd@0
|
235 #
|
|
ferencd@0
|
236 # Will put the loot stuff on the level. food_locations is an array where wealready have placed food
|
|
ferencd@0
|
237 #
|
|
ferencd@0
|
238 def place_loot(grid, food_locations)
|
|
ferencd@0
|
239 loot_js = 'var loot=['
|
|
ferencd@0
|
240 max_possible_loot = grid.dead_ends[1].length + grid.dead_ends[2].length + grid.dead_ends[4].length + grid.dead_ends[8].length
|
|
ferencd@0
|
241 max_possible_loot = max_possible_loot / 4 + 1
|
|
ferencd@0
|
242
|
|
ferencd@0
|
243 max_loot_count = $ITEMS.length # 32 items defined in the png_to_js
|
|
ferencd@0
|
244
|
|
ferencd@0
|
245 loot_count = [rand(max_possible_loot), max_loot_count].min # We want a lot of loot in the maze
|
|
ferencd@0
|
246
|
|
ferencd@0
|
247 current_loot_count = 0
|
|
ferencd@0
|
248 idxs = [1, 2, 4, 8]
|
|
ferencd@0
|
249 idxsc = 0
|
|
ferencd@0
|
250 current_idx = idxs[idxsc]
|
|
ferencd@0
|
251 loot_js_arr = []
|
|
ferencd@0
|
252 placed_loots = []
|
|
ferencd@0
|
253 current_loot_value = 0
|
|
ferencd@0
|
254
|
|
ferencd@0
|
255 (1..loot_count).each do |_|
|
|
ferencd@0
|
256
|
|
ferencd@0
|
257 place_ctr = 0
|
|
ferencd@0
|
258 can_place = true
|
|
ferencd@0
|
259 begin
|
|
ferencd@0
|
260 cell = grid.dead_ends[current_idx][rand (grid.dead_ends[current_idx].length)]
|
|
ferencd@0
|
261 place_ctr += 1
|
|
ferencd@0
|
262 already_placed_here = placed_loots.select {|loot_loc| loot_loc[:r] == cell.row && loot_loc[:c] == cell.column}
|
|
ferencd@0
|
263 here_is_not_fine = already_placed_here.length > 0
|
|
ferencd@0
|
264
|
|
ferencd@0
|
265 unless here_is_not_fine
|
|
ferencd@0
|
266 food_placed_here = food_locations.select {|food_loc| food_loc[:r] == cell.row && food_loc[:c] == cell.column}
|
|
ferencd@0
|
267 here_is_not_fine |= food_placed_here.length > 0
|
|
ferencd@0
|
268 end
|
|
ferencd@0
|
269
|
|
ferencd@0
|
270 end while here_is_not_fine && place_ctr < grid.dead_ends[current_idx].length-1
|
|
ferencd@0
|
271
|
|
ferencd@0
|
272 if place_ctr == grid.dead_ends[current_idx].length-1
|
|
ferencd@0
|
273 if already_placed_here.length > 0
|
|
ferencd@0
|
274 # try to find the first non empty place in the grid
|
|
ferencd@0
|
275 found = false
|
|
ferencd@0
|
276 (0..grid.dead_ends[current_idx].length - 1).each do |i|
|
|
ferencd@0
|
277 cell = grid.dead_ends[current_idx][i]
|
|
ferencd@0
|
278
|
|
ferencd@0
|
279 already_placed_here = placed_loots.select {|loot_loc| loot_loc[:r] == cell.row && loot_loc[:c] == cell.column}
|
|
ferencd@0
|
280 can_go_here = already_placed_here.length == 0
|
|
ferencd@0
|
281 food_placed_here = food_locations.select {|loot_loc| loot_loc[:r] == cell.row && loot_loc[:c] == cell.column}
|
|
ferencd@0
|
282 can_go_here &= food_placed_here.length == 0
|
|
ferencd@0
|
283
|
|
ferencd@0
|
284 if can_go_here
|
|
ferencd@0
|
285 found = true
|
|
ferencd@0
|
286 break
|
|
ferencd@0
|
287 end
|
|
ferencd@0
|
288
|
|
ferencd@0
|
289 end
|
|
ferencd@0
|
290 can_place = false if found
|
|
ferencd@0
|
291 end
|
|
ferencd@0
|
292 end
|
|
ferencd@0
|
293
|
|
ferencd@0
|
294 if can_place
|
|
ferencd@0
|
295 loot_js_arr << "{r:#{cell.row},c:#{cell.column},t:#{current_loot_count}}" if (cell.row > 0 && cell.column > 0)
|
|
ferencd@0
|
296
|
|
ferencd@0
|
297 current_loot_value += $ITEMS[current_loot_count][:value]
|
|
ferencd@0
|
298 placed_loots << {:r => cell.row, :c => cell.column}
|
|
ferencd@0
|
299 else
|
|
ferencd@0
|
300 break
|
|
ferencd@0
|
301 end
|
|
ferencd@0
|
302
|
|
ferencd@0
|
303 current_idx = idxs[idxsc]
|
|
ferencd@0
|
304
|
|
ferencd@0
|
305 idxsc += 1
|
|
ferencd@0
|
306 if idxsc == idxs.length
|
|
ferencd@0
|
307 idxsc = 0
|
|
ferencd@0
|
308 end
|
|
ferencd@0
|
309 current_loot_count += 1
|
|
ferencd@0
|
310 if current_loot_count == max_loot_count
|
|
ferencd@0
|
311 current_loot_count = 0
|
|
ferencd@0
|
312 end
|
|
ferencd@0
|
313 end
|
|
ferencd@0
|
314 loot_js << loot_js_arr.join(',') << "];\n"
|
|
ferencd@0
|
315 return loot_js, placed_loots, current_loot_value
|
|
ferencd@0
|
316 end
|
|
ferencd@0
|
317
|
|
ferencd@0
|
318 #
|
|
ferencd@0
|
319 # Will put the food on the table ... ie. level
|
|
ferencd@0
|
320 #
|
|
ferencd@0
|
321 def place_food(grid, level_number, game_type)
|
|
ferencd@0
|
322 food_js = 'var food=['
|
|
ferencd@0
|
323 max_possible_food = grid.dead_ends[1].length + grid.dead_ends[2].length + grid.dead_ends[4].length + grid.dead_ends[8].length
|
|
ferencd@0
|
324 max_possible_food = max_possible_food / 4 + 1
|
|
ferencd@0
|
325 food_count = rand(max_possible_food)
|
|
ferencd@0
|
326
|
|
ferencd@0
|
327 if game_type == GAME_TYPE_STORY
|
|
ferencd@0
|
328 if level_number > 55
|
|
ferencd@0
|
329 food_count *= 4
|
|
ferencd@0
|
330 elsif level_number > 45
|
|
ferencd@0
|
331 food_count *= 3
|
|
ferencd@0
|
332 elsif level_number > 20
|
|
ferencd@0
|
333 food_count *= 2
|
|
ferencd@0
|
334 elsif level_number < 10
|
|
ferencd@0
|
335 food_count /= 2
|
|
ferencd@0
|
336 food_count += 1
|
|
ferencd@0
|
337 end
|
|
ferencd@0
|
338 end
|
|
ferencd@0
|
339
|
|
ferencd@0
|
340 max_food_count = 10 # This comes from png_to_js the number of possible food items available
|
|
ferencd@0
|
341 current_food_count = 0 # Counts the food items of the max available
|
|
ferencd@0
|
342 idxs = [1, 2, 4, 8] # The indexes of the cells, which are "dead ends".
|
|
ferencd@0
|
343 idxsc = 0 # Counter for the "dead end" index array
|
|
ferencd@0
|
344 current_idx = idxs[idxsc] # The current "dead end" index
|
|
ferencd@0
|
345 food_js_arr = [] # Will hold the javascript array for the food stuff
|
|
ferencd@0
|
346 placed_foods = [] # Will hold where the food was placed
|
|
ferencd@0
|
347
|
|
ferencd@0
|
348 (1..food_count).each do |_|
|
|
ferencd@0
|
349
|
|
ferencd@0
|
350 place_ctr = 0
|
|
ferencd@0
|
351 can_place = true
|
|
ferencd@0
|
352
|
|
ferencd@0
|
353 # Find a place (cell) where we can place the food item
|
|
ferencd@0
|
354 begin
|
|
ferencd@0
|
355 cell = grid.dead_ends[current_idx][rand (grid.dead_ends[current_idx].length)]
|
|
ferencd@0
|
356 place_ctr += 1
|
|
ferencd@0
|
357 already_placed_here = placed_foods.select {|food_loc| food_loc[:r] == cell.row && food_loc[:c] == cell.column}
|
|
ferencd@0
|
358 end while already_placed_here.length>0 && place_ctr < grid.dead_ends[current_idx].length-1
|
|
ferencd@0
|
359
|
|
ferencd@0
|
360 if place_ctr == grid.dead_ends[current_idx].length-1
|
|
ferencd@0
|
361 # Did not find an "empty dead end" cell to put the food there
|
|
ferencd@0
|
362 if already_placed_here.length > 0
|
|
ferencd@0
|
363 # try to find the first empty cell in the grid
|
|
ferencd@0
|
364 found = false
|
|
ferencd@0
|
365 (0..grid.dead_ends[current_idx].length - 1).each do |i|
|
|
ferencd@0
|
366 cell = grid.dead_ends[current_idx][i]
|
|
ferencd@0
|
367 already_placed_here = placed_foods.select {|food_loc| food_loc[:r] == cell.row && food_loc[:c] == cell.column}
|
|
ferencd@0
|
368 if already_placed_here.length == 0
|
|
ferencd@0
|
369 found = true
|
|
ferencd@0
|
370 break
|
|
ferencd@0
|
371 end
|
|
ferencd@0
|
372 end
|
|
ferencd@0
|
373 can_place = false if found
|
|
ferencd@0
|
374 end
|
|
ferencd@0
|
375 end
|
|
ferencd@0
|
376
|
|
ferencd@0
|
377 if can_place
|
|
ferencd@0
|
378 food_js_arr << "{r:#{cell.row},c:#{cell.column},t:#{current_food_count}}" if (cell.row > 0 && cell.column > 0)
|
|
ferencd@0
|
379 placed_foods << {:r => cell.row, :c => cell.column}
|
|
ferencd@0
|
380 else
|
|
ferencd@0
|
381 break
|
|
ferencd@0
|
382 end
|
|
ferencd@0
|
383
|
|
ferencd@0
|
384 current_idx = idxs[idxsc]
|
|
ferencd@0
|
385
|
|
ferencd@0
|
386 idxsc += 1
|
|
ferencd@0
|
387 if idxsc == idxs.length
|
|
ferencd@0
|
388 idxsc = 0
|
|
ferencd@0
|
389 end
|
|
ferencd@0
|
390 current_food_count += 1
|
|
ferencd@0
|
391 if current_food_count == max_food_count
|
|
ferencd@0
|
392 current_food_count = 0
|
|
ferencd@0
|
393 end
|
|
ferencd@0
|
394 end
|
|
ferencd@0
|
395 food_js << food_js_arr.join(',') << "];\n"
|
|
ferencd@0
|
396 return food_js, placed_foods
|
|
ferencd@0
|
397 end
|
|
ferencd@0
|
398
|
|
ferencd@0
|
399 def place_torches(grid)
|
|
ferencd@0
|
400 torches = grid.identify_torch_locations
|
|
ferencd@0
|
401 torch_data = []
|
|
ferencd@0
|
402 torches.each do |torch|
|
|
ferencd@0
|
403 torch_data << "{i:#{torch[:i]},j:#{torch[:j]},p:#{torch[:number]}}"
|
|
ferencd@0
|
404 end
|
|
ferencd@0
|
405 torch_str = "var torch_placements=[#{torch_data.join(',')}];\n"
|
|
ferencd@0
|
406 storch_str = Utils.split(torch_str, 80)
|
|
ferencd@0
|
407 storch_str
|
|
ferencd@0
|
408 end
|
|
ferencd@0
|
409
|
|
ferencd@0
|
410 def place_doors(grid, exit_row, exit_col)
|
|
ferencd@0
|
411 doors_js = []
|
|
ferencd@0
|
412 # Create a few rooms in the grid
|
|
ferencd@0
|
413 room_count = 0 #rand(4 .. 10)
|
|
ferencd@0
|
414 (1..room_count).each do
|
|
ferencd@0
|
415 room_js = create_room(grid)
|
|
ferencd@0
|
416 if room_js
|
|
ferencd@0
|
417 doors_js << room_js
|
|
ferencd@0
|
418 else
|
|
ferencd@0
|
419 break
|
|
ferencd@0
|
420 end
|
|
ferencd@0
|
421 end
|
|
ferencd@0
|
422 # 0 -> cell with a top door, 1 -> cell with a bottom door in
|
|
ferencd@0
|
423 # adding a door at (0,0) just for visual effects :)
|
|
ferencd@0
|
424 # add another door at (width, height) to indicate exit
|
|
ferencd@0
|
425 doors_js << '{r:0,c:0,v:0}'
|
|
ferencd@0
|
426 doors_js << "{r:#{exit_row},c:#{exit_col},v:5}"
|
|
ferencd@0
|
427 doors_str = "var doors=[ #{doors_js.join(',')}];\nvar exit_row=#{exit_row};\nvar exit_col=#{exit_col};";
|
|
ferencd@0
|
428 sdoors_str = Utils.split(doors_str, 80)
|
|
ferencd@0
|
429 sdoors_str
|
|
ferencd@0
|
430 end
|
|
ferencd@0
|
431
|
|
ferencd@0
|
432 def place_weapons(food_locations, grid, height, width)
|
|
ferencd@0
|
433 weapons_js = 'var weapon_locations = ['
|
|
ferencd@0
|
434 weapon_locs = []
|
|
ferencd@0
|
435 all_weapons = [0, 1, 2, 3] # 0 - spear, armor, shoe, ring
|
|
ferencd@0
|
436 special_weapons = [2, 3].to_set
|
|
ferencd@0
|
437 shoe_distance = 0
|
|
ferencd@0
|
438 ring_distance = 0
|
|
ferencd@0
|
439
|
|
ferencd@0
|
440 all_weapons.each do |weapon|
|
|
ferencd@0
|
441 distance_len = 101
|
|
ferencd@0
|
442 begin
|
|
ferencd@0
|
443 wcol = 1 + rand(width - 2)
|
|
ferencd@0
|
444 wrow = 1+ rand(height - 2)
|
|
ferencd@0
|
445
|
|
ferencd@0
|
446 fl = 0
|
|
ferencd@0
|
447 fp = ''
|
|
ferencd@0
|
448 wep_cell = grid[wrow, wcol]
|
|
ferencd@0
|
449 cell00 = grid[0, 0]
|
|
ferencd@0
|
450 distance_len, _ = distance_calculator(wep_cell, grid, cell00, fl, fp)
|
|
ferencd@0
|
451
|
|
ferencd@0
|
452 if weapon == 2
|
|
ferencd@0
|
453 shoe_distance = distance_len
|
|
ferencd@0
|
454 end
|
|
ferencd@0
|
455
|
|
ferencd@0
|
456 if weapon == 3
|
|
ferencd@0
|
457 ring_distance = distance_len
|
|
ferencd@0
|
458 end
|
|
ferencd@0
|
459
|
|
ferencd@0
|
460 foods_already_placed_here = food_locations.select {|food_loc| food_loc[:r] == wrow && food_loc[:c] == wcol}
|
|
ferencd@0
|
461 food_here = foods_already_placed_here.length > 0
|
|
ferencd@0
|
462
|
|
ferencd@0
|
463 weapons_placed_here = weapon_locs.select {|weapon_loc| weapon_loc[:r] == wrow && weapon_loc[:c] == wcol}
|
|
ferencd@0
|
464 weapon_here = weapons_placed_here.length > 0
|
|
ferencd@0
|
465
|
|
ferencd@0
|
466 end while (distance_len > 101 && special_weapons.include?(weapon)) || food_here || weapon_here
|
|
ferencd@0
|
467
|
|
ferencd@0
|
468 weapon_locs << {:r => wrow, :c => wcol, :t => weapon}
|
|
ferencd@0
|
469 end
|
|
ferencd@0
|
470 weap_tmp_arr=[]
|
|
ferencd@0
|
471 weapon_locs.each {|wpl| weap_tmp_arr << "{r:#{wpl[:r]},c:#{wpl[:c]},t:#{wpl[:t]}}"}
|
|
ferencd@0
|
472 weapons_js << weap_tmp_arr.join(',') << "];\n"
|
|
ferencd@0
|
473 return weapons_js, shoe_distance, ring_distance
|
|
ferencd@0
|
474 end
|
|
ferencd@0
|
475
|
|
ferencd@0
|
476 #
|
|
ferencd@0
|
477 # Will create a new maze with the given number as the seed for the random generator.
|
|
ferencd@0
|
478 #
|
|
ferencd@0
|
479 def handle_maze_with_number(level_number, game_id, main_html='lab.html', game_type = GAME_TYPE_STORY)
|
|
ferencd@0
|
480
|
|
ferencd@0
|
481 current_seed = 0x2ECD06801D ^ level_number
|
|
ferencd@0
|
482 # Set the seed based on the level number
|
|
ferencd@0
|
483 srand(current_seed)
|
|
ferencd@0
|
484
|
|
ferencd@0
|
485 minwidth = 10
|
|
ferencd@0
|
486 minheight = 10
|
|
ferencd@0
|
487
|
|
ferencd@0
|
488 maxwidth = 30
|
|
ferencd@0
|
489 maxheight = 30
|
|
ferencd@0
|
490
|
|
ferencd@0
|
491 # There are no walkers, so the system should be able to handle it
|
|
ferencd@0
|
492 if game_type == GAME_TYPE_MAZE
|
|
ferencd@0
|
493 maxwidth = 40
|
|
ferencd@0
|
494 maxheight = 40
|
|
ferencd@0
|
495 end
|
|
ferencd@0
|
496
|
|
ferencd@0
|
497 maxwidth = [minwidth + level_number, maxwidth].min
|
|
ferencd@0
|
498 maxheight = [minheight + level_number, maxheight].min
|
|
ferencd@0
|
499
|
|
ferencd@0
|
500 width = rand(minwidth .. maxwidth)
|
|
ferencd@0
|
501 height = rand(minheight ..maxheight)
|
|
ferencd@0
|
502
|
|
ferencd@0
|
503 $LOG.info "GameID:#{game_id} Generated: #{width} x #{height} for level #{level_number}"
|
|
ferencd@0
|
504
|
|
ferencd@0
|
505 grid = DistanceGrid.new(height, width)
|
|
ferencd@0
|
506 wilson = Wilsons.new
|
|
ferencd@0
|
507 wilson.on grid
|
|
ferencd@0
|
508
|
|
ferencd@0
|
509 maze_js = ''
|
|
ferencd@0
|
510 maze_js << "history.pushState(null, null, '/#{game_id}');"
|
|
ferencd@0
|
511 maze_js << "var w = #{width};\n"
|
|
ferencd@0
|
512 maze_js << "var h = #{height};\n"
|
|
ferencd@0
|
513 maze_js << "#{grid.maze_js_array}\n"
|
|
ferencd@0
|
514
|
|
ferencd@0
|
515 # Now identify all the places where a torch can go
|
|
ferencd@0
|
516 storch_str = place_torches(grid)
|
|
ferencd@0
|
517 maze_js << storch_str
|
|
ferencd@0
|
518
|
|
ferencd@0
|
519 # Where the exit is for now
|
|
ferencd@0
|
520 exit_col = width - 1
|
|
ferencd@0
|
521 exit_row = height- 1
|
|
ferencd@0
|
522
|
|
ferencd@0
|
523
|
|
ferencd@0
|
524 # At a later stage the exit will not be exactly at the end of the maze, but at the furthest cell from (0,0)
|
|
ferencd@0
|
525 # start = grid[0,0]
|
|
ferencd@0
|
526 # distances = start.distances
|
|
ferencd@0
|
527 # new_start, _ = distances.max
|
|
ferencd@0
|
528 #if game_type == GAME_TYPE_ADVENTURE
|
|
ferencd@0
|
529 # exit_col = new_start.column
|
|
ferencd@0
|
530 # exit_row = new_start.row
|
|
ferencd@0
|
531 #end
|
|
ferencd@0
|
532
|
|
ferencd@0
|
533 # Calculate the shortest path from the entrance to the exit
|
|
ferencd@0
|
534 fp_fl = 0
|
|
ferencd@0
|
535 fp_fp = ''
|
|
ferencd@0
|
536 fp_wep_cell = grid[exit_row, exit_col]
|
|
ferencd@0
|
537 fp_cell00 = grid[0,0]
|
|
ferencd@0
|
538 full_path_len, _ = distance_calculator(fp_wep_cell, grid, fp_cell00, fp_fl, fp_fp)
|
|
ferencd@0
|
539 $LOG.info "Distance from (0,0) to (#{exit_col}, #{exit_row}) is #{full_path_len} steps"
|
|
ferencd@0
|
540
|
|
ferencd@0
|
541 loot_value = 0
|
|
ferencd@0
|
542 walkers = []
|
|
ferencd@0
|
543 food_locations = []
|
|
ferencd@0
|
544
|
|
ferencd@0
|
545 # Create a few rooms with doors. Notes:
|
|
ferencd@0
|
546 # 1. This is not done due to various reasons yet
|
|
ferencd@0
|
547
|
|
ferencd@0
|
548 sdoors_str = place_doors(grid, exit_row, exit_col)
|
|
ferencd@0
|
549 maze_js << sdoors_str
|
|
ferencd@0
|
550
|
|
ferencd@0
|
551 # Create a few walkers but only if the game type is not a simple maze runner
|
|
ferencd@0
|
552 if game_type != GAME_TYPE_MAZE
|
|
ferencd@0
|
553 max_walkers = 0
|
|
ferencd@0
|
554 if game_type == GAME_TYPE_STORY
|
|
ferencd@0
|
555 max_walkers = [ [1, level_number - 3].max, 15].min if level_number > 4
|
|
ferencd@0
|
556 else
|
|
ferencd@0
|
557 max_walkers = rand(3..15)
|
|
ferencd@0
|
558 end
|
|
ferencd@0
|
559
|
|
ferencd@0
|
560 walkers = generate_walkers(grid, max_walkers)
|
|
ferencd@0
|
561 walkers_str_array = []
|
|
ferencd@0
|
562 walkers.each do |walker|
|
|
ferencd@0
|
563 walkers_str_array << "{t:#{walker[:body]},#{walker[:path]}}"
|
|
ferencd@0
|
564 end
|
|
ferencd@0
|
565 walkers_js = "var walkers=[#{walkers_str_array.join(',')}];\n"
|
|
ferencd@0
|
566 maze_js << Utils.split(walkers_js, 80)
|
|
ferencd@0
|
567 maze_js << "var walkers_count = #{walkers.length};"
|
|
ferencd@0
|
568 else
|
|
ferencd@0
|
569 maze_js << "var walkers=[];\nvar walkers_count=0;"
|
|
ferencd@0
|
570 end
|
|
ferencd@0
|
571
|
|
ferencd@0
|
572 # Food items
|
|
ferencd@0
|
573 if game_type != GAME_TYPE_MAZE
|
|
ferencd@0
|
574 food_js, food_locations = place_food(grid, level_number, game_type)
|
|
ferencd@0
|
575 maze_js << "#{food_js}"
|
|
ferencd@0
|
576 else
|
|
ferencd@0
|
577 maze_js << "var food=[];\n"
|
|
ferencd@0
|
578 end
|
|
ferencd@0
|
579
|
|
ferencd@0
|
580 # Loot in the maze only if this is an adventure game
|
|
ferencd@0
|
581 if game_type == GAME_TYPE_ADVENTURE
|
|
ferencd@0
|
582 loot_js, loot_locations, loot_value = place_loot(grid, food_locations)
|
|
ferencd@0
|
583
|
|
ferencd@0
|
584 # Just hack the food locations to contain all the loot
|
|
ferencd@0
|
585 (food_locations << loot_locations).flatten!
|
|
ferencd@0
|
586 else
|
|
ferencd@0
|
587 loot_js = "var loot=[];\n"
|
|
ferencd@0
|
588 end
|
|
ferencd@0
|
589
|
|
ferencd@0
|
590 maze_js << "#{loot_js}"
|
|
ferencd@0
|
591
|
|
ferencd@0
|
592 shoe_distance = 0
|
|
ferencd@0
|
593 ring_distance = 0
|
|
ferencd@0
|
594
|
|
ferencd@0
|
595 # Weapons
|
|
ferencd@0
|
596 if game_type != GAME_TYPE_MAZE
|
|
ferencd@0
|
597 weapons_js,shoe_distance,ring_distance = place_weapons(food_locations, grid, height, width)
|
|
ferencd@0
|
598 maze_js << "#{weapons_js}"
|
|
ferencd@0
|
599 else
|
|
ferencd@0
|
600 maze_js << "var weapon_locations=[];\n"
|
|
ferencd@0
|
601 end
|
|
ferencd@0
|
602
|
|
ferencd@0
|
603 templated_maze = IO.binread(main_html)
|
|
ferencd@0
|
604 if $arrives.has_key? level_number
|
|
ferencd@0
|
605 templates_arrives = $arrives[level_number]
|
|
ferencd@0
|
606 else
|
|
ferencd@0
|
607 templates_arrives = $generic_arrives
|
|
ferencd@0
|
608 end
|
|
ferencd@0
|
609 complete_templates templates_arrives
|
|
ferencd@0
|
610
|
|
ferencd@0
|
611 templates_arrives[:gid] = "#{game_id}"
|
|
ferencd@0
|
612 templates_arrives[:lid] = "#{level_number}"
|
|
ferencd@0
|
613 templates_arrives[:page_loader] = 'upon_page_load();'
|
|
ferencd@0
|
614 # templates_arrives[:page_loader] = 'setup_labyrinth();' if game_type == GAME_TYPE_ADVENTURE or game_type == GAME_TYPE_MAZE
|
|
ferencd@0
|
615
|
|
ferencd@0
|
616 templates_arrives[:sysmenu_visible] = 'hidden;'
|
|
ferencd@0
|
617 templates_arrives[:sysmenu_display] = 'none;'
|
|
ferencd@0
|
618 templates_arrives[:menu_line_visible] = 'visible;'
|
|
ferencd@0
|
619
|
|
ferencd@0
|
620 level_statistics = "Level Number:#{level_number}\nExit at (#{exit_col}, #{exit_row}).\nDistance from (0,0) to (#{exit_col}, #{exit_row}) is #{full_path_len}"
|
|
ferencd@0
|
621
|
|
ferencd@0
|
622 templates_arrives[:badbrowser_visible] = 'hidden;'
|
|
ferencd@0
|
623 templates_arrives[:badbrowser_display] = 'none;'
|
|
ferencd@0
|
624 templates_arrives[:health_visible] = 'visible'
|
|
ferencd@0
|
625 templates_arrives[:statis_visible] = 'hidden'
|
|
ferencd@0
|
626 templates_arrives[:gameid_size] = '105px'
|
|
ferencd@0
|
627 templates_arrives[:gameid_visible] = 'visible'
|
|
ferencd@0
|
628 templates_arrives[:equipment_visible] = 'hidden'
|
|
ferencd@0
|
629 templates_arrives[:messages_visible] = 'hidden; display:none'
|
|
ferencd@0
|
630
|
|
ferencd@0
|
631 if game_type == GAME_TYPE_ADVENTURE
|
|
ferencd@0
|
632 templates_arrives[:gold_visible] = 'visible'
|
|
ferencd@0
|
633 templates_arrives[:skeletons_visible] = 'visible'
|
|
ferencd@0
|
634 templates_arrives[:levelctr_visible] = 'hidden; display:none'
|
|
ferencd@0
|
635 templates_arrives[:timer_visible] = 'visible'
|
|
ferencd@0
|
636 templates_arrives[:day_or_level] = 'Level'
|
|
ferencd@0
|
637 templates_arrives[:new_game_type] = 'new_adventure_game'
|
|
ferencd@0
|
638 level_statistics << "\nGold to be found in this dungeon: #{loot_value}\nSkeletons: #{walkers.length}\nSkeletons' acumen: Droidlike\n"
|
|
ferencd@0
|
639 level_statistics << "Boots of Lightness at #{shoe_distance} steps apart from the start\nRing of Health #{ring_distance} steps apart from the start"
|
|
ferencd@0
|
640
|
|
ferencd@0
|
641 else
|
|
ferencd@0
|
642 templates_arrives[:gold_visible] = 'hidden; display:none'
|
|
ferencd@0
|
643 templates_arrives[:skeletons_visible] = 'hidden; display:none'
|
|
ferencd@0
|
644 templates_arrives[:levelctr_visible] = 'visible'
|
|
ferencd@0
|
645 templates_arrives[:timer_visible] = 'hidden; display:none'
|
|
ferencd@0
|
646 templates_arrives[:new_game_type] = 'new_story_game'
|
|
ferencd@0
|
647 templates_arrives[:day_or_level] = 'Day'
|
|
ferencd@0
|
648
|
|
ferencd@0
|
649 if game_type == GAME_TYPE_MAZE
|
|
ferencd@0
|
650 templates_arrives[:levelctr_visible] = 'hidden; display:none'
|
|
ferencd@0
|
651 templates_arrives[:health_visible] = 'hidden; display:none'
|
|
ferencd@0
|
652 templates_arrives[:equipment_visible] = 'hidden; display:none'
|
|
ferencd@0
|
653 templates_arrives[:timer_visible] = 'visible'
|
|
ferencd@0
|
654 templates_arrives[:statis_visible] = 'visible'
|
|
ferencd@0
|
655 templates_arrives[:new_game_type] = 'new_timechaser_game'
|
|
ferencd@0
|
656 else
|
|
ferencd@0
|
657 templates_arrives[:messages_visible] = 'visible'
|
|
ferencd@0
|
658 end
|
|
ferencd@0
|
659
|
|
ferencd@0
|
660 end
|
|
ferencd@0
|
661
|
|
ferencd@0
|
662 templates_arrives[:story_game_loc] = Game.gen_game_url 'SG'
|
|
ferencd@0
|
663 templates_arrives[:adv_game_loc] = Game.gen_game_url 'AG'
|
|
ferencd@0
|
664 templates_arrives[:timer_game_loc] = Game.gen_game_url 'TG'
|
|
ferencd@0
|
665
|
|
ferencd@0
|
666 templates_arrives[:level_statistics] = level_statistics
|
|
ferencd@0
|
667
|
|
ferencd@0
|
668 full_maze = SimpleHtmlRenderer.render(templated_maze, templates_arrives)
|
|
ferencd@0
|
669 full_maze << '<script type="text/javascript">'
|
|
ferencd@0
|
670
|
|
ferencd@0
|
671
|
|
ferencd@0
|
672 gt = case game_type
|
|
ferencd@0
|
673 when GAME_TYPE_ADVENTURE then 'GAME_TYPE_ADVENTURE'
|
|
ferencd@0
|
674 when GAME_TYPE_STORY then 'GAME_TYPE_STORY'
|
|
ferencd@0
|
675 when GAME_TYPE_MAZE then 'GAME_TYPE_TIMERUN'
|
|
ferencd@0
|
676 else 'GAME_TYPE_TIMERUN'
|
|
ferencd@0
|
677 end
|
|
ferencd@0
|
678 javascripts = ''
|
|
ferencd@0
|
679
|
|
ferencd@0
|
680 javascripts << "const GAME_TYPE_ADVENTURE = 1;\nconst GAME_TYPE_STORY = 2;\nconst GAME_TYPE_TIMERUN = 3\n;var game_type=#{gt};\n"
|
|
ferencd@0
|
681
|
|
ferencd@0
|
682
|
|
ferencd@0
|
683 javascripts << maze_js
|
|
ferencd@0
|
684
|
|
ferencd@0
|
685 if game_type == GAME_TYPE_ADVENTURE
|
|
ferencd@0
|
686 templates_descends = $adventure_descend_summary
|
|
ferencd@0
|
687 else
|
|
ferencd@0
|
688 if game_type == GAME_TYPE_STORY
|
|
ferencd@0
|
689 if $descends.has_key? level_number
|
|
ferencd@0
|
690 templates_descends = $descends[level_number]
|
|
ferencd@0
|
691 else
|
|
ferencd@0
|
692 templates_descends = $generic_descends
|
|
ferencd@0
|
693 end
|
|
ferencd@0
|
694 else
|
|
ferencd@0
|
695 templates_descends = $timerun_descends
|
|
ferencd@0
|
696 end
|
|
ferencd@0
|
697 end
|
|
ferencd@0
|
698
|
|
ferencd@0
|
699 javascripts << "var story_text =\"#{templates_descends[:story_text]}\";\n"
|
|
ferencd@0
|
700 javascripts << "var leave_text =\"#{templates_descends[:leave_text]}\";\n"
|
|
ferencd@0
|
701
|
|
ferencd@0
|
702
|
|
ferencd@0
|
703 javascripts << '</script>'
|
|
ferencd@0
|
704
|
|
ferencd@0
|
705 # javascripts << '<script type="text/javascript" src="graphics.js"></script>'
|
|
ferencd@0
|
706 #
|
|
ferencd@0
|
707 # javascripts << '<script type="text/javascript" src="game.js"></script>'
|
|
ferencd@0
|
708
|
|
ferencd@0
|
709 # templated_game_js = IO.binread 'game.js'
|
|
ferencd@0
|
710 # game_js = SimpleHtmlRenderer.render(templated_game_js, templates_descends)
|
|
ferencd@0
|
711
|
|
ferencd@0
|
712 # javascripts << game_js
|
|
ferencd@0
|
713
|
|
ferencd@0
|
714 full_maze << javascripts
|
|
ferencd@0
|
715
|
|
ferencd@0
|
716 full_maze << 'request("graphics.js");</script></body></html>'
|
|
ferencd@0
|
717 retv = [full_maze]
|
|
ferencd@0
|
718
|
|
ferencd@0
|
719 return 200, retv
|
|
ferencd@0
|
720 end
|
|
ferencd@0
|
721
|
|
ferencd@0
|
722 #
|
|
ferencd@0
|
723 # Handles the root request. Creates a new maze number
|
|
ferencd@0
|
724 #
|
|
ferencd@0
|
725 def handle_root
|
|
ferencd@0
|
726 templated_maze = IO.binread(MAIN_HTML)
|
|
ferencd@0
|
727 templates_arrives = $generic_arrives
|
|
ferencd@0
|
728 complete_templates templates_arrives
|
|
ferencd@0
|
729
|
|
ferencd@0
|
730 templates_arrives[:gid] = ''
|
|
ferencd@0
|
731 templates_arrives[:lid] = ''
|
|
ferencd@0
|
732
|
|
ferencd@0
|
733 templates_arrives[:page_loader] = 'page_loader();'
|
|
ferencd@0
|
734
|
|
ferencd@0
|
735 templates_arrives[:sysmenu_visible] = 'visible;'
|
|
ferencd@0
|
736 templates_arrives[:sysmenu_display] = 'block;'
|
|
ferencd@0
|
737 templates_arrives[:menu_line_visible] = 'hidden;'
|
|
ferencd@0
|
738
|
|
ferencd@0
|
739 templates_arrives[:gameid_visible] = 'hidden'
|
|
ferencd@0
|
740 templates_arrives[:gold_visible] = 'hidden'
|
|
ferencd@0
|
741 templates_arrives[:skeletons_visible] = 'hidden'
|
|
ferencd@0
|
742 templates_arrives[:levelctr_visible] = 'hidden'
|
|
ferencd@0
|
743 templates_arrives[:health_visible] = 'hidden'
|
|
ferencd@0
|
744 templates_arrives[:timer_visible] = 'hidden'
|
|
ferencd@0
|
745 templates_arrives[:gameid_size] = '0px; padding:0'
|
|
ferencd@0
|
746 templates_arrives[:day_or_level] = 'Stage'
|
|
ferencd@0
|
747 templates_arrives[:level_statistics] = 'Nothing here yet'
|
|
ferencd@0
|
748 templates_arrives[:statis_visible] = 'hidden'
|
|
ferencd@0
|
749 templates_arrives[:equipment_visible] = 'hidden'
|
|
ferencd@0
|
750 templates_arrives[:new_game_type] = 'page_loader'
|
|
ferencd@0
|
751 templates_arrives[:messages_visible] = 'hidden'
|
|
ferencd@0
|
752
|
|
ferencd@0
|
753 templates_arrives[:badbrowser_visible] = 'hidden;'
|
|
ferencd@0
|
754 templates_arrives[:badbrowser_display] = 'none;'
|
|
ferencd@0
|
755
|
|
ferencd@0
|
756 templates_arrives[:story_game_loc] = Game.gen_game_url 'SG'
|
|
ferencd@0
|
757 templates_arrives[:adv_game_loc] = Game.gen_game_url 'AG'
|
|
ferencd@0
|
758 templates_arrives[:timer_game_loc] = Game.gen_game_url 'TG'
|
|
ferencd@0
|
759
|
|
ferencd@0
|
760 full_maze = SimpleHtmlRenderer.render(templated_maze, templates_arrives)
|
|
ferencd@0
|
761 full_maze << '</body></html>'
|
|
ferencd@0
|
762
|
|
ferencd@0
|
763 retv = [full_maze]
|
|
ferencd@0
|
764
|
|
ferencd@0
|
765 return 200, retv
|
|
ferencd@0
|
766 end
|
|
ferencd@0
|
767
|
|
ferencd@0
|
768 #
|
|
ferencd@0
|
769 # Delivers a file to the browser
|
|
ferencd@0
|
770 #
|
|
ferencd@0
|
771 def deliver_file(name)
|
|
ferencd@0
|
772
|
|
ferencd@0
|
773 code, content_type, retv = page_not_found
|
|
ferencd@0
|
774
|
|
ferencd@0
|
775 # Will read a file. Supposed to be on the same level as the script
|
|
ferencd@0
|
776 filename = name[1..-1]
|
|
ferencd@0
|
777 if File.exists?(filename)
|
|
ferencd@0
|
778
|
|
ferencd@0
|
779 extension = filename.partition('.').last
|
|
ferencd@0
|
780
|
|
ferencd@0
|
781 code = 200
|
|
ferencd@0
|
782 content_type = { CONTENT_TYPE => CONTENT_TYPES[extension] }
|
|
ferencd@0
|
783 retv = [ IO.binread(name.partition('/').last) ]
|
|
ferencd@0
|
784
|
|
ferencd@0
|
785 end
|
|
ferencd@0
|
786
|
|
ferencd@0
|
787 return code, content_type, retv
|
|
ferencd@0
|
788
|
|
ferencd@0
|
789 end
|
|
ferencd@0
|
790
|
|
ferencd@0
|
791 def handle_game_loader(loc)
|
|
ferencd@0
|
792
|
|
ferencd@0
|
793 begin
|
|
ferencd@0
|
794 key = loc[0..5]
|
|
ferencd@0
|
795 enced = loc[6..-1]
|
|
ferencd@0
|
796 deced = enced.decrypt key
|
|
ferencd@0
|
797 rescue
|
|
ferencd@0
|
798 deced = 'SG'
|
|
ferencd@0
|
799 end
|
|
ferencd@0
|
800 game_type = case deced
|
|
ferencd@0
|
801 when 'SG' then
|
|
ferencd@0
|
802 deced
|
|
ferencd@0
|
803 when 'AG' then
|
|
ferencd@0
|
804 deced
|
|
ferencd@0
|
805 when 'TG' then
|
|
ferencd@0
|
806 deced
|
|
ferencd@0
|
807 else
|
|
ferencd@0
|
808 'SG'
|
|
ferencd@0
|
809 end
|
|
ferencd@0
|
810 code, retv = Game.create_game game_type
|
|
ferencd@0
|
811 return code, retv
|
|
ferencd@0
|
812 end
|
|
ferencd@0
|
813
|
|
ferencd@0
|
814 def retrieve_game_id(request)
|
|
ferencd@0
|
815 gid = ''
|
|
ferencd@0
|
816 gid = request[:headers]['X-Extra'] if request[:headers].has_key? 'X-Extra'
|
|
ferencd@0
|
817 gid = gid.split('=')[1] if gid && gid.count('=') > 0
|
|
ferencd@0
|
818 gid
|
|
ferencd@0
|
819 end
|
|
ferencd@0
|
820
|
|
ferencd@0
|
821 def handle_next_level(gid)
|
|
ferencd@0
|
822
|
|
ferencd@0
|
823 # See where the player was
|
|
ferencd@0
|
824 level_nr = Database.get_db_level_for_gid gid
|
|
ferencd@0
|
825
|
|
ferencd@0
|
826 # Move him to the next level
|
|
ferencd@0
|
827 level_nr += 1
|
|
ferencd@0
|
828 Database.update_level_number_for_gid(level_nr, gid)
|
|
ferencd@0
|
829
|
|
ferencd@0
|
830 # And let's play that level
|
|
ferencd@0
|
831 code, retv = handle_maze_with_number(level_nr, gid, MAIN_HTML, GAME_TYPE_STORY)
|
|
ferencd@0
|
832
|
|
ferencd@0
|
833 return code, retv
|
|
ferencd@0
|
834 end
|
|
ferencd@0
|
835
|
|
ferencd@0
|
836 #
|
|
ferencd@0
|
837 # Each connection will get in here
|
|
ferencd@0
|
838 #
|
|
ferencd@0
|
839 Net::HTTP::Server.run(:port => 8180) do |request, _|
|
|
ferencd@0
|
840 begin
|
|
ferencd@0
|
841 url = request[:uri]
|
|
ferencd@0
|
842
|
|
ferencd@0
|
843 code, content_type, retv = page_not_found
|
|
ferencd@0
|
844
|
|
ferencd@0
|
845 lab_id = url[:path]
|
|
ferencd@0
|
846
|
|
ferencd@0
|
847 # pp lab_id
|
|
ferencd@0
|
848
|
|
ferencd@0
|
849 # what we are trying to load
|
|
ferencd@0
|
850 what = lab_id.to_s
|
|
ferencd@0
|
851
|
|
ferencd@0
|
852 # Handle favico
|
|
ferencd@0
|
853 if what == '/favicon.ico'
|
|
ferencd@0
|
854 code = 200
|
|
ferencd@0
|
855 content_type = {CONTENT_TYPE => 'image/x-icon'}
|
|
ferencd@0
|
856 retv = [ IO.binread('favicon.ico') ]
|
|
ferencd@0
|
857 end
|
|
ferencd@0
|
858
|
|
ferencd@0
|
859 # Nothing, just load the default, and create a new maze
|
|
ferencd@0
|
860 if what == '/'
|
|
ferencd@0
|
861 code, retv = handle_root
|
|
ferencd@0
|
862 elsif what != '/favicon.ico'
|
|
ferencd@0
|
863 # some file that needs to be delivered?
|
|
ferencd@0
|
864 if what.end_with?('.js') or what.end_with?('.png') or what.end_with?('.gif')
|
|
ferencd@0
|
865 code, content_type, retv = deliver_file(what)
|
|
ferencd@0
|
866 else
|
|
ferencd@0
|
867 # The actual location
|
|
ferencd@0
|
868 loc = what[1..-1]
|
|
ferencd@0
|
869
|
|
ferencd@0
|
870 # See if this is a gametype loader from the main screen, ie full hex string:
|
|
ferencd@0
|
871 if loc =~ /^[0-9A-F]+$/i and not loc.is_i?
|
|
ferencd@0
|
872 code, retv = handle_game_loader(loc)
|
|
ferencd@0
|
873 else
|
|
ferencd@0
|
874 # gid will be the Game ID of the current game if story mode, otherwise the adventure mode is selected for the
|
|
ferencd@0
|
875 # current maze
|
|
ferencd@0
|
876 gid = retrieve_game_id(request)
|
|
ferencd@0
|
877
|
|
ferencd@0
|
878 # Crazy locations will lead to random maze games
|
|
ferencd@0
|
879 if loc.length > 9
|
|
ferencd@0
|
880 loc = 'T' + Utils.random_string(8)
|
|
ferencd@0
|
881 end
|
|
ferencd@0
|
882 if gid == loc
|
|
ferencd@0
|
883 # The player advanced to the next level from the game, we have a valid gid equaling the location of the window
|
|
ferencd@0
|
884 code, retv = handle_next_level(gid)
|
|
ferencd@0
|
885 elsif loc.is_i?
|
|
ferencd@0
|
886 # We get here by a simple "GET" from the browser URL, someone just wants to play a maze game
|
|
ferencd@0
|
887 # Now update in the DB the level number for gid
|
|
ferencd@0
|
888 code, retv = handle_maze_with_number(loc.to_i, gid, MAIN_HTML, GAME_TYPE_MAZE)
|
|
ferencd@0
|
889 elsif loc.length > 0 and (loc[0] == 'S' or loc[0] == 'A' or loc[0] == 'T')
|
|
ferencd@0
|
890 level_number = Database.get_db_level_for_gid(loc)
|
|
ferencd@0
|
891 if level_number == -1
|
|
ferencd@0
|
892 level_number = Zlib::crc32(loc, 0)
|
|
ferencd@0
|
893 end
|
|
ferencd@0
|
894 code, retv = handle_maze_with_number(level_number, loc,
|
|
ferencd@0
|
895 MAIN_HTML,
|
|
ferencd@0
|
896 if loc[0] == 'S' then GAME_TYPE_STORY elsif loc[0] == 'T' then GAME_TYPE_MAZE
|
|
ferencd@0
|
897 else GAME_TYPE_ADVENTURE end
|
|
ferencd@0
|
898 )
|
|
ferencd@0
|
899
|
|
ferencd@0
|
900 end
|
|
ferencd@0
|
901 end
|
|
ferencd@0
|
902 end
|
|
ferencd@0
|
903 end
|
|
ferencd@0
|
904 rescue => ex
|
|
ferencd@0
|
905 $LOG.fatal("A Somewhat critical error: #{ex.to_s}")
|
|
ferencd@0
|
906 code, content_type, retv = internal_server_error
|
|
ferencd@0
|
907 raise
|
|
ferencd@0
|
908 end
|
|
ferencd@0
|
909
|
|
ferencd@0
|
910 # This will go back to the caller
|
|
ferencd@0
|
911 reply = [code, content_type, retv]
|
|
ferencd@0
|
912 reply
|
|
ferencd@0
|
913
|
|
ferencd@0
|
914 end
|
|
ferencd@0
|
915
|