alchemist-server 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +5 -0
  3. data/README.md +118 -0
  4. data/Rakefile +1 -0
  5. data/alchemist-server.gemspec +29 -0
  6. data/bin/alchemist-repl +37 -0
  7. data/bin/alchemist-server +10 -0
  8. data/lib/alchemist-server.rb +151 -0
  9. data/lib/alchemist-server/avatar.rb +82 -0
  10. data/lib/alchemist-server/commands/appear.rb +13 -0
  11. data/lib/alchemist-server/commands/base.rb +31 -0
  12. data/lib/alchemist-server/commands/basics.rb +12 -0
  13. data/lib/alchemist-server/commands/compounds.rb +13 -0
  14. data/lib/alchemist-server/commands/create.rb +15 -0
  15. data/lib/alchemist-server/commands/describe.rb +18 -0
  16. data/lib/alchemist-server/commands/directions.rb +48 -0
  17. data/lib/alchemist-server/commands/element.rb +16 -0
  18. data/lib/alchemist-server/commands/forge.rb +18 -0
  19. data/lib/alchemist-server/commands/formulate.rb +20 -0
  20. data/lib/alchemist-server/commands/inventory.rb +12 -0
  21. data/lib/alchemist-server/commands/location.rb +13 -0
  22. data/lib/alchemist-server/commands/lock.rb +12 -0
  23. data/lib/alchemist-server/commands/look.rb +14 -0
  24. data/lib/alchemist-server/commands/message.rb +15 -0
  25. data/lib/alchemist-server/commands/put.rb +16 -0
  26. data/lib/alchemist-server/commands/read.rb +18 -0
  27. data/lib/alchemist-server/commands/take.rb +17 -0
  28. data/lib/alchemist-server/commands/who.rb +18 -0
  29. data/lib/alchemist-server/curses/geography_window.rb +63 -0
  30. data/lib/alchemist-server/curses/glyph_window.rb +89 -0
  31. data/lib/alchemist-server/curses/item_window.rb +59 -0
  32. data/lib/alchemist-server/curses/messages_window.rb +43 -0
  33. data/lib/alchemist-server/curses/prompt_window.rb +35 -0
  34. data/lib/alchemist-server/direction.rb +28 -0
  35. data/lib/alchemist-server/element.rb +14 -0
  36. data/lib/alchemist-server/event.rb +43 -0
  37. data/lib/alchemist-server/formula.rb +24 -0
  38. data/lib/alchemist-server/geography.rb +111 -0
  39. data/lib/alchemist-server/outcome.rb +12 -0
  40. data/lib/alchemist-server/record.rb +51 -0
  41. data/lib/alchemist-server/server_handler.rb +143 -0
  42. data/lib/alchemist-server/version.rb +8 -0
  43. data/lib/alchemist-server/world.rb +206 -0
  44. data/lib/alchemist-server/world_history.rb +45 -0
  45. data/script/alchemist-curses +307 -0
  46. metadata +148 -0
