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.
- data/.gitignore +5 -0
- data/Gemfile +5 -0
- data/README.md +118 -0
- data/Rakefile +1 -0
- data/alchemist-server.gemspec +29 -0
- data/bin/alchemist-repl +37 -0
- data/bin/alchemist-server +10 -0
- data/lib/alchemist-server.rb +151 -0
- data/lib/alchemist-server/avatar.rb +82 -0
- data/lib/alchemist-server/commands/appear.rb +13 -0
- data/lib/alchemist-server/commands/base.rb +31 -0
- data/lib/alchemist-server/commands/basics.rb +12 -0
- data/lib/alchemist-server/commands/compounds.rb +13 -0
- data/lib/alchemist-server/commands/create.rb +15 -0
- data/lib/alchemist-server/commands/describe.rb +18 -0
- data/lib/alchemist-server/commands/directions.rb +48 -0
- data/lib/alchemist-server/commands/element.rb +16 -0
- data/lib/alchemist-server/commands/forge.rb +18 -0
- data/lib/alchemist-server/commands/formulate.rb +20 -0
- data/lib/alchemist-server/commands/inventory.rb +12 -0
- data/lib/alchemist-server/commands/location.rb +13 -0
- data/lib/alchemist-server/commands/lock.rb +12 -0
- data/lib/alchemist-server/commands/look.rb +14 -0
- data/lib/alchemist-server/commands/message.rb +15 -0
- data/lib/alchemist-server/commands/put.rb +16 -0
- data/lib/alchemist-server/commands/read.rb +18 -0
- data/lib/alchemist-server/commands/take.rb +17 -0
- data/lib/alchemist-server/commands/who.rb +18 -0
- data/lib/alchemist-server/curses/geography_window.rb +63 -0
- data/lib/alchemist-server/curses/glyph_window.rb +89 -0
- data/lib/alchemist-server/curses/item_window.rb +59 -0
- data/lib/alchemist-server/curses/messages_window.rb +43 -0
- data/lib/alchemist-server/curses/prompt_window.rb +35 -0
- data/lib/alchemist-server/direction.rb +28 -0
- data/lib/alchemist-server/element.rb +14 -0
- data/lib/alchemist-server/event.rb +43 -0
- data/lib/alchemist-server/formula.rb +24 -0
- data/lib/alchemist-server/geography.rb +111 -0
- data/lib/alchemist-server/outcome.rb +12 -0
- data/lib/alchemist-server/record.rb +51 -0
- data/lib/alchemist-server/server_handler.rb +143 -0
- data/lib/alchemist-server/version.rb +8 -0
- data/lib/alchemist-server/world.rb +206 -0
- data/lib/alchemist-server/world_history.rb +45 -0
- data/script/alchemist-curses +307 -0
- metadata +148 -0
@@ -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,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,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,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
|
+
|