gambit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. data/AUTHORS +2 -0
  2. data/CHANGELOG +7 -0
  3. data/COPYING +340 -0
  4. data/INSTALL +23 -0
  5. data/LICENSE +7 -0
  6. data/README +25 -0
  7. data/Rakefile +87 -0
  8. data/TODO +6 -0
  9. data/examples/bird_wars/game.rb +434 -0
  10. data/examples/bird_wars/html/chest.rhtml +37 -0
  11. data/examples/bird_wars/html/combat.rhtml +38 -0
  12. data/examples/bird_wars/html/fight.rhtml +71 -0
  13. data/examples/bird_wars/html/fridge.rhtml +31 -0
  14. data/examples/bird_wars/html/help.rhtml +30 -0
  15. data/examples/bird_wars/html/house.rhtml +36 -0
  16. data/examples/bird_wars/html/images/albatross.jpg +0 -0
  17. data/examples/bird_wars/html/images/alka_seltzer_small.png +0 -0
  18. data/examples/bird_wars/html/images/bazooka_small.png +0 -0
  19. data/examples/bird_wars/html/images/bb_gun_small.png +0 -0
  20. data/examples/bird_wars/html/images/cat_small.png +0 -0
  21. data/examples/bird_wars/html/images/combat.png +0 -0
  22. data/examples/bird_wars/html/images/crossbow_small.png +0 -0
  23. data/examples/bird_wars/html/images/cuckoo.jpg +0 -0
  24. data/examples/bird_wars/html/images/fridge.png +0 -0
  25. data/examples/bird_wars/html/images/gull.jpg +0 -0
  26. data/examples/bird_wars/html/images/house.jpg +0 -0
  27. data/examples/bird_wars/html/images/items.png +0 -0
  28. data/examples/bird_wars/html/images/not_found.png +0 -0
  29. data/examples/bird_wars/html/images/note.jpg +0 -0
  30. data/examples/bird_wars/html/images/oil_small.png +0 -0
  31. data/examples/bird_wars/html/images/one_stone_small.png +0 -0
  32. data/examples/bird_wars/html/images/owl.jpg +0 -0
  33. data/examples/bird_wars/html/images/poisoned_seeds_small.png +0 -0
  34. data/examples/bird_wars/html/images/rice_small.png +0 -0
  35. data/examples/bird_wars/html/images/shotgun_small.png +0 -0
  36. data/examples/bird_wars/html/images/slingshot_small.png +0 -0
  37. data/examples/bird_wars/html/images/soda_rings_small.png +0 -0
  38. data/examples/bird_wars/html/images/spear_small.png +0 -0
  39. data/examples/bird_wars/html/images/stork.jpg +0 -0
  40. data/examples/bird_wars/html/images/weapons.png +0 -0
  41. data/examples/bird_wars/html/images/woodpecker.jpg +0 -0
  42. data/examples/bird_wars/html/images/you.jpg +0 -0
  43. data/examples/bird_wars/html/index.rhtml +13 -0
  44. data/examples/bird_wars/html/weapons.rhtml +35 -0
  45. data/examples/cli/blackjack.rb +86 -0
  46. data/examples/cli/go.rb +93 -0
  47. data/examples/cli/space_trader2/planet_data +12280 -0
  48. data/examples/cli/space_trader2/space_trader2.rb +248 -0
  49. data/examples/cli/space_trader2/world.rb +127 -0
  50. data/examples/cli/spacetrader.rb +262 -0
  51. data/examples/cli/yahtzee.rb +161 -0
  52. data/examples/galactic_courier/Rakefile +9 -0
  53. data/examples/galactic_courier/bin/galactic_courier.rb +44 -0
  54. data/examples/galactic_courier/html/console.rhtml +15 -0
  55. data/examples/galactic_courier/html/images/barren.jpg +0 -0
  56. data/examples/galactic_courier/html/images/industrial.jpg +0 -0
  57. data/examples/galactic_courier/html/images/jungle.jpg +0 -0
  58. data/examples/galactic_courier/html/images/oceanic.jpg +0 -0
  59. data/examples/galactic_courier/html/images/tundra.jpg +0 -0
  60. data/examples/galactic_courier/html/images/volcanic.jpg +0 -0
  61. data/examples/galactic_courier/lib/galaxy.rb +64 -0
  62. data/examples/galactic_courier/lib/planet.rb +30 -0
  63. data/examples/galactic_courier/lib/sector.rb +84 -0
  64. data/examples/galactic_courier/lib/station.rb +18 -0
  65. data/examples/galactic_courier/test/tc_galaxy.rb +24 -0
  66. data/examples/galactic_courier/test/tc_planet.rb +22 -0
  67. data/examples/galactic_courier/test/tc_sector.rb +55 -0
  68. data/examples/galactic_courier/test/ts_all.rb +12 -0
  69. data/examples/gambit_mail/html/compose.rhtml +39 -0
  70. data/examples/gambit_mail/html/index.rhtml +3 -0
  71. data/examples/gambit_mail/html/mailbox.rhtml +47 -0
  72. data/examples/gambit_mail/html/message.rhtml +34 -0
  73. data/examples/gambit_mail/mail.rb +75 -0
  74. data/lib/gambit.rb +10 -0
  75. data/lib/gambit/server.rb +269 -0
  76. data/lib/gambit/server/gambiterror.rb +28 -0
  77. data/lib/gambit/server/game.rb +185 -0
  78. data/lib/gambit/server/game/eventform.rb +174 -0
  79. data/lib/gambit/server/message.rb +85 -0
  80. data/lib/gambit/server/player.rb +40 -0
  81. data/lib/gambit/tools.rb +13 -0
  82. data/lib/gambit/tools/board.rb +275 -0
  83. data/lib/gambit/tools/cards.rb +11 -0
  84. data/lib/gambit/tools/cards/card.rb +158 -0
  85. data/lib/gambit/tools/cards/deck.rb +99 -0
  86. data/lib/gambit/tools/cards/hand.rb +86 -0
  87. data/lib/gambit/tools/cards/pile.rb +107 -0
  88. data/lib/gambit/tools/currency.rb +148 -0
  89. data/lib/gambit/tools/dice.rb +219 -0
  90. data/lib/gambit/tools/movehistory.rb +164 -0
  91. data/lib/gambit/tools/scorecard.rb +333 -0
  92. data/lib/gambit/viewable.rb +71 -0
  93. data/setup.rb +1360 -0
  94. data/test/tc_board.rb +167 -0
  95. data/test/tc_cards.rb +182 -0
  96. data/test/tc_currency.rb +99 -0
  97. data/test/tc_dice.rb +83 -0
  98. data/test/tc_error.rb +34 -0
  99. data/test/tc_event.rb +367 -0
  100. data/test/tc_game.rb +29 -0
  101. data/test/tc_message.rb +35 -0
  102. data/test/tc_movehistory.rb +38 -0
  103. data/test/tc_player.rb +60 -0
  104. data/test/tc_scorecard.rb +112 -0
  105. data/test/tc_views.rb +353 -0
  106. data/test/test_game.rb +19 -0
  107. data/test/test_view.rhtml +2 -0
  108. data/test/ts_all.rb +12 -0
  109. data/test/ts_server.rb +14 -0
  110. data/test/ts_tools.rb +14 -0
  111. metadata +183 -0