@@ -0,0 +1,13 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Appear < Base
4
+ pattern "app(ear)?"
5
+
6
+ def run
7
+ outcome "appeared",
8
+ history.world.new_avatar(avatar_name),
9
+ Commands::Who
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,31 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Base
4
+ def self.pattern(arg = nil)
5
+ if arg
6
+ @pattern = arg
7
+ end
8
+
9
+ @pattern
10
+ end
11
+
12
+ attr_reader :avatar_name, :history
13
+
14
+ def initialize(avatar_name, history)
15
+ @avatar_name = avatar_name
16
+ @history = history
17
+ end
18
+
19
+ def outcome(response = nil, new_world = nil, command = nil)
20
+ Outcome.new response: response,
21
+ new_world: new_world,
22
+ nearby_avatar_command: command
23
+ end
24
+
25
+ def self.run(avatar_name, history, *args)
26
+ new(avatar_name, history).run *args
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,12 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Basics < Base
4
+ pattern "basics"
5
+
6
+ def run
7
+ elements = history.world.basic_elements
8
+ outcome "basics #{elements.map(&:symbol).join('')}"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Compounds < Base
4
+ pattern "compounds"
5
+
6
+ def run
7
+ elements = history.world.compound_elements
8
+ outcome "compounds #{elements.map(&:symbol).join('')}"
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,15 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Create < Base
4
+ pattern "create"
5
+
6
+ def run(resource)
7
+ world = history.world.create avatar_name, resource
8
+ a = world.avatar avatar_name
9
+
10
+ outcome "inventory #{a.try :inventory}", world
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,18 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Describe < Base
4
+ pattern "describe"
5
+
6
+ def run(symbol)
7
+ element = history.world.element symbol
8
+
9
+ if element
10
+ outcome "element #{element.symbol} #{element.name} #{element.hex_code}"
11
+ else
12
+ outcome "noelement #{symbol}"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,48 @@
1
+ module Alchemist
2
+ module Commands
3
+ class DirectionCommand < Base
4
+ def run
5
+ world = history.world.move avatar_name, direction
6
+ x, y = world.location avatar_name
7
+
8
+ outcome "location #{x} #{y}",
9
+ world,
10
+ Commands::Who
11
+ end
12
+ end
13
+
14
+ class North < DirectionCommand
15
+ pattern 'north'
16
+
17
+ def direction
18
+ Direction::North
19
+ end
20
+ end
21
+
22
+ class South < DirectionCommand
23
+ pattern 'south'
24
+
25
+ def direction
26
+ Direction::South
27
+ end
28
+ end
29
+
30
+ class East < DirectionCommand
31
+ pattern 'east'
32
+
33
+ def direction
34
+ Direction::East
35
+ end
36
+ end
37
+
38
+ class West < DirectionCommand
39
+ pattern 'west'
40
+
41
+ def direction
42
+ Direction::West
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+
@@ -0,0 +1,16 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Element < Base
4
+ pattern "el(ement)?"
5
+
6
+ def run(char, *name)
7
+ world = history.world.new_element char, name.join(' ')
8
+
9
+ outcome nil,
10
+ world,
11
+ Commands::Basics
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,18 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Forge < Base
4
+ pattern "forg(e)?"
5
+
6
+ def run(elem_1, elem_2, novel_elem)
7
+ world = history.world.forge avatar_name,
8
+ elem_1,
9
+ elem_2,
10
+ novel_elem
11
+ a = world.avatar avatar_name
12
+
13
+ outcome "inventory #{a.inventory}",
14
+ world
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Formulate < Base
4
+ pattern "form(ulate)?"
5
+
6
+ def run(elem_1, elem_2, novel_elem, *name)
7
+ world = history.world.formulate avatar_name,
8
+ elem_1,
9
+ elem_2,
10
+ novel_elem,
11
+ name.join(' ')
12
+ a = world.avatar avatar_name
13
+
14
+ outcome "inventory #{a.inventory}",
15
+ world,
16
+ Commands::Compounds
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Inventory < Base
4
+ pattern "inv(entory)?"
5
+
6
+ def run
7
+ outcome "inventory #{history.world.avatar(avatar_name).inventory}"
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,13 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Location < Base
4
+ pattern "location"
5
+
6
+ def run
7
+ x, y = history.world.location avatar_name
8
+ outcome "location #{x} #{y}"
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,12 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Lock < Base
4
+ pattern "lock"
5
+
6
+ def run
7
+ outcome "locked", history.world.lock
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,14 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Look < Base
4
+ pattern "look"
5
+
6
+ def run
7
+ outcome [
8
+ "see #{World::LOOK_RANGE*2}",
9
+ history.world.look(avatar_name)
10
+ ].join("\n")
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Message < Base
4
+ pattern "message|msg"
5
+
6
+ def run(key, *words)
7
+ world = history.world.put_message avatar_name,
8
+ key,
9
+ words.join(' ')
10
+
11
+ outcome nil, world, Commands::Read
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Put < Base
4
+ pattern "put"
5
+
6
+ def run(resource)
7
+ world = history.world.put avatar_name, resource
8
+ a = world.avatar avatar_name
9
+
10
+ outcome "inventory #{a.inventory}",
11
+ world,
12
+ Commands::Look
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Read < Base
4
+ pattern "read"
5
+
6
+ def run
7
+ messages = history.world.messages_for avatar_name
8
+
9
+ lines = messages.flat_map do |name, messages|
10
+ ["#{name}:"] + messages + ['']
11
+ end
12
+
13
+ outcome((["messages #{lines.length}"] + lines + ['']).join("\n"))
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,17 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Take < Base
4
+ pattern "take"
5
+
6
+ def run
7
+ world = history.world.take(avatar_name)
8
+ a = world.avatar avatar_name
9
+
10
+ outcome "inventory #{a.inventory}",
11
+ world,
12
+ Commands::Look
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,18 @@
1
+ module Alchemist
2
+ module Commands
3
+ class Who < Base
4
+ pattern "who"
5
+
6
+ def run
7
+ a = history.world.avatar avatar_name
8
+ avatars = history.world.nearby_avatars a
9
+
10
+ locations = avatars.map do |avatar|
11
+ "#{avatar.name} #{avatar.x} #{avatar.y}\n"
12
+ end
13
+
14
+ outcome (["avatars #{locations.length}\n"] + locations).join('')
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,63 @@
1
+ module Alchemist
2
+ module Curses
3
+ class GeographyWindow
4
+ include FFI::NCurses
5
+
6
+ def initialize(line, col, avatar_color_num = nil)
7
+ @win = newwin 20, 43, line, col
8
+ @avatar_color_num = avatar_color_num
9
+ @avatars = {}
10
+ @loc_x, @loc_y = nil
11
+ @data = ''
12
+ end
13
+
14
+ def draw
15
+ wclear @win
16
+ wmove @win, 0, 0
17
+ draw_colored_data @data.force_encoding Encoding::UTF_8
18
+ move_to_avatar_position
19
+ end
20
+
21
+ def draw_colored_data(data)
22
+ data.each_line.with_index do |line, y|
23
+ line.each_char.with_index do |c, x|
24
+ if @avatar_color_num && avatar_at?(x, y)
25
+ wattr_set @win, A_NORMAL, @avatar_color_num, nil
26
+ else
27
+ wattr_set @win, A_NORMAL, 0, nil
28
+ end
29
+
30
+ wprintw @win, c.pad_to_unicode_monospace
31
+ end
32
+ end
33
+ end
34
+
35
+ def avatar_at?(x,y)
36
+ @avatars.values.include? [x + (@loc_x - 10),
37
+ y + (@loc_y - 10)]
38
+ end
39
+
40
+ def update(location, data)
41
+ @loc_x, @loc_y = location
42
+ @data = data
43
+ draw
44
+ end
45
+
46
+ def update_avatar(name, x, y)
47
+ @avatars[name] = [x,y]
48
+ draw
49
+ end
50
+
51
+ def update_avatars(avatars)
52
+ @avatars = avatars.dup
53
+ draw
54
+ end
55
+
56
+ def move_to_avatar_position
57
+ wmove @win, 10, 20
58
+ wrefresh @win
59
+ end
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,89 @@
1
+ module Alchemist
2
+ module Curses
3
+ class GlyphWindow
4
+ include FFI::NCurses
5
+
6
+ ROWS = 21
7
+ COLS = 48
8
+
9
+ def initialize(line,col)
10
+ @width = (COLS + 2)*2
11
+ @win = newwin ROWS, @width, line, col
12
+ @starting_char = 0
13
+ @cursor_offset = 0
14
+ end
15
+
16
+ def draw
17
+ wmove @win, 0, 0
18
+ wclear @win
19
+ wprintw @win, rows.pad_to_unicode_monospace
20
+ reset_cursor
21
+ end
22
+
23
+ def reset_cursor
24
+ y,x = @cursor_offset.divmod COLS
25
+ wmove @win, y, x*2
26
+ wrefresh @win
27
+ end
28
+
29
+ def characters
30
+ Glyphs.strings[range_start..range_end] || []
31
+ end
32
+
33
+ def rows
34
+ characters
35
+ .each_slice(COLS)
36
+ .map { |slice| slice.join('') }
37
+ .join("\n")
38
+ .force_encoding(Encoding::UTF_8)
39
+ end
40
+
41
+ def range_start
42
+ @starting_char
43
+ end
44
+
45
+ def range_end
46
+ @starting_char + ROWS*COLS
47
+ end
48
+
49
+ def have_user_select
50
+ draw
51
+ wmove @win, 0, 0
52
+ wrefresh @win
53
+
54
+ while (c = getch) != KEY_RETURN
55
+ y,x = getyx @win
56
+
57
+ case c
58
+ when KEY_ESCAPE
59
+ return nil
60
+ when KEY_LEFT
61
+ @cursor_offset = [@cursor_offset - 1, 0].max
62
+ reset_cursor
63
+ when KEY_RIGHT
64
+ @cursor_offset = [@cursor_offset + 1, (ROWS*COLS)].min
65
+ reset_cursor
66
+ when KEY_UP
67
+ @cursor_offset = [@cursor_offset - COLS, 0].max
68
+ reset_cursor
69
+ when KEY_DOWN
70
+ @cursor_offset = [@cursor_offset + COLS, (ROWS*COLS)].min
71
+ reset_cursor
72
+ when '0'.ord
73
+ @starting_char += ROWS*COLS
74
+ draw
75
+ when '9'.ord
76
+ @starting_char = [@starting_char-ROWS*COLS,0].max
77
+ draw
78
+ end
79
+ end
80
+
81
+ characters[@cursor_offset]
82
+ ensure
83
+ wclear @win
84
+ wrefresh @win
85
+ end
86
+ end
87
+ end
88
+ end
89
+