alchemist-server 0.0.1

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 (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
+