@@ -0,0 +1,22 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_planet.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-06-06.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "planet"
11
+
12
+ class TestPlanet < Test::Unit::TestCase
13
+ def test_creation
14
+ assert_not_nil(planet = Planet.new(:volcanic))
15
+ assert_equal(:volcanic, planet.type)
16
+
17
+ assert_not_nil(planet = Planet.random)
18
+ assert_instance_of(Planet, planet)
19
+ assert( [ :volcanic, :tundra, :oceanic,
20
+ :jungle, :industrial, :barren ].include?(planet.type) )
21
+ end
22
+ end
@@ -0,0 +1,55 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_sector.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-06-06.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "sector"
11
+ require "planet"
12
+ require "station"
13
+
14
+ class TestSector < Test::Unit::TestCase
15
+ def test_creation
16
+ assert_not_nil(sector = Sector.new(:black_hole))
17
+ assert_equal(:black_hole, sector.feature)
18
+ assert_same(sector, sector.create_planet(Planet.new(:tundra)))
19
+ 4.times { assert_same(sector, sector << Planet.new(:jungle)) }
20
+ assert_raise(RuntimeError) { sector << Planet.new(:jungle) }
21
+ assert_equal(:tundra, sector[0].type)
22
+ assert_equal(:jungle, sector[rand(4) + 1].type)
23
+ assert_not_nil(sector.build_station(Station.random))
24
+ assert_raise(RuntimeError) { sector.build_station(Station.random) }
25
+ assert_equal(5, sector.size)
26
+
27
+ assert_not_nil(sector = Sector.random)
28
+ assert_instance_of(Sector, sector)
29
+ assert( [ :none, :nebula,
30
+ :asteroids, :black_hole ].include?(sector.feature) )
31
+ assert(sector.size >= 0)
32
+ assert(sector.size <= 5)
33
+ end
34
+
35
+ def test_linking
36
+ sectors = [Sector.random]
37
+ 2.times { sectors << Sector.random }
38
+ sectors.each_with_index { |sec, index| sec.name = index + 1 }
39
+ sectors.each { |sec| assert_equal(0, sec.links.size) }
40
+ sectors.first.link(sectors.last)
41
+ assert_equal(1, sectors.first.links.size)
42
+ assert_equal(1, sectors.last.links.size)
43
+ assert_equal(3, sectors.first.links.first.name)
44
+ assert_equal(1, sectors.last.links.first.name)
45
+
46
+ sectors[0].link(sectors[1], true)
47
+ sectors[1].link(sectors[2], true)
48
+ assert_equal(2, sectors[0].links.size)
49
+ assert_equal(1, sectors[1].links.size)
50
+ assert_equal(1, sectors[2].links.size)
51
+ assert_equal([3, 2], sectors[0].links.map { |sec| sec.name })
52
+ assert_equal([3], sectors[1].links.map { |sec| sec.name })
53
+ assert_equal([1], sectors[2].links.map { |sec| sec.name })
54
+ end
55
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # ts_all.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-06-06.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "tc_planet"
11
+ require "tc_sector"
12
+ require "tc_galaxy"
@@ -0,0 +1,39 @@
1
+ <html>
2
+ <head>
3
+ <title>Compose Mail</title>
4
+ <style> #Message { height: 300px; width: 400px; border: 2px solid; }
5
+ .event p { margin: 0 0 0 350; }
6
+ #To { margin: 0 20 0 36; border: 2px solid;
7
+ padding: 2px; }
8
+ #Subject { margin: 2 0 0 8; width: 400px; border: 2px solid;
9
+ padding: 2px; }
10
+ form dd {
11
+ margin: 5;
12
+ }
13
+
14
+ form dt {
15
+ float: left;
16
+ padding-right = 10px;
17
+ }
18
+
19
+ label { margin: 0 4 0 0; }
20
+ </style>
21
+ </head>
22
+ <body>
23
+ <%message = @message ||
24
+ Gambit::Server::Message.new(@player.name,"","","") %>
25
+ <% player = @player %>
26
+ <%= event(nil,"send_message") do
27
+ if message.to.eql?("")
28
+ menu "To", Gambit::Server::SERVER.players.keys - [player.name]
29
+ else
30
+ menu "To", message.to
31
+ end
32
+ hidden "From", message.from
33
+ text "Subject", "value" => message.subject
34
+ document "Message"
35
+ submit "Send"
36
+ end %>
37
+ </body>
38
+ </html>
39
+
@@ -0,0 +1,3 @@
1
+ <html><head><title>Mail System</title></head><body>
2
+ <%= event("Spam me!", "spam") %></body></html>
3
+
@@ -0,0 +1,47 @@
1
+ <html>
2
+ <head>
3
+ <title>Mailbox</title>
4
+ <style type="Text/CSS">
5
+ .message_short { padding: 2px; margin: 0px; width: 900px;}
6
+ .message_short li { list-style-type: none;
7
+ float: left;
8
+ border: 1px solid; padding: 0px 20px 0px 20px;}
9
+ .from_short { width: 200px; background-color: #dddddd; }
10
+ .subject_short { width: 200px; background-color: #eeeeee; }
11
+ .time_short { background-color: #dddddd; width: 275px; }
12
+ #mailbox_header_from { width: 200px; background-color: #f8f7d1 }
13
+ #mailbox_header_subject { width: 200px; background-color: #f8f7d1 }
14
+ #mailbox_header_time { width: 275px; background-color: #f8f7d1 }
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <% @message = nil %>
19
+ <ul class="message_short">
20
+ <li id="mailbox_header_from">
21
+ <%= event("Sender","sort","sort_by" => "sender") %>
22
+ </li>
23
+ <li id="mailbox_header_subject">
24
+ <%= event("Subject","sort","sort_by" => "subject") %>
25
+ </li>
26
+ <li id="mailbox_header_time">
27
+ <%= event("Time","sort","sort_by" => "time") %>
28
+ </li>
29
+ </ul>
30
+ <% @player.mailbox.each do |mes| %>
31
+ <ul class="message_short">
32
+ <li class="from_short"> <%= mes.from %> </li>
33
+ <li class="subject_short">
34
+ <%= event(mes.subject, "show_message",
35
+ "id" => mes.object_id) %>
36
+ </li>
37
+ <li class="time_short"> <%= mes.time %> </li>
38
+ </ul>
39
+ <% end %>
40
+ <p style="clear: both; margin: 0 20 20 520;">
41
+ <br>
42
+ <a href="compose.rhtml"> Compose</a> |
43
+ <%= event("Delete All Messages", "delete_all") %>
44
+ </p>
45
+ </body>
46
+ </html>
47
+
@@ -0,0 +1,34 @@
1
+ <html>
2
+ <head>
3
+ <title>Mailbox</title>
4
+ <style type="Text/CSS">
5
+ .message { border: 1px ; width: 400px; }
6
+ .message td { border: 2px solid; padding: 4px }
7
+ a { text-decoration: none; color : #000000; }
8
+ ul { padding: 0 0 0 100; }
9
+ li { float: left; padding: 2 5 2 5; list-style: none;
10
+ border: 1px solid }
11
+ #time { text-align: center; background-color: #ffffff;}
12
+ #from { width: 50%; text-align: center; background-color: #cccccc;
13
+ vertical-align: top; }
14
+ #to { width: 50%; text-align: center; background-color: #cccccc;
15
+ vertical-align: top;}
16
+ #subject { text-align: center; background-color: #dddddd; }
17
+ #body { background-color: #aaaaaa; padding: 8px}
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <%= @message.view(:gambit_html) %>
22
+ <ul>
23
+ <li>
24
+ <%= event("reply", "reply",
25
+ "id" => @message.object_id) %>
26
+ </li>
27
+ <li>
28
+ <%= event("delete","delete_message",
29
+ "id" => @message.object_id) %>
30
+ </li>
31
+ <li><a href="mailbox.rhtml">Return to mailbox</a></li>
32
+ </ul>
33
+ </body>
34
+ </html>
@@ -0,0 +1,75 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # mail.rb
4
+ #
5
+ # Created by Gregory Brown on 22005-06-05
6
+ # Copyright 2005 smtose.org. All rights reserved.
7
+
8
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "..", "lib"))
9
+ require "gambit"
10
+ require "gambit/server/message"
11
+
12
+ class Mail< Gambit::Server::Game
13
+ def initialize( )
14
+ super
15
+ end
16
+
17
+ def do_login( player, details )
18
+ "mailbox.rhtml"
19
+ end
20
+
21
+ def do_show_message( player, details )
22
+ @message = get_message(details["id"])
23
+ "message.rhtml"
24
+ end
25
+
26
+ def do_delete_message( player, details )
27
+ player.mailbox.delete(get_message(details["id"]))
28
+ "mailbox.rhtml"
29
+ end
30
+
31
+ def do_sort( player, details )
32
+ sort_by = details["sort_by"]
33
+ case sort_by
34
+ when("sender")
35
+ @player.mailbox.sort! { |a,b| a.from <=> b.from }
36
+ when("subject")
37
+ @player.mailbox.sort! { |a,b| a.subject <=> b.subject }
38
+ when("time")
39
+ @player.mailbox.sort! { |a,b| a.time <=> b.time }
40
+ end
41
+ "mailbox.rhtml"
42
+ end
43
+
44
+ def do_reply( player, details )
45
+ message = get_message(details["id"])
46
+ @message = Gambit::Server::Message.new(message.to, message.from,
47
+ "RE: " + message.subject,"")
48
+ return "compose.rhtml"
49
+ end
50
+
51
+ def do_send_message( player, details )
52
+ Gambit::Server::SERVER.players[details["To"]].mailbox <<
53
+ Gambit::Server::Message.new( details["From"],
54
+ details["To"],
55
+ details["Subject"],
56
+ details["Message"] )
57
+ return "mailbox.rhtml"
58
+ end
59
+
60
+ def do_delete_all( player, details )
61
+ player.mailbox.clear
62
+ return "mailbox.rhtml"
63
+ end
64
+
65
+ def do_configure(player, details)
66
+ super
67
+ return "mailbox.rhtml"
68
+ end
69
+
70
+ private
71
+
72
+ def get_message( id )
73
+ @player.mailbox.find { |m| m.object_id == id.to_i }
74
+ end
75
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # gambit.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-06-04.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+
8
+ require "gambit/tools"
9
+ require "gambit/viewable"
10
+ require "gambit/server"
@@ -0,0 +1,269 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # server.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-06-03.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+
8
+ require "webrick"
9
+ require "erb"
10
+ require "monitor"
11
+ require "gambit/server/gambiterror"
12
+ require "gambit/server/game"
13
+ require "gambit/server/player"
14
+ require "gambit/viewable"
15
+
16
+ module Gambit
17
+ # The controller layer of the Gambit framework. (Docs coming soon...)
18
+ class Server < WEBrick::HTTPServer
19
+ include Gambit::Viewable
20
+ register_view(:game_listing, <<-END_GAME_LIST.gsub(/^\t{2}/, ""))
21
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
22
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
23
+ <html xmlns="http://www.w3.org/1999/xhtml">
24
+ <head>
25
+ <title>Game List</title>
26
+ </head><body>
27
+ <h1>Select a Game</h1>
28
+ % unless @server_message.nil?
29
+ <p class="notification"><%= @server_message %></p>
30
+ % @server_message = nil
31
+ % end
32
+ <ul>
33
+ % @games.each do |(id, game)|
34
+ <li><a href="/event/<%= id %>/login"><%= game.name %></a></li>
35
+ % end
36
+ </ul>
37
+ <p><a href="/server/new_game">Add a Game!</a>
38
+ <a href="/server/new_player">Create a Player!</a></p>
39
+ </body></html>
40
+ END_GAME_LIST
41
+ register_view(:new_player, <<-END_GAME_LIST.gsub(/^\t{2}/, ""))
42
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
43
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
44
+ <html xmlns="http://www.w3.org/1999/xhtml">
45
+ <head>
46
+ <title>New Player</title>
47
+ </head><body>
48
+ <h1>Create Your Player</h1>
49
+ % unless @server_message.nil?
50
+ <p class="notification"><%= @server_message %></p>
51
+ % @server_message = nil
52
+ % end
53
+ <form action="/server/create_player" method="post">
54
+ <dl>
55
+ <dt><label for="name">Name:</label></dt>
56
+ <dd><input type="text" id="name" name="name" /></dd>
57
+ <dt><label for="password">Password:</label></dt>
58
+ <dd><input type="password" id="password" name="password" /></dd>
59
+ <dt><label for="verify">Verify Password:</label></dt>
60
+ <dd><input type="password" id="verify" name="verify" /></dd>
61
+ </dl>
62
+ <p><input type="submit" value="Create" /> <input type="reset" /></p>
63
+ </form>
64
+ </body></html>
65
+ END_GAME_LIST
66
+
67
+ include MonitorMixin
68
+
69
+ def initialize( game_class,
70
+ port = 80, html_dir = "html", become_daemon = false )
71
+ super(:Port => port)
72
+
73
+ @html_dir = File.join(File.expand_path(File.dirname($0)), html_dir)
74
+ self.class.const_set(:SERVER, self)
75
+ @server_message = nil
76
+
77
+ @game_class = game_class
78
+ @games = Hash.new
79
+ @players = Hash.new
80
+
81
+ WEBrick::Daemon.start if become_daemon
82
+
83
+ mount_proc("/") { |req, resp| serve_file(req, resp, req.path) }
84
+ mount_proc("/view") { |req, resp| serve_view(req, resp) }
85
+ mount_proc("/event") { |req, resp| serve_event(req, resp) }
86
+ mount_proc("/server") { |req, resp| serve_server_event(req, resp) }
87
+
88
+ ['INT', 'TERM'].each { |signal| trap(signal) { shutdown } }
89
+ end
90
+
91
+ attr_reader :players
92
+
93
+ def login( req, resp, game, event = nil )
94
+ if cookie = req.cookies.find { |c| c.name == "player" }
95
+ cookie.expires = nil # defaults to end of session
96
+ resp.cookies << cookie
97
+ cookie.path = "/"
98
+ @players[cookie.value]
99
+ elsif (event == "login") and
100
+ not (req.query["login"].nil? or req.query["login"].empty?)
101
+ if player = @players[req.query["login"]]
102
+ if player.login?(req.query["password"])
103
+ cookie = WEBrick::Cookie.new( "player",
104
+ req.query["login"] )
105
+ cookie.expires = nil # defaults to end of session
106
+ resp.cookies << cookie
107
+ cookie.path = "/"
108
+
109
+ @players[cookie.value]
110
+ else
111
+ raise Gambit::Server::GambitError, "Invalid password."
112
+ end
113
+ else
114
+ raise Gambit::Server::GambitError, "Unknown name."
115
+ end
116
+ else
117
+ resp.body = game.view(:login)
118
+ raise WEBrick::HTTPStatus::OK
119
+ end
120
+ end
121
+
122
+ def serve_event( req, resp )
123
+ begin
124
+ if req.path =~ %r{/event/([^/]+)/([^/]+)}
125
+ game_name = $1.to_i
126
+ event_name = $2
127
+
128
+ if @games[game_name].nil?
129
+ raise Gambit::Server::GambitError, "Game not found!"
130
+ else
131
+ player = login( req, resp,
132
+ @games[game_name], event_name )
133
+ next_page = nil
134
+ synchronize do
135
+ next_page = @games[game_name].do_event( player,
136
+ event_name,
137
+ req.query )
138
+ end
139
+
140
+ if cookie = req.cookies.find { |c| c.name == "player" }
141
+ resp.cookies << cookie
142
+ end
143
+ resp.set_redirect( WEBrick::HTTPStatus::SeeOther,
144
+ "/view/#{game_name}/#{next_page}" )
145
+ raise WEBrick::HTTPStatus::SeeOther
146
+ end
147
+ else
148
+ raise Gambit::Server::GambitError, "Malformed Event!"
149
+ end
150
+ rescue Gambit::Server::GambitError => error
151
+ resp.body = error.view(:error_page)
152
+ raise WEBrick::HTTPStatus::OK
153
+ end
154
+ end
155
+
156
+ def serve_server_event( req, resp )
157
+ if req.path == "/server/new_game"
158
+ game = @game_class.new
159
+ if not @players.empty?
160
+ @games[game.object_id] = game
161
+ resp.body = game.view(:configure)
162
+ else
163
+ @server_message = "No users!"
164
+ resp.body = view(:game_listing)
165
+ end
166
+ raise WEBrick::HTTPStatus::OK
167
+ elsif req.path == "/server/new_player"
168
+ resp.body = view(:new_player)
169
+ raise WEBrick::HTTPStatus::OK
170
+ elsif req.path == "/server/create_player"
171
+ if @players.include?(req.query["name"])
172
+ @server_message = "Sorry, that name is taken."
173
+ resp.body = view(:new_player)
174
+ raise WEBrick::HTTPStatus::OK
175
+ elsif req.query["password"] != req.query["verify"]
176
+ @server_message = "The provided passwords do not match."
177
+ resp.body = view(:new_player)
178
+ raise WEBrick::HTTPStatus::OK
179
+ else
180
+ @server_message = "Player created."
181
+ @players[req.query["name"]] =
182
+ Gambit::Server::Player.new( req.query["name"],
183
+ req.query["password"] )
184
+ cookie = WEBrick::Cookie.new( "player",
185
+ req.query["name"] )
186
+ cookie.expires = nil # defaults to end of session
187
+ resp.cookies << cookie
188
+ cookie.path = "/"
189
+
190
+ resp.body = view(:game_listing)
191
+ raise WEBrick::HTTPStatus::OK
192
+ end
193
+ elsif req.path == "/server/test"
194
+ test_mode
195
+
196
+ cookie = WEBrick::Cookie.new("player", "tester")
197
+ cookie.expires = nil # defaults to end of session
198
+ resp.cookies << cookie
199
+ cookie.path = "/"
200
+
201
+ resp.body = view(:game_listing)
202
+ raise WEBrick::HTTPStatus::OK
203
+ else
204
+ resp.body = view(:game_listing)
205
+ raise WEBrick::HTTPStatus::OK
206
+ end
207
+ end
208
+
209
+ def serve_file( req, resp, file )
210
+ if file == "/"
211
+ resp.body = view(:game_listing)
212
+ raise WEBrick::HTTPStatus::OK
213
+ end
214
+
215
+ stats = File::stat(file)
216
+ mtime = stats.mtime
217
+ resp["etag"] = sprintf( "%x-%x-%x", stats.ino, stats.size,
218
+ stats.mtime.to_i )
219
+ mtype = WEBrick::HTTPUtils::mime_type(file, self[:MimeTypes])
220
+ resp["content-type"] = mtype
221
+ resp["content-length"] = stats.size
222
+ resp["last-modified"] = mtime.httpdate
223
+ resp.body = File.open(file, "rb")
224
+ raise WEBrick::HTTPStatus::OK
225
+ end
226
+
227
+ def serve_view( req, resp )
228
+ begin
229
+ if req.path =~ %r{/view/([^/]+)/(.+)}
230
+ game_name = $1.to_i
231
+ view_file = $2
232
+
233
+ erb_file = File.join(@html_dir, view_file)
234
+
235
+ if test(?e, erb_file)
236
+ player = login(req, resp, @games[game_name])
237
+ @games[game_name].player = player
238
+
239
+ if File.extname(erb_file) == ".rhtml"
240
+ erb_page = ERB.new( File.read(erb_file),
241
+ nil, "%<>" )
242
+ resp.body = erb_page.result(
243
+ @games[game_name].event_binding )
244
+ raise WEBrick::HTTPStatus::OK
245
+ else
246
+ serve_file(req, resp, erb_file)
247
+ end
248
+ else
249
+ raise Gambit::Server::GambitError, "View not found!"
250
+ end
251
+ else
252
+ raise Gambit::Server::GambitError, "Malformed View!"
253
+ end
254
+ rescue Gambit::Server::GambitError => error
255
+ resp.body = error.view(:error_page)
256
+ raise WEBrick::HTTPStatus::OK
257
+ end
258
+ end
259
+
260
+ def test_mode( )
261
+ game = @game_class.new
262
+ @games[game.object_id] = game
263
+ game.do_configure(nil, "game_name" => "Test Mode Game")
264
+ @players["tester"] = Gambit::Server::Player.new( "tester",
265
+ "test" )
266
+ @server_message = "Test mode active."
267
+ end
268
+ end
269
+ end