alchemist-server 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|